feat: actually send email

This commit is contained in:
Sandro Eiler 2024-03-04 21:49:08 +01:00
parent 6dfc9a0f3e
commit 0427df8656
3 changed files with 51 additions and 12 deletions

View file

@ -30,6 +30,7 @@ impl TryFrom<FormData> 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(

View file

@ -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(),

View file

@ -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;