From f198638f998b99d36356113d00f6cdbff1ad3482 Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Tue, 13 Apr 2021 19:07:51 +0200 Subject: [PATCH] Add tests to the handler --- Cargo.toml | 2 +- src/domain/handler.rs | 164 ++++++++++++++++++++++++++++++++++++--- src/domain/sql_tables.rs | 32 ++++---- src/main.rs | 2 +- 4 files changed, 170 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index be9728a..ab08ab9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tracing-actix-web = "0.3.0-beta.2" tracing-log = "*" tracing-subscriber = "*" async-trait = "0.1.48" -sea-query = "0.9.2" +sea-query = { version = "0.9.2", features = [ "with-chrono" ] } [dependencies.figment] features = ["toml", "env"] diff --git a/src/domain/handler.rs b/src/domain/handler.rs index ab1bad3..4beb062 100644 --- a/src/domain/handler.rs +++ b/src/domain/handler.rs @@ -1,11 +1,12 @@ use super::sql_tables::*; +use crate::domain::sql_tables::Pool; use crate::infra::configuration::Configuration; use anyhow::{bail, Result}; use async_trait::async_trait; use futures_util::StreamExt; -use sea_query::{Expr, SqliteQueryBuilder, Query, SimpleExpr}; +use log::*; +use sea_query::{Expr, Order, Query, SimpleExpr, SqliteQueryBuilder}; use sqlx::Row; -use crate::domain::sql_tables::Pool; #[cfg_attr(test, derive(PartialEq, Eq, Debug))] pub struct BindRequest { @@ -100,7 +101,11 @@ impl BackendHandler for SqlBackendHandler { if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await { if passwords_match(&request.password, &row.get::("password")) { return Ok(()); + } else { + debug!(r#"Invalid password for "{}""#, request.name); } + } else { + debug!(r#"No user found for "{}""#, request.name); } bail!(r#"Authentication error for "{}""#, request.name) } @@ -116,6 +121,7 @@ impl BackendHandler for SqlBackendHandler { .column(Users::Avatar) .column(Users::CreationDate) .from(Users::Table) + .order_by(Users::UserId, Order::Asc) .to_owned(); if let Some(filter) = request.filters { if filter != RequestFilter::And(Vec::new()) @@ -153,24 +159,162 @@ mockall::mock! { #[cfg(test)] mod tests { use super::*; + use crate::domain::sql_tables::init_table; + + async fn get_in_memory_db() -> Pool { + PoolOptions::new().connect("sqlite::memory:").await.unwrap() + } + + async fn get_initialized_db() -> Pool { + let sql_pool = get_in_memory_db().await; + init_table(&sql_pool).await.unwrap(); + sql_pool + } + + async fn insert_user(sql_pool: &Pool, name: &str, pass: &str) { + /* + let query = Query::insert() + .into_table(Users::Table) + .columns(vec![ + Users::UserId, + Users::Email, + Users::DisplayName, + Users::FirstName, + Users::LastName, + Users::CreationDate, + Users::Password, + ]) + .values_panic(vec![ + "bob".into(), + "bob@bob".into(), + "Bob Böbberson".into(), + "Bob".into(), + "Böbberson".into(), + chrono::NaiveDateTime::from_timestamp(0, 0).into(), + "bob00".into(), + ]) + .to_string(SqliteQueryBuilder); + sqlx::query(&query).execute(&sql_pool).await.unwrap(); + */ + sqlx::query( + r#"INSERT INTO users + (user_id, email, display_name, first_name, last_name, creation_date, password) + VALUES (?, "em@ai.l", "Display Name", "Firstname", "Lastname", "1970-01-01 00:00:00", ?)"#, + ) + .bind(name.to_string()) + .bind(pass.to_string()) + .execute(sql_pool) + .await + .unwrap(); + } #[tokio::test] async fn test_bind_admin() { - let sql_pool = PoolOptions::new() - .connect("sqlite::memory:") - .await - .unwrap(); + let sql_pool = get_in_memory_db().await; let mut config = Configuration::default(); config.ldap_user_dn = "admin".to_string(); config.ldap_user_pass = "test".to_string(); let handler = SqlBackendHandler::new(config, sql_pool); - assert!(true); - assert!(handler + handler .bind(BindRequest { name: "admin".to_string(), - password: "test".to_string() + password: "test".to_string(), }) .await - .is_ok()); + .unwrap(); + } + + #[tokio::test] + async fn test_bind_user() { + let sql_pool = get_initialized_db().await; + insert_user(&sql_pool, "bob", "bob00").await; + let config = Configuration::default(); + let handler = SqlBackendHandler::new(config, sql_pool); + handler + .bind(BindRequest { + name: "bob".to_string(), + password: "bob00".to_string(), + }) + .await + .unwrap(); + handler + .bind(BindRequest { + name: "andrew".to_string(), + password: "bob00".to_string(), + }) + .await + .unwrap_err(); + handler + .bind(BindRequest { + name: "bob".to_string(), + password: "wrong_password".to_string(), + }) + .await + .unwrap_err(); + } + + #[tokio::test] + async fn test_list_users() { + let sql_pool = get_initialized_db().await; + insert_user(&sql_pool, "bob", "bob00").await; + insert_user(&sql_pool, "patrick", "pass").await; + insert_user(&sql_pool, "John", "Pa33w0rd!").await; + let config = Configuration::default(); + let handler = SqlBackendHandler::new(config, sql_pool); + { + let users = handler + .list_users(ListUsersRequest { filters: None }) + .await + .unwrap() + .into_iter() + .map(|u| u.user_id) + .collect::>(); + assert_eq!(users, vec!["John", "bob", "patrick"]); + } + { + let users = handler + .list_users(ListUsersRequest { + filters: Some(RequestFilter::Equality( + "user_id".to_string(), + "bob".to_string(), + )), + }) + .await + .unwrap() + .into_iter() + .map(|u| u.user_id) + .collect::>(); + assert_eq!(users, vec!["bob"]); + } + { + let users = handler + .list_users(ListUsersRequest { + filters: Some(RequestFilter::Or(vec![ + RequestFilter::Equality("user_id".to_string(), "bob".to_string()), + RequestFilter::Equality("user_id".to_string(), "John".to_string()), + ])), + }) + .await + .unwrap() + .into_iter() + .map(|u| u.user_id) + .collect::>(); + assert_eq!(users, vec!["John", "bob"]); + } + { + let users = handler + .list_users(ListUsersRequest { + filters: Some(RequestFilter::Not(Box::new(RequestFilter::Equality( + "user_id".to_string(), + "bob".to_string(), + )))), + }) + .await + .unwrap() + .into_iter() + .map(|u| u.user_id) + .collect::>(); + assert_eq!(users, vec!["John", "patrick"]); + } } } diff --git a/src/domain/sql_tables.rs b/src/domain/sql_tables.rs index 14e9040..500914c 100644 --- a/src/domain/sql_tables.rs +++ b/src/domain/sql_tables.rs @@ -1,3 +1,4 @@ +use chrono::NaiveDateTime; use sea_query::*; pub type Pool = sqlx::sqlite::SqlitePool; @@ -92,11 +93,7 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> { .not_null() .primary_key(), ) - .col( - ColumnDef::new(Memberships::GroupId) - .integer() - .not_null(), - ) + .col(ColumnDef::new(Memberships::GroupId).integer().not_null()) .foreign_key( ForeignKey::create() .name("MembershipUserForeignKey") @@ -128,28 +125,27 @@ mod tests { #[actix_rt::test] async fn test_init_table() { - let sql_pool = PoolOptions::new() - .connect("sqlite::memory:") - .await - .unwrap(); + let sql_pool = PoolOptions::new().connect("sqlite::memory:").await.unwrap(); init_table(&sql_pool).await.unwrap(); sqlx::query(r#"INSERT INTO users (user_id, email, display_name, first_name, last_name, creation_date, password) - VALUES ("bôb", "böb@bob.bob", "Bob Bobbersön", "Bob", "Bobberson", CURRENT_TIMESTAMP, "bob00")"#).execute(&sql_pool).await.unwrap(); - let row = sqlx::query(r#"SELECT display_name FROM users WHERE user_id = "bôb""#) - .fetch_one(&sql_pool) - .await - .unwrap(); + VALUES ("bôb", "böb@bob.bob", "Bob Bobbersön", "Bob", "Bobberson", "1970-01-01 00:00:00", "bob00")"#).execute(&sql_pool).await.unwrap(); + let row = + sqlx::query(r#"SELECT display_name, creation_date FROM users WHERE user_id = "bôb""#) + .fetch_one(&sql_pool) + .await + .unwrap(); assert_eq!(row.column(0).name(), "display_name"); assert_eq!(row.get::("display_name"), "Bob Bobbersön"); + assert_eq!( + row.get::("creation_date"), + NaiveDateTime::from_timestamp(0, 0) + ); } #[actix_rt::test] async fn test_already_init_table() { - let sql_pool = PoolOptions::new() - .connect("sqlite::memory:") - .await - .unwrap(); + let sql_pool = PoolOptions::new().connect("sqlite::memory:").await.unwrap(); init_table(&sql_pool).await.unwrap(); init_table(&sql_pool).await.unwrap(); } diff --git a/src/main.rs b/src/main.rs index 8d7a66d..52476c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,8 @@ +use crate::domain::sql_tables::PoolOptions; use crate::infra::configuration::Configuration; use anyhow::Result; use futures_util::TryFutureExt; use log::*; -use crate::domain::sql_tables::PoolOptions; mod domain; mod infra;