From f9cbf95e5b850a7407c34f936c0f858520682a5d Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Thu, 24 Oct 2024 19:49:54 -0400 Subject: Tests for retrieving invites --- src/channel/routes/channel/test/delete.rs | 10 ++--- src/clock.rs | 2 +- src/invite/app.rs | 6 +-- src/invite/mod.rs | 2 +- src/invite/routes/invite/mod.rs | 2 + src/invite/routes/invite/test/get.rs | 65 +++++++++++++++++++++++++++++++ src/invite/routes/invite/test/mod.rs | 1 + src/invite/routes/mod.rs | 2 + src/invite/routes/post.rs | 2 +- src/invite/routes/test.rs | 28 +++++++++++++ src/test/fixtures/invite.rs | 17 ++++++++ src/test/fixtures/mod.rs | 1 + 12 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 src/invite/routes/invite/test/get.rs create mode 100644 src/invite/routes/invite/test/mod.rs create mode 100644 src/invite/routes/test.rs create mode 100644 src/test/fixtures/invite.rs (limited to 'src') diff --git a/src/channel/routes/channel/test/delete.rs b/src/channel/routes/channel/test/delete.rs index e9af12f..e1210fd 100644 --- a/src/channel/routes/channel/test/delete.rs +++ b/src/channel/routes/channel/test/delete.rs @@ -9,7 +9,7 @@ use crate::{ }; #[tokio::test] -pub async fn delete_channel() { +pub async fn valid_channel() { // Set up the environment let app = fixtures::scratch_app().await; @@ -38,7 +38,7 @@ pub async fn delete_channel() { } #[tokio::test] -pub async fn delete_invalid_channel_id() { +pub async fn invalid_channel_id() { // Set up the environment let app = fixtures::scratch_app().await; @@ -62,7 +62,7 @@ pub async fn delete_invalid_channel_id() { } #[tokio::test] -pub async fn delete_deleted() { +pub async fn channel_deleted() { // Set up the environment let app = fixtures::scratch_app().await; @@ -91,7 +91,7 @@ pub async fn delete_deleted() { } #[tokio::test] -pub async fn delete_expired() { +pub async fn channel_expired() { // Set up the environment let app = fixtures::scratch_app().await; @@ -120,7 +120,7 @@ pub async fn delete_expired() { } #[tokio::test] -pub async fn delete_purged() { +pub async fn channel_purged() { // Set up the environment let app = fixtures::scratch_app().await; diff --git a/src/clock.rs b/src/clock.rs index 9ffef82..242bcdf 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -12,7 +12,7 @@ pub type DateTime = chrono::DateTime; // calculated once per request, even if the extractor is used in multiple // places. This requires the [middleware] function to be installed with // [axum::middleware::from_fn] around the current route. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct RequestedAt(pub DateTime); impl RequestedAt { diff --git a/src/invite/app.rs b/src/invite/app.rs index 64ba753..65e7721 100644 --- a/src/invite/app.rs +++ b/src/invite/app.rs @@ -20,11 +20,7 @@ impl<'a> Invites<'a> { Self { db } } - pub async fn create( - &self, - issuer: &Login, - issued_at: &DateTime, - ) -> Result { + pub async fn issue(&self, issuer: &Login, issued_at: &DateTime) -> Result { let mut tx = self.db.begin().await?; let invite = tx.invites().create(issuer, issued_at).await?; tx.commit().await?; diff --git a/src/invite/mod.rs b/src/invite/mod.rs index d59fb9c..53ca984 100644 --- a/src/invite/mod.rs +++ b/src/invite/mod.rs @@ -14,7 +14,7 @@ pub struct Invite { pub issued_at: DateTime, } -#[derive(serde::Serialize)] +#[derive(Debug, serde::Serialize)] pub struct Summary { pub id: Id, pub issuer: nfc::String, diff --git a/src/invite/routes/invite/mod.rs b/src/invite/routes/invite/mod.rs index 04593fd..c22029a 100644 --- a/src/invite/routes/invite/mod.rs +++ b/src/invite/routes/invite/mod.rs @@ -1,4 +1,6 @@ pub mod get; pub mod post; +#[cfg(test)] +pub mod test; type PathInfo = crate::invite::Id; diff --git a/src/invite/routes/invite/test/get.rs b/src/invite/routes/invite/test/get.rs new file mode 100644 index 0000000..c6780ed --- /dev/null +++ b/src/invite/routes/invite/test/get.rs @@ -0,0 +1,65 @@ +use axum::extract::{Json, Path, State}; + +use crate::{invite::routes::invite::get, 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 endpoint + + let Json(response) = get::handler(State(app), Path(invite.id)) + .await + .expect("get for an existing invite succeeds"); + + // Verify response + + assert_eq!(issuer.name.display(), &response.issuer); + assert_eq!(invite.issued_at, response.issued_at); +} + +#[tokio::test] +async fn nonexistent_invite() { + // Set up the environment + + let app = fixtures::scratch_app().await; + + // Call endpoint + + let invite = fixtures::invite::fictitious(); + let error = get::handler(State(app), Path(invite.clone())) + .await + .expect_err("get for a nonexistent invite fails"); + + // Verify response + + assert!(matches!(error, get::Error::NotFound(error_id) if invite == error_id)); +} + +#[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 endpoint + + let error = get::handler(State(app), Path(invite.id.clone())) + .await + .expect_err("get for an expired invite fails"); + + // Verify response + + assert!(matches!(error, get::Error::NotFound(error_id) if invite.id == error_id)); +} diff --git a/src/invite/routes/invite/test/mod.rs b/src/invite/routes/invite/test/mod.rs new file mode 100644 index 0000000..a608fbb --- /dev/null +++ b/src/invite/routes/invite/test/mod.rs @@ -0,0 +1 @@ +mod get; diff --git a/src/invite/routes/mod.rs b/src/invite/routes/mod.rs index dae20ba..2f7375c 100644 --- a/src/invite/routes/mod.rs +++ b/src/invite/routes/mod.rs @@ -7,6 +7,8 @@ use crate::app::App; mod invite; mod post; +#[cfg(test)] +mod test; pub fn router() -> Router { Router::new() diff --git a/src/invite/routes/post.rs b/src/invite/routes/post.rs index eb7d706..898081e 100644 --- a/src/invite/routes/post.rs +++ b/src/invite/routes/post.rs @@ -10,7 +10,7 @@ pub async fn handler( identity: Identity, _: Json, ) -> Result, Internal> { - let invite = app.invites().create(&identity.login, &issued_at).await?; + let invite = app.invites().issue(&identity.login, &issued_at).await?; Ok(Json(invite)) } diff --git a/src/invite/routes/test.rs b/src/invite/routes/test.rs new file mode 100644 index 0000000..4d99660 --- /dev/null +++ b/src/invite/routes/test.rs @@ -0,0 +1,28 @@ +use axum::extract::{Json, State}; + +use super::post; +use crate::test::fixtures; + +#[tokio::test] +async fn create_invite() { + // Set up the environment + + let app = fixtures::scratch_app().await; + let issuer = fixtures::identity::create(&app, &fixtures::now()).await; + let issued_at = fixtures::now(); + + // Call the endpoint + + let Json(invite) = post::handler( + State(app), + issued_at.clone(), + issuer.clone(), + Json(post::Request {}), + ) + .await + .expect("creating an invite always succeeds"); + + // Verify the response + assert_eq!(issuer.login.id, invite.issuer); + assert_eq!(&*issued_at, &invite.issued_at); +} diff --git a/src/test/fixtures/invite.rs b/src/test/fixtures/invite.rs new file mode 100644 index 0000000..654d1b4 --- /dev/null +++ b/src/test/fixtures/invite.rs @@ -0,0 +1,17 @@ +use crate::{ + app::App, + clock::DateTime, + invite::{self, Invite}, + login::Login, +}; + +pub async fn issue(app: &App, issuer: &Login, issued_at: &DateTime) -> Invite { + app.invites() + .issue(issuer, issued_at) + .await + .expect("issuing invites never fails") +} + +pub fn fictitious() -> invite::Id { + invite::Id::generate() +} diff --git a/src/test/fixtures/mod.rs b/src/test/fixtures/mod.rs index 9111811..2b7b6af 100644 --- a/src/test/fixtures/mod.rs +++ b/src/test/fixtures/mod.rs @@ -7,6 +7,7 @@ pub mod cookie; pub mod event; pub mod future; pub mod identity; +pub mod invite; pub mod login; pub mod message; -- cgit v1.2.3