Flash messages using axum-messages
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
use argon2::{
|
||||
Argon2, PasswordHasher,
|
||||
password_hash::{SaltString, rand_core::OsRng},
|
||||
};
|
||||
use linkify::LinkFinder;
|
||||
use once_cell::sync::Lazy;
|
||||
use sqlx::{Connection, Executor, PgConnection, PgPool};
|
||||
@@ -22,34 +26,49 @@ pub struct ConfirmationLinks {
|
||||
pub text: reqwest::Url,
|
||||
}
|
||||
|
||||
pub struct TestUser {
|
||||
pub user_id: Uuid,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl TestUser {
|
||||
pub fn generate() -> Self {
|
||||
Self {
|
||||
user_id: Uuid::new_v4(),
|
||||
username: Uuid::new_v4().to_string(),
|
||||
password: Uuid::new_v4().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn store(&self, connection_pool: &PgPool) {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let password_hash = Argon2::default()
|
||||
.hash_password(self.password.as_bytes(), &salt)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
sqlx::query!(
|
||||
"INSERT INTO users (user_id, username, password_hash) VALUES ($1, $2, $3)",
|
||||
self.user_id,
|
||||
self.username,
|
||||
password_hash
|
||||
)
|
||||
.execute(connection_pool)
|
||||
.await
|
||||
.expect("Failed to create test user");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestApp {
|
||||
pub address: String,
|
||||
pub connection_pool: PgPool,
|
||||
pub email_server: wiremock::MockServer,
|
||||
pub port: u16,
|
||||
pub test_user: TestUser,
|
||||
pub api_client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl TestApp {
|
||||
pub fn get_confirmation_links(&self, request: &wiremock::Request) -> ConfirmationLinks {
|
||||
let body: serde_json::Value = serde_json::from_slice(&request.body).unwrap();
|
||||
let get_link = |s: &str| {
|
||||
let links: Vec<_> = LinkFinder::new()
|
||||
.links(s)
|
||||
.filter(|l| *l.kind() == linkify::LinkKind::Url)
|
||||
.collect();
|
||||
assert_eq!(links.len(), 1);
|
||||
let raw_link = links[0].as_str();
|
||||
let mut confirmation_link = reqwest::Url::parse(raw_link).unwrap();
|
||||
assert_eq!(confirmation_link.host_str().unwrap(), "127.0.0.1");
|
||||
confirmation_link.set_port(Some(self.port)).unwrap();
|
||||
confirmation_link
|
||||
};
|
||||
|
||||
let html = get_link(body["html"].as_str().unwrap());
|
||||
let text = get_link(body["text"].as_str().unwrap());
|
||||
ConfirmationLinks { html, text }
|
||||
}
|
||||
|
||||
pub async fn spawn() -> Self {
|
||||
Lazy::force(&TRACING);
|
||||
|
||||
@@ -73,11 +92,20 @@ impl TestApp {
|
||||
.parse::<u16>()
|
||||
.unwrap();
|
||||
let address = format!("http://{}", application.local_addr());
|
||||
let test_user = TestUser::generate();
|
||||
test_user.store(&connection_pool).await;
|
||||
let api_client = reqwest::Client::builder()
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.cookie_store(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
let app = TestApp {
|
||||
address,
|
||||
connection_pool,
|
||||
email_server,
|
||||
port,
|
||||
test_user,
|
||||
api_client,
|
||||
};
|
||||
|
||||
tokio::spawn(application.run_until_stopped());
|
||||
@@ -85,8 +113,39 @@ impl TestApp {
|
||||
app
|
||||
}
|
||||
|
||||
pub fn get_confirmation_links(&self, request: &wiremock::Request) -> ConfirmationLinks {
|
||||
let body: serde_json::Value = serde_json::from_slice(&request.body).unwrap();
|
||||
let get_link = |s: &str| {
|
||||
let links: Vec<_> = LinkFinder::new()
|
||||
.links(s)
|
||||
.filter(|l| *l.kind() == linkify::LinkKind::Url)
|
||||
.collect();
|
||||
assert_eq!(links.len(), 1);
|
||||
let raw_link = links[0].as_str();
|
||||
let mut confirmation_link = reqwest::Url::parse(raw_link).unwrap();
|
||||
assert_eq!(confirmation_link.host_str().unwrap(), "127.0.0.1");
|
||||
confirmation_link.set_port(Some(self.port)).unwrap();
|
||||
confirmation_link
|
||||
};
|
||||
|
||||
let html = get_link(body["html"].as_str().unwrap());
|
||||
let text = get_link(body["text"].as_str().unwrap());
|
||||
ConfirmationLinks { html, text }
|
||||
}
|
||||
|
||||
pub async fn get_login_html(&self) -> String {
|
||||
self.api_client
|
||||
.get(format!("{}/login", &self.address))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request")
|
||||
.text()
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn post_subscriptions(&self, body: String) -> reqwest::Response {
|
||||
reqwest::Client::new()
|
||||
self.api_client
|
||||
.post(format!("{}/subscriptions", self.address))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.body(body)
|
||||
@@ -99,6 +158,19 @@ impl TestApp {
|
||||
reqwest::Client::new()
|
||||
.post(format!("{}/newsletters", self.address))
|
||||
.json(&body)
|
||||
.basic_auth(&self.test_user.username, Some(&self.test_user.password))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request")
|
||||
}
|
||||
|
||||
pub async fn post_login<Body>(&self, body: &Body) -> reqwest::Response
|
||||
where
|
||||
Body: serde::Serialize,
|
||||
{
|
||||
self.api_client
|
||||
.post(format!("{}/login", self.address))
|
||||
.form(body)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request")
|
||||
@@ -124,3 +196,8 @@ async fn configure_database(config: &DatabaseSettings) -> PgPool {
|
||||
|
||||
connection_pool
|
||||
}
|
||||
|
||||
pub fn assert_is_redirect_to(response: &reqwest::Response, location: &str) {
|
||||
assert_eq!(response.status().as_u16(), 303);
|
||||
assert_eq!(response.headers().get("Location").unwrap(), location);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user