From 0427df8656044bac8d3cc6ab19d5d8cb1a2b03a5 Mon Sep 17 00:00:00 2001 From: Sandro Eiler Date: Mon, 4 Mar 2024 21:49:08 +0100 Subject: [PATCH] feat: actually send email --- src/routes/subscriptions.rs | 23 ++++++++++++++++------- tests/api/helpers.rs | 11 +++++++---- tests/api/subscriptions.rs | 29 ++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/routes/subscriptions.rs b/src/routes/subscriptions.rs index e59b786..6dd1fbb 100644 --- a/src/routes/subscriptions.rs +++ b/src/routes/subscriptions.rs @@ -30,6 +30,7 @@ impl TryFrom for NewSubscriber { } } +// TODO: remove request_id? #[tracing::instrument( name = "Adding a new subscriber", skip(form, db_pool, email_client), @@ -52,14 +53,22 @@ pub async fn subscribe( return (StatusCode::BAD_REQUEST, "Invalid subscription.").into_response(); } }; - match insert_subscriber(&db_pool, &new_subscriber).await { - Ok(_) => { - return (StatusCode::OK,).into_response(); - } - Err(_) => { - return (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong.").into_response(); - } + if insert_subscriber(&db_pool, &new_subscriber).await.is_err() { + return (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong.").into_response(); } + if email_client + .send_email( + new_subscriber.email, + "Welcome!", + "Welcome to our newsletter!", + "Welcome to our newsletter!", + ) + .await + .is_err() + { + return (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong.").into_response(); + } + return (StatusCode::OK,).into_response(); } #[tracing::instrument( diff --git a/tests/api/helpers.rs b/tests/api/helpers.rs index ccee1ce..9010e59 100644 --- a/tests/api/helpers.rs +++ b/tests/api/helpers.rs @@ -4,6 +4,7 @@ use learn_axum::telemetry::{get_subscriber, init_subscriber}; use once_cell::sync::Lazy; use sqlx::{Connection, Executor, PgConnection, PgPool}; use uuid::Uuid; +use wiremock::MockServer; /// Ensure that the `tracing` stack is only initialised once using `once_cell` static TRACING: Lazy<()> = Lazy::new(|| { @@ -25,6 +26,7 @@ static TRACING: Lazy<()> = Lazy::new(|| { pub struct TestApp { pub address: String, pub db_pool: PgPool, + pub email_server: MockServer, } impl TestApp { @@ -51,9 +53,8 @@ pub async fn spawn_app() -> TestApp { // All other invocations will instead skip execution. Lazy::force(&TRACING); - // TODO: - // // Launch a mock server to stand in for Postmark's API - // let email_server = MockServer::start().await; + // Launch a mock server to stand in for Postmark's API + let email_server = MockServer::start().await; // Randomise configuration to ensure test isolation let configuration = { @@ -62,6 +63,8 @@ pub async fn spawn_app() -> TestApp { c.database.name = Uuid::new_v4().to_string(); // Use a random OS port c.application.port = 0; + // Use the mock server as email API + c.email_client.base_url = email_server.uri(); c }; @@ -81,7 +84,7 @@ pub async fn spawn_app() -> TestApp { address, // port: application_port, db_pool: connection_pool, - // email_server, + email_server, // test_user: TestUser::generate(), // api_client: client, // email_client: configuration.email_client.client(), diff --git a/tests/api/subscriptions.rs b/tests/api/subscriptions.rs index 276fd09..bfa8587 100644 --- a/tests/api/subscriptions.rs +++ b/tests/api/subscriptions.rs @@ -1,4 +1,26 @@ -use crate::helpers::{spawn_app, TestApp}; +use crate::helpers::spawn_app; +use wiremock::matchers::{method, path}; +use wiremock::{Mock, ResponseTemplate}; + +#[tokio::test] +async fn subscribe_sends_a_confirmation_email_for_valid_data() { + // Arrange + let app = spawn_app().await; + let body = "name=le%20guin&email=ursula_le_guin%40gmail.com"; + + Mock::given(path("/email")) + .and(method("POST")) + .respond_with(ResponseTemplate::new(200)) + .expect(1) + .mount(&app.email_server) + .await; + + // Act + app.post_subscriptions(body.into()).await; + + // Assert + // Mock asserts on drop +} #[tokio::test] async fn subscribe_returns_a_422_when_data_is_missing() { @@ -29,6 +51,11 @@ async fn subscribe_returns_a_200_for_valid_form_data() { // Arrange let app = spawn_app().await; let body = "name=le%20guin&email=ursula_le_guin%40gmail.com"; + Mock::given(path("/email")) + .and(method("POST")) + .respond_with(ResponseTemplate::new(200)) + .mount(&app.email_server) + .await; // Act let response = app.post_subscriptions(body.into()).await;