not working smtp test
This commit is contained in:
@@ -42,33 +42,56 @@ workers:
|
|||||||
|
|
||||||
|
|
||||||
# Mailer Configuration.
|
# Mailer Configuration.
|
||||||
|
# Defaults keep the whole suite on the in-memory stub mailer. The real-SMTP
|
||||||
|
# smoke test (tests/mailer/smtp_send.rs) opts in by setting these env vars
|
||||||
|
# before boot; nothing else in the suite sends real mail.
|
||||||
mailer:
|
mailer:
|
||||||
stub: true
|
stub: {{ get_env(name="MAILER_STUB", default="true") }}
|
||||||
# SMTP mailer configuration.
|
# SMTP mailer configuration.
|
||||||
smtp:
|
smtp:
|
||||||
# Enable/Disable smtp mailer.
|
# Enable/Disable smtp mailer.
|
||||||
enable: true
|
enable: {{ get_env(name="SMTP_ENABLE", default="true") }}
|
||||||
# SMTP server host. e.x localhost, smtp.gmail.com
|
# SMTP server host. e.x localhost, smtp.gmail.com
|
||||||
host: localhost
|
host: "{{ get_env(name="SMTP_HOST", default="localhost") }}"
|
||||||
# SMTP server port
|
# SMTP server port
|
||||||
port: 1025
|
port: {{ get_env(name="SMTP_PORT", default="1025") }}
|
||||||
# Use secure connection (SSL/TLS).
|
# Use secure connection (SSL/TLS).
|
||||||
secure: false
|
secure: {{ get_env(name="SMTP_SECURE", default="false") }}
|
||||||
# auth:
|
auth:
|
||||||
# user:
|
user: "{{ get_env(name="SMTP_USER", default="") }}"
|
||||||
# password:
|
password: "{{ get_env(name="SMTP_PASSWORD", default="") }}"
|
||||||
|
|
||||||
# Initializers Configuration
|
# Initializers Configuration
|
||||||
# initializers:
|
# OAuth2StoreInitializer requires this block to boot (it builds the client store
|
||||||
# oauth2:
|
# in after_routes). Static, non-secret placeholders: tests never perform a real
|
||||||
# authorization_code: # Authorization code grant type
|
# OAuth2 handshake, they just need the store to construct successfully.
|
||||||
# - client_identifier: google # Identifier for the OAuth2 provider. Replace 'google' with your provider's name if different, must be unique within the oauth2 config.
|
initializers:
|
||||||
# ... other fields
|
oauth2:
|
||||||
|
secret_key: 0123456789012345678901234567890123456789012345678901234567890123
|
||||||
|
authorization_code:
|
||||||
|
- client_identifier: google
|
||||||
|
client_credentials:
|
||||||
|
client_id: test-client-id
|
||||||
|
client_secret: test-client-secret
|
||||||
|
url_config:
|
||||||
|
auth_url: https://accounts.google.com/o/oauth2/auth
|
||||||
|
token_url: https://www.googleapis.com/oauth2/v3/token
|
||||||
|
redirect_url: http://localhost:5150/api/oauth2/google/callback
|
||||||
|
profile_url: https://openidconnect.googleapis.com/v1/userinfo
|
||||||
|
scopes:
|
||||||
|
- https://www.googleapis.com/auth/userinfo.email
|
||||||
|
- https://www.googleapis.com/auth/userinfo.profile
|
||||||
|
cookie_config:
|
||||||
|
protected_url: http://localhost:5150/
|
||||||
|
timeout_seconds: 600
|
||||||
|
|
||||||
# Database Configuration
|
# Database Configuration
|
||||||
database:
|
database:
|
||||||
# Database connection URI
|
# Database connection URI. Pinned to the throwaway test DB and intentionally
|
||||||
uri: {{ get_env(name="DATABASE_URL", default="postgres://uni_loco_web_user:3@localhost:5432/kompress_eshop_test") }}
|
# NOT read from `DATABASE_URL`: the app loads `.env` on boot (app.rs
|
||||||
|
# `load_config`), and this config has `dangerously_recreate: true`, so honoring
|
||||||
|
# an env override here would let `cargo test` recreate the dev/prod database.
|
||||||
|
uri: "postgres://uni_loco_web_user:3@localhost:5432/kompress_eshop_test"
|
||||||
# When enabled, the sql query will be logged.
|
# When enabled, the sql query will be logged.
|
||||||
enable_logging: false
|
enable_logging: false
|
||||||
# Set the timeout duration when acquiring a connection.
|
# Set the timeout duration when acquiring a connection.
|
||||||
|
|||||||
1
tests/mailer/mod.rs
Normal file
1
tests/mailer/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mod smtp_send;
|
||||||
101
tests/mailer/smtp_send.rs
Normal file
101
tests/mailer/smtp_send.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
//! Real-SMTP smoke test.
|
||||||
|
//!
|
||||||
|
//! Sends an actual email through the live SMTP server using the real
|
||||||
|
//! `AuthMailer` pipeline (config -> Loco mailer -> templates -> SMTP). The test
|
||||||
|
//! PASSES when the SMTP server accepts the message (the send returns `Ok`);
|
||||||
|
//! confirm real delivery by checking the recipient's inbox.
|
||||||
|
//!
|
||||||
|
//! It is `#[ignore]`d so it never runs in CI or a normal `cargo test` (it opens
|
||||||
|
//! a real network connection, uses real credentials, and sends a real email).
|
||||||
|
//! Run it explicitly, inside `nix develop` so `SMTP_PASSWORD` is present:
|
||||||
|
//!
|
||||||
|
//! ```sh
|
||||||
|
//! nix develop -c cargo test --test mod -- --ignored mailer::smtp_send
|
||||||
|
//! # optional: choose the recipient (defaults to the address below)
|
||||||
|
//! MAILER_TEST_TO=you@example.com \
|
||||||
|
//! nix develop -c cargo test --test mod -- --ignored mailer::smtp_send
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use kompress_eshop::{
|
||||||
|
app::App,
|
||||||
|
mailers::auth::AuthMailer,
|
||||||
|
models::users::{Model, RegisterParams},
|
||||||
|
};
|
||||||
|
use loco_rs::testing::prelude::*;
|
||||||
|
use sea_orm::IntoActiveModel;
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
|
// Non-secret production SMTP settings (mirror `.env`). The password is
|
||||||
|
// intentionally NOT here: it is supplied at runtime via `SMTP_PASSWORD`
|
||||||
|
// (direnv -> `pass`), and never committed.
|
||||||
|
const SMTP_HOST: &str = "smtp.kompress.sk";
|
||||||
|
const SMTP_PORT: &str = "587";
|
||||||
|
const SMTP_USER: &str = "kompres";
|
||||||
|
const SMTP_SECURE: &str = "true";
|
||||||
|
|
||||||
|
// Where the test email is sent. Override with `MAILER_TEST_TO`.
|
||||||
|
const DEFAULT_RECIPIENT: &str = "filipriec@gmail.com";
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
#[ignore = "sends a real email via live SMTP; run explicitly with --ignored"]
|
||||||
|
async fn sends_real_email() {
|
||||||
|
// The actual secret must come from the environment (direnv -> `pass`).
|
||||||
|
// Fail loudly with guidance rather than silently sending nothing.
|
||||||
|
let password = std::env::var("SMTP_PASSWORD").unwrap_or_default();
|
||||||
|
assert!(
|
||||||
|
!password.is_empty(),
|
||||||
|
"SMTP_PASSWORD is not set. Run inside `nix develop` so direnv loads it from `pass`."
|
||||||
|
);
|
||||||
|
|
||||||
|
let recipient =
|
||||||
|
std::env::var("MAILER_TEST_TO").unwrap_or_else(|_| DEFAULT_RECIPIENT.to_string());
|
||||||
|
|
||||||
|
// Flip the booted context onto the real SMTP transport. `config/test.yaml`
|
||||||
|
// reads these via `get_env` at boot. We deliberately do NOT load `.env`
|
||||||
|
// here: it carries `DATABASE_URL`, and `test.yaml` has
|
||||||
|
// `dangerously_recreate: true`, so loading it would recreate the real DB.
|
||||||
|
// Leaving `DATABASE_URL` untouched keeps boot on the throwaway test DB.
|
||||||
|
//
|
||||||
|
// SAFETY: edition 2024 marks `set_var` as unsafe. This test is `#[serial]`,
|
||||||
|
// so no other test mutates the process environment concurrently.
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("MAILER_STUB", "false");
|
||||||
|
std::env::set_var("SMTP_ENABLE", "true");
|
||||||
|
std::env::set_var("SMTP_HOST", SMTP_HOST);
|
||||||
|
std::env::set_var("SMTP_PORT", SMTP_PORT);
|
||||||
|
std::env::set_var("SMTP_USER", SMTP_USER);
|
||||||
|
std::env::set_var("SMTP_SECURE", SMTP_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
let boot = boot_test::<App>()
|
||||||
|
.await
|
||||||
|
.expect("Failed to boot test application");
|
||||||
|
|
||||||
|
// A real user whose address is the recipient, so `send_welcome` targets it.
|
||||||
|
let user = Model::create_with_password(
|
||||||
|
&boot.app_context.db,
|
||||||
|
&RegisterParams {
|
||||||
|
email: recipient.clone(),
|
||||||
|
password: "smtp-smoke-test".to_string(),
|
||||||
|
name: "SMTP smoke test".to_string(),
|
||||||
|
account_type: Some("personal".to_string()),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("failed to create test user");
|
||||||
|
|
||||||
|
// Give the welcome email a realistic verification token/link.
|
||||||
|
user.into_active_model()
|
||||||
|
.set_email_verification_sent(&boot.app_context.db)
|
||||||
|
.await
|
||||||
|
.expect("failed to set email verification token");
|
||||||
|
let user = Model::find_by_email(&boot.app_context.db, &recipient)
|
||||||
|
.await
|
||||||
|
.expect("failed to reload test user");
|
||||||
|
|
||||||
|
// The assertion: the live SMTP server must accept the message.
|
||||||
|
AuthMailer::send_welcome(&boot.app_context, &user)
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|e| panic!("real SMTP send to {recipient} failed: {e:?}"));
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod mailer;
|
||||||
mod models;
|
mod models;
|
||||||
mod requests;
|
mod requests;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ async fn can_create_with_password() {
|
|||||||
email: "test@framework.com".to_string(),
|
email: "test@framework.com".to_string(),
|
||||||
password: "1234".to_string(),
|
password: "1234".to_string(),
|
||||||
name: "framework".to_string(),
|
name: "framework".to_string(),
|
||||||
|
account_type: Some("personal".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = Model::create_with_password(&boot.app_context.db, ¶ms).await;
|
let res = Model::create_with_password(&boot.app_context.db, ¶ms).await;
|
||||||
@@ -78,6 +79,7 @@ async fn handle_create_with_password_with_duplicate() {
|
|||||||
email: "user1@example.com".to_string(),
|
email: "user1@example.com".to_string(),
|
||||||
password: "1234".to_string(),
|
password: "1234".to_string(),
|
||||||
name: "framework".to_string(),
|
name: "framework".to_string(),
|
||||||
|
account_type: Some("personal".to_string()),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
Reference in New Issue
Block a user