web: add unit tests++

axum-login-upgrade
Manos Pitsidianakis 2023-05-14 17:50:54 +03:00
parent c4f7ea1822
commit f23d7805ca
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
6 changed files with 145 additions and 34 deletions

1
Cargo.lock generated
View File

@ -2035,6 +2035,7 @@ dependencies = [
"rand",
"serde",
"serde_json",
"serde_urlencoded",
"tempfile",
"tokio",
"tower",

Binary file not shown.

View File

@ -340,7 +340,7 @@ mod tests {
list: 1,
address: "user@example.com".to_string(),
name: Some("Name".to_string()),
account: None,
account: Some(1),
enabled: true,
verified: false,
digest: false,

View File

@ -43,7 +43,8 @@ zstd = { version = "0.12", default-features = false }
[dev-dependencies]
hyper = { version = "0.14" }
mailpot-tests = { version = "^0.1", path = "../mailpot-tests" }
tempfile = "3.3"
serde_urlencoded = { version = "^0.7" }
tempfile = { version = "3.3" }
tower = { version = "^0.4" }
[build-dependencies]

View File

@ -179,7 +179,7 @@ pub async fn ssh_signin_post(
let (_prev_token, _) = if let Some(tok @ (_, timestamp)) =
session.get::<(String, i64)>(TOKEN_KEY)
{
if !(timestamp < now && now - timestamp < EXPIRY_IN_SECS) {
if !(timestamp <= now && now - timestamp < EXPIRY_IN_SECS) {
session.add_message(Message {
message: "The token has expired. Please retry.".into(),
level: Level::Error,

View File

@ -26,12 +26,8 @@ use minijinja::value::Value;
use rand::Rng;
use tokio::sync::RwLock;
fn create_app(conf: Configuration) -> Router {
let store = MemoryStore::new();
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret).with_secure(false);
let shared_state = Arc::new(AppState {
fn new_state(conf: Configuration) -> Arc<AppState> {
Arc::new(AppState {
conf,
root_url_prefix: Value::from_safe_string(
std::env::var("ROOT_URL_PREFIX").unwrap_or_default(),
@ -42,7 +38,13 @@ fn create_app(conf: Configuration) -> Router {
.into(),
site_subtitle: std::env::var("SITE_SUBTITLE").ok().map(Into::into),
user_store: Arc::new(RwLock::new(HashMap::default())),
});
})
}
fn create_app(shared_state: Arc<AppState>) -> Router {
let store = MemoryStore::new();
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret).with_secure(false);
let auth_layer = AuthLayer::new(shared_state.clone(), &secret);
@ -155,7 +157,7 @@ async fn main() {
return;
}
let conf = Configuration::from_file(config_path).unwrap();
let app = create_app(conf);
let app = create_app(new_state(conf));
let hostname = std::env::var("HOSTNAME").unwrap_or_else(|_| "0.0.0.0".to_string());
let port = std::env::var("PORT").unwrap_or_else(|_| "3000".to_string());
@ -215,7 +217,11 @@ mod tests {
use axum::{
body::Body,
http::{method::Method, Request, StatusCode},
http::{
header::{COOKIE, SET_COOKIE},
method::Method,
Request, StatusCode,
},
};
use mailpot::{Configuration, Connection, SendMail};
use mailpot_tests::init_stderr_logging;
@ -228,6 +234,26 @@ mod tests {
async fn test_routes() {
init_stderr_logging();
macro_rules! req {
(get $url:expr) => {{
Request::builder()
.uri($url)
.method(Method::GET)
.body(Body::empty())
.unwrap()
}};
(post $url:expr, $body:expr) => {{
Request::builder()
.uri($url)
.method(Method::POST)
.header("Content-Type", "application/x-www-form-urlencoded")
.body(Body::from(
serde_urlencoded::to_string($body).unwrap().into_bytes(),
))
.unwrap()
}};
}
let tmp_dir = TempDir::new().unwrap();
let db_path = tmp_dir.path().join("mpot.db");
@ -241,46 +267,129 @@ mod tests {
let db = Connection::open_db(config.clone()).unwrap();
let list = db.lists().unwrap().remove(0);
let state = new_state(config.clone());
// ------------------------------------------------------------
// list()
let cl = |url, config| async move {
let response = create_app(config)
.oneshot(
Request::builder()
.uri(&url)
.method(Method::GET)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
let cl = |url, state| async move {
let response = create_app(state).oneshot(req!(get & url)).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
hyper::body::to_bytes(response.into_body()).await.unwrap()
};
assert_eq!(
cl(format!("/list/{}/", list.id), config.clone()).await,
cl(format!("/list/{}/", list.pk), config.clone()).await
cl(format!("/list/{}/", list.id), state.clone()).await,
cl(format!("/list/{}/", list.pk), state.clone()).await
);
// ------------------------------------------------------------
// help(), ssh_signin(), root()
for path in ["/help/", "/login/", "/"] {
let response = create_app(config.clone())
.oneshot(
Request::builder()
.uri(path)
.method(Method::GET)
.body(Body::empty())
.unwrap(),
)
for path in ["/help/", "/"] {
let response = create_app(state.clone())
.oneshot(req!(get path))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
}
// ------------------------------------------------------------
// auth.rs...
let login_app = create_app(state.clone());
let session_cookie = {
let response = login_app
.clone()
.oneshot(req!(get "/login/"))
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
response.headers().get(SET_COOKIE).unwrap().clone()
};
let user = User {
pk: 1,
ssh_signature: String::new(),
role: Role::User,
public_key: None,
password: String::new(),
name: None,
address: String::new(),
enabled: true,
};
state.insert_user(1, user.clone()).await;
{
let mut request = req!(post "/login/",
AuthFormPayload {
address: "user@example.com".into(),
password: "hunter2".into()
}
);
request
.headers_mut()
.insert(COOKIE, session_cookie.to_owned());
let res = login_app.clone().oneshot(request).await.unwrap();
assert_eq!(
res.headers().get(http::header::LOCATION),
Some(
&SettingsPath
.to_uri()
.to_string()
.as_str()
.try_into()
.unwrap()
)
);
}
// ------------------------------------------------------------
// settings()
{
let mut request = req!(get "/settings/");
request
.headers_mut()
.insert(COOKIE, session_cookie.to_owned());
let response = login_app.clone().oneshot(request).await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
}
// ------------------------------------------------------------
// settings_post()
{
let mut request = req!(
post "/settings/",
crate::settings::ChangeSetting::Subscribe {
list_pk: IntPOST(1),
});
request
.headers_mut()
.insert(COOKIE, session_cookie.to_owned());
let res = login_app.clone().oneshot(request).await.unwrap();
assert_eq!(
res.headers().get(http::header::LOCATION),
Some(
&SettingsPath
.to_uri()
.to_string()
.as_str()
.try_into()
.unwrap()
)
);
}
// ------------------------------------------------------------
// user_list_subscription() TODO
// ------------------------------------------------------------
// user_list_subscription_post() TODO
}
}