summaryrefslogtreecommitdiff
path: root/src/invite
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-10-24 20:17:55 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-10-24 20:17:55 -0400
commit6321980ac49525d6d56f1fec67f9008e253a9c39 (patch)
tree79581c5d1f546e5ad745c1e06e2356a17c43439f /src/invite
parentf9cbf95e5b850a7407c34f936c0f858520682a5d (diff)
Tests for accepting invites
Diffstat (limited to 'src/invite')
-rw-r--r--src/invite/routes/invite/post.rs3
-rw-r--r--src/invite/routes/invite/test/mod.rs1
-rw-r--r--src/invite/routes/invite/test/post.rs208
3 files changed, 211 insertions, 1 deletions
diff --git a/src/invite/routes/invite/post.rs b/src/invite/routes/invite/post.rs
index 3ca4e6b..0dd8dba 100644
--- a/src/invite/routes/invite/post.rs
+++ b/src/invite/routes/invite/post.rs
@@ -36,7 +36,8 @@ pub struct Request {
pub password: Password,
}
-pub struct Error(app::AcceptError);
+#[derive(Debug)]
+pub struct Error(pub app::AcceptError);
impl IntoResponse for Error {
fn into_response(self) -> Response {
diff --git a/src/invite/routes/invite/test/mod.rs b/src/invite/routes/invite/test/mod.rs
index a608fbb..d6c1f06 100644
--- a/src/invite/routes/invite/test/mod.rs
+++ b/src/invite/routes/invite/test/mod.rs
@@ -1 +1,2 @@
mod get;
+mod post;
diff --git a/src/invite/routes/invite/test/post.rs b/src/invite/routes/invite/test/post.rs
new file mode 100644
index 0000000..65ab61e
--- /dev/null
+++ b/src/invite/routes/invite/test/post.rs
@@ -0,0 +1,208 @@
+use axum::extract::{Json, Path, State};
+
+use crate::{
+ invite::{app::AcceptError, routes::invite::post},
+ name::Name,
+ test::fixtures,
+};
+
+#[tokio::test]
+async fn valid_invite() {
+ // Set up the environment
+
+ let app = fixtures::scratch_app().await;
+ let issuer = fixtures::login::create(&app, &fixtures::now()).await;
+ let invite = fixtures::invite::issue(&app, &issuer, &fixtures::now()).await;
+
+ // Call the endpoint
+
+ let (name, password) = fixtures::login::propose();
+ let identity = fixtures::cookie::not_logged_in();
+ let request = post::Request {
+ name: name.clone(),
+ password: password.clone(),
+ };
+ let (identity, Json(response)) = post::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::login::propose();
+ let identity = fixtures::cookie::not_logged_in();
+ let request = post::Request {
+ name: name.clone(),
+ password: password.clone(),
+ };
+ let post::Error(error) = post::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::login::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::login::propose();
+ let identity = fixtures::cookie::not_logged_in();
+ let request = post::Request {
+ name: name.clone(),
+ password: password.clone(),
+ };
+ let post::Error(error) = post::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::login::create(&app, &fixtures::ancient()).await;
+ let invite = fixtures::invite::issue(&app, &issuer, &fixtures::ancient()).await;
+
+ let (name, password) = fixtures::login::propose();
+ app.invites()
+ .accept(&invite.id, &name, &password, &fixtures::now())
+ .await
+ .expect("accepting a valid invite succeeds");
+
+ // Call the endpoint
+
+ let (name, password) = fixtures::login::propose();
+ let identity = fixtures::cookie::not_logged_in();
+ let request = post::Request {
+ name: name.clone(),
+ password: password.clone(),
+ };
+ let post::Error(error) = post::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::login::create(&app, &fixtures::ancient()).await;
+ let invite = fixtures::invite::issue(&app, &issuer, &fixtures::ancient()).await;
+
+ let existing_name = Name::from("rijksmuseum");
+ app.logins()
+ .create(
+ &existing_name,
+ &fixtures::login::propose_password(),
+ &fixtures::now(),
+ )
+ .await
+ .expect("creating a login in an empty environment succeeds");
+
+ // Call the endpoint
+
+ let conflicting_name = Name::from("r\u{0133}ksmuseum");
+ let password = fixtures::login::propose_password();
+
+ let identity = fixtures::cookie::not_logged_in();
+ let request = post::Request {
+ name: conflicting_name.clone(),
+ password: password.clone(),
+ };
+ let post::Error(error) = post::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)
+ );
+}