From 920c5d00aaea047179dc231dc6adb5338c2f2bdb Mon Sep 17 00:00:00 2001 From: Manuel Gugger Date: Sat, 27 Aug 2022 14:41:08 +0200 Subject: [PATCH] add integration test for get req --- Cargo.toml | 8 +- example/src/main.rs | 4 +- src/lib.rs | 4 +- src/routes/helpers.rs | 4 +- tests/integration_test_get_resp_is_success.rs | 64 +++++++++++++++ tests/test_setup/comment.rs | 51 ++++++++++++ tests/test_setup/helper.rs | 47 +++++++++++ tests/test_setup/mod.rs | 63 +++++++++++++++ tests/test_setup/post.rs | 79 +++++++++++++++++++ 9 files changed, 317 insertions(+), 7 deletions(-) create mode 100644 tests/integration_test_get_resp_is_success.rs create mode 100644 tests/test_setup/comment.rs create mode 100644 tests/test_setup/helper.rs create mode 100644 tests/test_setup/mod.rs create mode 100644 tests/test_setup/post.rs diff --git a/Cargo.toml b/Cargo.toml index 7cfbee5..6c460d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,14 @@ chrono = "0.4.20" tera = "1.16.0" async-trait = "0.1.53" lazy_static = "1.4.0" +itertools = "0.10.3" serde = "1.0.136" serde_derive = "1.0.136" sea-orm = { version = "^0.9.1", features = [], default-features = false } +actix_admin_macros = { path = "actix_admin_macros" } -actix_admin_macros = { path = "actix_admin_macros" } \ No newline at end of file +[dev-dependencies] +trybuild = "1.0" +sea-orm = { version = "^0.9.1", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros" ], default-features = true } +actix_admin_macros = { path = "actix_admin_macros" } +async-trait = "0.1.53" \ No newline at end of file diff --git a/example/src/main.rs b/example/src/main.rs index fddd84c..fe6e0aa 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -61,8 +61,8 @@ fn create_actix_admin_builder() -> ActixAdminBuilder { let user_info = session.get::("user_info").unwrap(); user_info.is_some() }), - login_link: "/azure-auth/login".to_string(), - logout_link: "/azure-auth/logout".to_string() + login_link: Some("/azure-auth/login".to_string()), + logout_link: Some("/azure-auth/logout".to_string() }; let mut admin_builder = ActixAdminBuilder::new(configuration); diff --git a/src/lib.rs b/src/lib.rs index 13e3b0a..f766471 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,8 +100,8 @@ pub trait ActixAdminSelectListTrait { pub struct ActixAdminConfiguration { pub enable_auth: bool, pub user_is_logged_in: Option fn(&'a Session) -> bool>, - pub login_link: String, - pub logout_link: String + pub login_link: Option, + pub logout_link: Option } #[derive(Clone)] diff --git a/src/routes/helpers.rs b/src/routes/helpers.rs index adcc80c..1467d95 100644 --- a/src/routes/helpers.rs +++ b/src/routes/helpers.rs @@ -12,8 +12,8 @@ pub fn add_auth_context(session: &Session, actix_admin: &ActixAdmin, ctx: &mut C if *enable_auth { let func = &actix_admin.configuration.user_is_logged_in.unwrap(); ctx.insert("user_is_logged_in", &func(session)); - ctx.insert("login_link", &actix_admin.configuration.login_link); - ctx.insert("logout_link", &actix_admin.configuration.logout_link); + ctx.insert("login_link", &actix_admin.configuration.login_link.as_ref().unwrap_or(&String::new())); + ctx.insert("logout_link", &actix_admin.configuration.logout_link.as_ref().unwrap_or(&String::new())); } } diff --git a/tests/integration_test_get_resp_is_success.rs b/tests/integration_test_get_resp_is_success.rs new file mode 100644 index 0000000..9817349 --- /dev/null +++ b/tests/integration_test_get_resp_is_success.rs @@ -0,0 +1,64 @@ +mod test_setup; +use test_setup::helper::{AppState, create_tables_and_get_connection, create_actix_admin_builder}; + +#[cfg(test)] +mod tests { + extern crate serde_derive; + + use actix_web::test; + use actix_web::{middleware, web, App}; + + use actix_admin::prelude::*; + + #[actix_web::test] + async fn test_admin_index_get() { + test_get_is_success("/admin/").await + } + + #[actix_web::test] + async fn test_post_list() { + test_get_is_success("/admin/post/list").await + } + + #[actix_web::test] + async fn test_comment_list() { + test_get_is_success("/admin/comment/list").await + } + + #[actix_web::test] + async fn test_post_create() { + test_get_is_success("/admin/post/create").await + } + + #[actix_web::test] + async fn test_comment_create() { + test_get_is_success("/admin/comment/create").await + } + + async fn test_get_is_success(url: &str) { + let conn = super::create_tables_and_get_connection().await; + + let actix_admin_builder = super::create_actix_admin_builder(); + let actix_admin = actix_admin_builder.get_actix_admin(); + + let app_state = super::AppState { + db: conn, + actix_admin: actix_admin, + }; + + let app = test::init_service( + App::new() + .app_data(web::Data::new(app_state.clone())) + .service(actix_admin_builder.get_scope::()) + .wrap(middleware::Logger::default()), + ) + .await; + + let req = test::TestRequest::get() + .uri(url) + .to_request(); + let resp = test::call_service(&app, req).await; + + assert!(resp.status().is_success()); + } +} diff --git a/tests/test_setup/comment.rs b/tests/test_setup/comment.rs new file mode 100644 index 0000000..a38535e --- /dev/null +++ b/tests/test_setup/comment.rs @@ -0,0 +1,51 @@ +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; +use actix_admin::prelude::*; +use super::Post; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdmin, DeriveActixAdminModel, DeriveActixAdminViewModel)] +#[sea_orm(table_name = "comment")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + #[actix_admin(primary_key)] + pub id: i32, + pub comment: String, + #[sea_orm(column_type = "Text")] + #[actix_admin(html_input_type = "email")] + pub user: String, + #[sea_orm(column_type = "DateTime")] + pub insert_date: DateTime, + pub is_visible: bool, + #[actix_admin(select_list="Post")] + pub post_id: Option, + pub my_decimal: Decimal +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::post::Entity", + from = "Column::PostId", + to = "super::post::Column::Id" + )] + Post, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Post.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} + +impl ActixAdminModelValidationTrait for Entity { + fn validate(model: &ActiveModel) -> HashMap { + let mut errors = HashMap::new(); + if model.my_decimal.clone().unwrap() < Decimal::from(100 as i16) { + errors.insert("my_decimal".to_string(), "Must be larger than 100".to_string()); + } + errors + } +} \ No newline at end of file diff --git a/tests/test_setup/helper.rs b/tests/test_setup/helper.rs new file mode 100644 index 0000000..6f6441e --- /dev/null +++ b/tests/test_setup/helper.rs @@ -0,0 +1,47 @@ +use sea_orm::{ConnectOptions, DatabaseConnection}; +use actix_admin::prelude::*; + +use super::{Post, Comment, create_tables}; + +pub async fn create_tables_and_get_connection() -> DatabaseConnection { + let opt = ConnectOptions::new("sqlite::memory:".to_owned()); + + let conn = sea_orm::Database::connect(opt).await.unwrap(); + let _ = create_tables(&conn).await; + + conn +} + +#[derive(Clone)] +pub struct AppState { + pub db: DatabaseConnection, + pub actix_admin: ActixAdmin, +} + +impl ActixAdminAppDataTrait for AppState { + fn get_db(&self) -> &DatabaseConnection { + &self.db + } + + fn get_actix_admin(&self) -> &ActixAdmin { + &self.actix_admin + } +} + +pub fn create_actix_admin_builder() -> ActixAdminBuilder { + let post_view_model = ActixAdminViewModel::from(Post); + let comment_view_model = ActixAdminViewModel::from(Comment); + + let configuration = ActixAdminConfiguration { + enable_auth: false, + user_is_logged_in: None, + login_link: None, + logout_link: None, + }; + + let mut admin_builder = ActixAdminBuilder::new(configuration); + admin_builder.add_entity::(&post_view_model); + admin_builder.add_entity::(&comment_view_model); + + admin_builder +} diff --git a/tests/test_setup/mod.rs b/tests/test_setup/mod.rs new file mode 100644 index 0000000..c981952 --- /dev/null +++ b/tests/test_setup/mod.rs @@ -0,0 +1,63 @@ +// setup +use sea_orm::sea_query::{ForeignKeyCreateStatement, ColumnDef, TableCreateStatement}; +use sea_orm::{error::*, sea_query, ConnectionTrait, DbConn, ExecResult}; +pub mod comment; +pub mod post; +pub mod helper; +pub use comment::Entity as Comment; +pub use post::Entity as Post; + +// setup +async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result { + let builder = db.get_database_backend(); + db.execute(builder.build(stmt)).await +} + +pub async fn create_tables(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(post::Entity) + .if_not_exists() + .col( + ColumnDef::new(post::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(post::Column::Title).string().not_null()) + .col(ColumnDef::new(post::Column::Text).string().not_null()) + .col(ColumnDef::new(post::Column::TeaMandatory).string().not_null()) + .col(ColumnDef::new(post::Column::TeaOptional).string()) + .col(ColumnDef::new(post::Column::InsertDate).date()) + .to_owned(); + + let _result = create_table(db, &stmt).await; + + let stmt = sea_query::Table::create() + .table(comment::Entity) + .if_not_exists() + .col( + ColumnDef::new(post::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(comment::Column::Comment).string().not_null()) + .col(ColumnDef::new(comment::Column::User).string().not_null()) + .col(ColumnDef::new(comment::Column::InsertDate).date_time().not_null()) + .col(ColumnDef::new(comment::Column::IsVisible).boolean().not_null()) + .col(ColumnDef::new(comment::Column::MyDecimal).decimal().not_null()) + .col(ColumnDef::new(comment::Column::PostId).integer()) + .foreign_key( + ForeignKeyCreateStatement::new() + .name("fk-comment-post") + .from_tbl(Comment) + .from_col(comment::Column::PostId) + .to_tbl(Post) + .to_col(post::Column::Id), + ) + .to_owned(); + + create_table(db, &stmt).await +} diff --git a/tests/test_setup/post.rs b/tests/test_setup/post.rs new file mode 100644 index 0000000..98f911e --- /dev/null +++ b/tests/test_setup/post.rs @@ -0,0 +1,79 @@ +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; +use actix_admin::prelude::*; +use std::fmt; +use std::fmt::Display; +use std::str::FromStr; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdmin, DeriveActixAdminViewModel, DeriveActixAdminModel, DeriveActixAdminModelSelectList)] +#[sea_orm(table_name = "post")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + #[actix_admin(primary_key)] + pub id: i32, + #[actix_admin(searchable)] + pub title: String, + #[sea_orm(column_type = "Text")] + #[actix_admin(searchable, textarea)] + pub text: String, + #[actix_admin(select_list="Tea")] + pub tea_mandatory: Tea, + #[actix_admin(select_list="Tea")] + pub tea_optional: Option, + pub insert_date: Date, +} + +impl Display for Model { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match &*self { + _ => write!(formatter, "{} {}", &self.title, &self.insert_date), + } + } +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::comment::Entity")] + Comment, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Comment.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Deserialize, Serialize, DeriveActixAdminEnumSelectList)] +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] +pub enum Tea { + #[sea_orm(string_value = "EverydayTea")] + EverydayTea, + #[sea_orm(string_value = "BreakfastTea")] + BreakfastTea, +} + +impl FromStr for Tea { + type Err = (); + + fn from_str(input: &str) -> Result { + match input { + "EverydayTea" => Ok(Tea::EverydayTea), + "BreakfastTea" => Ok(Tea::BreakfastTea), + _ => Err(()), + } + } +} + +impl Display for Tea { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match &*self { + Tea::EverydayTea => write!(formatter, "{}", String::from("EverydayTea")), + Tea::BreakfastTea => write!(formatter, "{}", String::from("BreakfastTea")), + } + } +} + +impl ActixAdminModelValidationTrait for Entity {} \ No newline at end of file