feat: actually send email
This commit is contained in:
parent
6dfc9a0f3e
commit
0427df8656
3 changed files with 51 additions and 12 deletions
|
|
@ -30,6 +30,7 @@ impl TryFrom<FormData> for NewSubscriber {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove request_id?
|
||||||
#[tracing::instrument(
|
#[tracing::instrument(
|
||||||
name = "Adding a new subscriber",
|
name = "Adding a new subscriber",
|
||||||
skip(form, db_pool, email_client),
|
skip(form, db_pool, email_client),
|
||||||
|
|
@ -52,14 +53,22 @@ pub async fn subscribe(
|
||||||
return (StatusCode::BAD_REQUEST, "Invalid subscription.").into_response();
|
return (StatusCode::BAD_REQUEST, "Invalid subscription.").into_response();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match insert_subscriber(&db_pool, &new_subscriber).await {
|
if insert_subscriber(&db_pool, &new_subscriber).await.is_err() {
|
||||||
Ok(_) => {
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong.").into_response();
|
||||||
return (StatusCode::OK,).into_response();
|
|
||||||
}
|
|
||||||
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(
|
#[tracing::instrument(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use learn_axum::telemetry::{get_subscriber, init_subscriber};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use sqlx::{Connection, Executor, PgConnection, PgPool};
|
use sqlx::{Connection, Executor, PgConnection, PgPool};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use wiremock::MockServer;
|
||||||
|
|
||||||
/// Ensure that the `tracing` stack is only initialised once using `once_cell`
|
/// Ensure that the `tracing` stack is only initialised once using `once_cell`
|
||||||
static TRACING: Lazy<()> = Lazy::new(|| {
|
static TRACING: Lazy<()> = Lazy::new(|| {
|
||||||
|
|
@ -25,6 +26,7 @@ static TRACING: Lazy<()> = Lazy::new(|| {
|
||||||
pub struct TestApp {
|
pub struct TestApp {
|
||||||
pub address: String,
|
pub address: String,
|
||||||
pub db_pool: PgPool,
|
pub db_pool: PgPool,
|
||||||
|
pub email_server: MockServer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestApp {
|
impl TestApp {
|
||||||
|
|
@ -51,9 +53,8 @@ pub async fn spawn_app() -> TestApp {
|
||||||
// All other invocations will instead skip execution.
|
// All other invocations will instead skip execution.
|
||||||
Lazy::force(&TRACING);
|
Lazy::force(&TRACING);
|
||||||
|
|
||||||
// TODO:
|
// Launch a mock server to stand in for Postmark's API
|
||||||
// // Launch a mock server to stand in for Postmark's API
|
let email_server = MockServer::start().await;
|
||||||
// let email_server = MockServer::start().await;
|
|
||||||
|
|
||||||
// Randomise configuration to ensure test isolation
|
// Randomise configuration to ensure test isolation
|
||||||
let configuration = {
|
let configuration = {
|
||||||
|
|
@ -62,6 +63,8 @@ pub async fn spawn_app() -> TestApp {
|
||||||
c.database.name = Uuid::new_v4().to_string();
|
c.database.name = Uuid::new_v4().to_string();
|
||||||
// Use a random OS port
|
// Use a random OS port
|
||||||
c.application.port = 0;
|
c.application.port = 0;
|
||||||
|
// Use the mock server as email API
|
||||||
|
c.email_client.base_url = email_server.uri();
|
||||||
c
|
c
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -81,7 +84,7 @@ pub async fn spawn_app() -> TestApp {
|
||||||
address,
|
address,
|
||||||
// port: application_port,
|
// port: application_port,
|
||||||
db_pool: connection_pool,
|
db_pool: connection_pool,
|
||||||
// email_server,
|
email_server,
|
||||||
// test_user: TestUser::generate(),
|
// test_user: TestUser::generate(),
|
||||||
// api_client: client,
|
// api_client: client,
|
||||||
// email_client: configuration.email_client.client(),
|
// email_client: configuration.email_client.client(),
|
||||||
|
|
|
||||||
|
|
@ -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]
|
#[tokio::test]
|
||||||
async fn subscribe_returns_a_422_when_data_is_missing() {
|
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
|
// Arrange
|
||||||
let app = spawn_app().await;
|
let app = spawn_app().await;
|
||||||
let body = "name=le%20guin&email=ursula_le_guin%40gmail.com";
|
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
|
// Act
|
||||||
let response = app.post_subscriptions(body.into()).await;
|
let response = app.post_subscriptions(body.into()).await;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue