This commit is contained in:
parent
b22588cd0d
commit
bd1e7ad407
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1221,6 +1221,7 @@ dependencies = [
|
||||||
name = "li7y"
|
name = "li7y"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"actix-http",
|
||||||
"actix-identity",
|
"actix-identity",
|
||||||
"actix-session",
|
"actix-session",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
|
|
@ -36,6 +36,7 @@ time = { version = "0.3.36", features = ["parsing", "serde"] }
|
||||||
uuid = { version = "1.9.0", features = ["serde", "v4"] }
|
uuid = { version = "1.9.0", features = ["serde", "v4"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
actix-http = "3.8.0"
|
||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
quickcheck_macros = "1.0.0"
|
quickcheck_macros = "1.0.0"
|
||||||
|
|
||||||
|
|
77
tests/auth.rs
Normal file
77
tests/auth.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use actix_http::header;
|
||||||
|
use actix_web::{cookie::Cookie, test};
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[sqlx::test]
|
||||||
|
async fn protected_route_requires_login(pool: PgPool) {
|
||||||
|
let srv = test::init_service(li7y::app(&common::config(), &pool)).await;
|
||||||
|
let req = test::TestRequest::get().uri("/items").to_request();
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert!(common::assert_redirect(res.map_into_boxed_body()).starts_with("/login"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[sqlx::test]
|
||||||
|
async fn login(pool: PgPool) {
|
||||||
|
let srv = test::init_service(li7y::app(&common::config(), &pool)).await;
|
||||||
|
|
||||||
|
// This is identical to common::session_cookie,
|
||||||
|
// but copied here explicitly to ensure the right functionality is tested.
|
||||||
|
let req = test::TestRequest::post()
|
||||||
|
.uri("/login")
|
||||||
|
.set_form(common::LoginForm::default())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
let session = Cookie::parse_encoded(
|
||||||
|
res.headers()
|
||||||
|
.clone()
|
||||||
|
.get(header::SET_COOKIE)
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(common::assert_redirect(res.map_into_boxed_body()).starts_with("/"));
|
||||||
|
|
||||||
|
let req = test::TestRequest::get()
|
||||||
|
.uri("/")
|
||||||
|
.cookie(session.clone())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert!(res.status().is_success());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ignore = "actix_session::CookieSessionStore does not support invalidating sessions"]
|
||||||
|
#[sqlx::test]
|
||||||
|
async fn logout(pool: PgPool) {
|
||||||
|
let srv = test::init_service(li7y::app(&common::config(), &pool)).await;
|
||||||
|
|
||||||
|
let session_cookie = common::session_cookie(&srv).await;
|
||||||
|
|
||||||
|
let req = test::TestRequest::post()
|
||||||
|
.uri("/logout")
|
||||||
|
.cookie(session_cookie.clone())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
let req = test::TestRequest::get()
|
||||||
|
.uri("/items")
|
||||||
|
.cookie(session_cookie.clone())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert!(common::assert_redirect(res.map_into_boxed_body()).starts_with("/login"));
|
||||||
|
}
|
69
tests/common/mod.rs
Normal file
69
tests/common/mod.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use actix_http::header;
|
||||||
|
use actix_web::{cookie::Cookie, dev::ServiceResponse, test};
|
||||||
|
use clap::Parser;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use li7y::Config;
|
||||||
|
|
||||||
|
pub const SUPERUSER_PASSWORD: &str = "correct horse battery staple";
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct LoginForm {
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LoginForm {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
password: SUPERUSER_PASSWORD.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config() -> Config {
|
||||||
|
env::set_var("SUPERUSER_PASSWORD", SUPERUSER_PASSWORD);
|
||||||
|
Config::parse_from(Vec::<std::ffi::OsString>::new().iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // for some reason rustc detects this as unused
|
||||||
|
pub fn assert_redirect(res: ServiceResponse) -> String {
|
||||||
|
assert!(res.status().is_redirection());
|
||||||
|
|
||||||
|
res.headers()
|
||||||
|
.get(header::LOCATION)
|
||||||
|
.expect("No location header set when expected")
|
||||||
|
.to_str()
|
||||||
|
.expect("Location header is not valid UTF-8")
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn session_cookie<'a>(
|
||||||
|
srv: &impl actix_web::dev::Service<
|
||||||
|
actix_http::Request,
|
||||||
|
Response = ServiceResponse<actix_web::body::EitherBody<actix_web::body::BoxBody>>,
|
||||||
|
Error = actix_web::Error,
|
||||||
|
>,
|
||||||
|
) -> Cookie<'a> {
|
||||||
|
let req = test::TestRequest::post()
|
||||||
|
.uri("/login")
|
||||||
|
.set_form(LoginForm::default())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
Cookie::parse_encoded(
|
||||||
|
test::call_service(&srv, req)
|
||||||
|
.await
|
||||||
|
.headers()
|
||||||
|
.get(header::SET_COOKIE)
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
}
|
71
tests/items.rs
Normal file
71
tests/items.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use actix_web::{body::MessageBody, test};
|
||||||
|
use sqlx::{query_as, PgPool};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[sqlx::test(fixtures("default"))]
|
||||||
|
async fn list(pool: PgPool) {
|
||||||
|
let srv = test::init_service(li7y::app(&common::config(), &pool)).await;
|
||||||
|
|
||||||
|
let session_cookie = common::session_cookie(&srv).await;
|
||||||
|
|
||||||
|
let req = test::TestRequest::get()
|
||||||
|
.uri("/items")
|
||||||
|
.cookie(session_cookie.clone())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert!(res.status().is_success());
|
||||||
|
|
||||||
|
let body = String::from_utf8(res.into_body().try_into_bytes().unwrap().to_vec()).unwrap();
|
||||||
|
|
||||||
|
let items: Vec<(Uuid, Option<String>)> = query_as("SELECT id, name FROM items")
|
||||||
|
.fetch_all(&pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for (id, name) in items {
|
||||||
|
assert!(body.contains(&format!(r#"href="/item/{id}""#)));
|
||||||
|
|
||||||
|
if let Some(name) = name {
|
||||||
|
assert!(body.contains(&format!(">{name}</a>")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[sqlx::test(fixtures("default"))]
|
||||||
|
async fn show(pool: PgPool) {
|
||||||
|
let srv = test::init_service(li7y::app(&common::config(), &pool)).await;
|
||||||
|
|
||||||
|
let session_cookie = common::session_cookie(&srv).await;
|
||||||
|
|
||||||
|
let req = test::TestRequest::get()
|
||||||
|
.uri("/item/663f45e6-b11a-4197-8ce4-c784ac9ee617")
|
||||||
|
.cookie(session_cookie.clone())
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert!(res.status().is_success());
|
||||||
|
|
||||||
|
let body = String::from_utf8(res.into_body().try_into_bytes().unwrap().to_vec()).unwrap();
|
||||||
|
|
||||||
|
assert!(body.contains("<h2>Item 2 <"));
|
||||||
|
assert!(body.contains("<th>UUID</th><td>663f45e6-b11a-4197-8ce4-c784ac9ee617</td>"));
|
||||||
|
assert!(body.contains("<th>Name</th><td>Item 2</td>"));
|
||||||
|
assert!(body
|
||||||
|
.contains(r#"href="/item-class/8a979306-b4c6-4ef8-900d-68f64abb2975">Subclass 1.1</a>"#));
|
||||||
|
assert!(body.contains(r#"href="/item/4fc0f5f4-4dca-4c24-844d-1f464cb32afa">Item 1</a>"#));
|
||||||
|
assert!(body.contains(r#"<li class="breadcrumb-item active">Item 2</li>"#));
|
||||||
|
assert!(body.contains(
|
||||||
|
r#"href="/item/049298e2-73db-42fb-957d-a741655648b1">Original Packaging of Item 2</a>"#
|
||||||
|
));
|
||||||
|
assert!(body.contains(">Lorem ipsum 3</td>"));
|
||||||
|
assert!(body.contains(">acquire</"));
|
||||||
|
}
|
Loading…
Reference in a new issue