use axum::extract::{Json, Path, State}; use crate::{invite::app::AcceptError, name::Name, test::fixtures}; #[tokio::test] async fn valid_invite() { // Set up the environment let app = fixtures::scratch_app().await; let issuer = fixtures::user::create(&app, &fixtures::now()).await; let invite = fixtures::invite::issue(&app, &issuer, &fixtures::now()).await; // Call the endpoint let (name, password) = fixtures::user::propose(); let identity = fixtures::cookie::not_logged_in(); let request = super::Request { name: name.clone(), password: password.clone(), }; let (identity, Json(response)) = super::handler( State(app.clone()), fixtures::now(), identity, Path(invite.id), Json(request), ) .await .expect("accepting a valid invite succeeds"); // Verify the response assert!(identity.secret().is_some()); assert_eq!(name, response.name); // Verify that the issued token is valid let secret = identity .secret() .expect("newly-issued identity has a token secret"); let (_, login) = app .tokens() .validate(&secret, &fixtures::now()) .await .expect("newly-issued identity cookie is valid"); assert_eq!(response, login); // Verify that the given credentials can log in let (login, _) = app .tokens() .login(&name, &password, &fixtures::now()) .await .expect("credentials given on signup are valid"); assert_eq!(response, login); } #[tokio::test] async fn nonexistent_invite() { // Set up the environment let app = fixtures::scratch_app().await; let invite = fixtures::invite::fictitious(); // Call the endpoint let (name, password) = fixtures::user::propose(); let identity = fixtures::cookie::not_logged_in(); let request = super::Request { name: name.clone(), password: password.clone(), }; let super::Error(error) = super::handler( State(app.clone()), fixtures::now(), identity, Path(invite.clone()), Json(request), ) .await .expect_err("accepting a nonexistent invite fails"); // Verify the response assert!(matches!(error, AcceptError::NotFound(error_id) if error_id == invite)); } #[tokio::test] async fn expired_invite() { // Set up the environment let app = fixtures::scratch_app().await; let issuer = fixtures::user::create(&app, &fixtures::ancient()).await; let invite = fixtures::invite::issue(&app, &issuer, &fixtures::ancient()).await; app.invites() .expire(&fixtures::now()) .await .expect("expiring invites never fails"); // Call the endpoint let (name, password) = fixtures::user::propose(); let identity = fixtures::cookie::not_logged_in(); let request = super::Request { name: name.clone(), password: password.clone(), }; let super::Error(error) = super::handler( State(app.clone()), fixtures::now(), identity, Path(invite.id.clone()), Json(request), ) .await .expect_err("accepting a nonexistent invite fails"); // Verify the response assert!(matches!(error, AcceptError::NotFound(error_id) if error_id == invite.id)); } #[tokio::test] async fn accepted_invite() { // Set up the environment let app = fixtures::scratch_app().await; let issuer = fixtures::user::create(&app, &fixtures::ancient()).await; let invite = fixtures::invite::issue(&app, &issuer, &fixtures::ancient()).await; let (name, password) = fixtures::user::propose(); app.invites() .accept(&invite.id, &name, &password, &fixtures::now()) .await .expect("accepting a valid invite succeeds"); // Call the endpoint let (name, password) = fixtures::user::propose(); let identity = fixtures::cookie::not_logged_in(); let request = super::Request { name: name.clone(), password: password.clone(), }; let super::Error(error) = super::handler( State(app.clone()), fixtures::now(), identity, Path(invite.id.clone()), Json(request), ) .await .expect_err("accepting a nonexistent invite fails"); // Verify the response assert!(matches!(error, AcceptError::NotFound(error_id) if error_id == invite.id)); } #[tokio::test] async fn conflicting_name() { // Set up the environment let app = fixtures::scratch_app().await; let issuer = fixtures::user::create(&app, &fixtures::ancient()).await; let invite = fixtures::invite::issue(&app, &issuer, &fixtures::ancient()).await; let existing_name = Name::from("rijksmuseum"); app.users() .create( &existing_name, &fixtures::user::propose_password(), &fixtures::now(), ) .await .expect("creating a user in an empty environment succeeds"); // Call the endpoint let conflicting_name = Name::from("r\u{0133}ksmuseum"); let password = fixtures::user::propose_password(); let identity = fixtures::cookie::not_logged_in(); let request = super::Request { name: conflicting_name.clone(), password: password.clone(), }; let super::Error(error) = super::handler( State(app.clone()), fixtures::now(), identity, Path(invite.id.clone()), Json(request), ) .await .expect_err("accepting a nonexistent invite fails"); // Verify the response assert!( matches!(error, AcceptError::DuplicateLogin(error_name) if error_name == conflicting_name) ); } #[tokio::test] async fn invalid_name() { // Set up the environment let app = fixtures::scratch_app().await; let issuer = fixtures::user::create(&app, &fixtures::now()).await; let invite = fixtures::invite::issue(&app, &issuer, &fixtures::now()).await; // Call the endpoint let name = fixtures::user::propose_invalid_name(); let password = fixtures::user::propose_password(); let identity = fixtures::cookie::not_logged_in(); let request = super::Request { name: name.clone(), password: password.clone(), }; let super::Error(error) = super::handler( State(app.clone()), fixtures::now(), identity, Path(invite.id), Json(request), ) .await .expect_err("using an invalid name should fail"); // Verify the response assert!(matches!(error, AcceptError::InvalidName(error_name) if name == error_name)); }