web: add unit tests

axum-login-upgrade
Manos Pitsidianakis 2023-05-14 09:47:54 +03:00
parent 1af4579519
commit c4f7ea1822
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
6 changed files with 116 additions and 53 deletions

4
Cargo.lock generated
View File

@ -2019,14 +2019,17 @@ dependencies = [
"axum-sessions",
"build-info",
"build-info-build",
"cfg-if 1.0.0",
"chrono",
"convert_case",
"dyn-clone",
"eyre",
"http",
"hyper",
"indexmap",
"lazy_static",
"mailpot",
"mailpot-tests",
"minijinja",
"percent-encoding",
"rand",
@ -2034,6 +2037,7 @@ dependencies = [
"serde_json",
"tempfile",
"tokio",
"tower",
"tower-http 0.3.5",
"tower-service",
"zstd",

View File

@ -14,16 +14,13 @@ categories = ["email"]
name = "mpot-web"
path = "src/main.rs"
[features]
default = ["zstd"]
zstd = ["dep:zstd"]
[dependencies]
axum = { version = "^0.6" }
axum-extra = { version = "^0.7", features = ["typed-routing"] }
axum-login = { version = "^0.5" }
axum-sessions = { version = "^0.5" }
build-info = { version = "0.0.31" }
cfg-if = { version = "1" }
chrono = { version = "^0.4" }
convert_case = { version = "^0.4" }
dyn-clone = { version = "^1" }
@ -41,8 +38,14 @@ tempfile = { version = "^3.5" }
tokio = { version = "1", features = ["full"] }
tower-http = { version = "^0.3" }
tower-service = { version = "^0.3" }
zstd = { version = "0.12.3", optional = true, default-features = false }
zstd = { version = "0.12", default-features = false }
[dev-dependencies]
hyper = { version = "0.14" }
mailpot-tests = { version = "^0.1", path = "../mailpot-tests" }
tempfile = "3.3"
tower = { version = "^0.4" }
[build-dependencies]
build-info-build = { version = "0.0.31" }
zstd = { version = "0.12.3", optional = true, default-features = false }
zstd = { version = "0.12", default-features = false }

View File

@ -4,9 +4,7 @@
cargo run --bin mpot-web -- /path/to/conf.toml
```
By default on release builds templates are compressed with `zstd` and bundled in the binary.
You can disable this behavior by disabling the `zstd` feature: `cargo build --release --no-default-features`
Templates are compressed with `zstd` and bundled in the binary.
## Configuration

View File

@ -44,7 +44,6 @@ fn commit_sha() {
}
}
#[cfg(feature = "zstd")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Embed HTML templates as zstd compressed byte slices into binary.
// [tag:embed_templates]
@ -104,8 +103,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
commit_sha();
Ok(())
}
#[cfg(not(feature = "zstd"))]
fn main() {
commit_sha();
}

View File

@ -26,19 +26,7 @@ use minijinja::value::Value;
use rand::Rng;
use tokio::sync::RwLock;
#[tokio::main]
async fn main() {
let config_path = std::env::args()
.nth(1)
.expect("Expected configuration file path as first argument.");
if ["-v", "--version", "info"].contains(&config_path.as_str()) {
println!("{}", crate::get_git_sha());
println!("{CLI_INFO}");
return;
}
let conf = Configuration::from_file(config_path).unwrap();
fn create_app(conf: Configuration) -> Router {
let store = MemoryStore::new();
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret).with_secure(false);
@ -60,7 +48,7 @@ async fn main() {
let login_url =
Arc::new(format!("{}{}", shared_state.root_url_prefix, LoginPath.to_crumb()).into());
let app = Router::new()
Router::new()
.route("/", get(root))
.typed_get(list)
.typed_get(list_post)
@ -152,7 +140,22 @@ async fn main() {
)
.layer(auth_layer)
.layer(session_layer)
.with_state(shared_state);
.with_state(shared_state)
}
#[tokio::main]
async fn main() {
let config_path = std::env::args()
.nth(1)
.expect("Expected configuration file path as first argument.");
if ["-v", "--version", "info"].contains(&config_path.as_str()) {
println!("{}", crate::get_git_sha());
println!("{CLI_INFO}");
return;
}
let conf = Configuration::from_file(config_path).unwrap();
let app = create_app(conf);
let hostname = std::env::var("HOSTNAME").unwrap_or_else(|_| "0.0.0.0".to_string());
let port = std::env::var("PORT").unwrap_or_else(|_| "3000".to_string());
@ -206,3 +209,78 @@ async fn root(
};
Ok(Html(TEMPLATES.get_template("lists.html")?.render(context)?))
}
#[cfg(test)]
mod tests {
use axum::{
body::Body,
http::{method::Method, Request, StatusCode},
};
use mailpot::{Configuration, Connection, SendMail};
use mailpot_tests::init_stderr_logging;
use tempfile::TempDir;
use tower::ServiceExt;
use super::*;
#[tokio::test]
async fn test_routes() {
init_stderr_logging();
let tmp_dir = TempDir::new().unwrap();
let db_path = tmp_dir.path().join("mpot.db");
std::fs::copy("../mailpot-tests/for_testing.db", &db_path).unwrap();
let config = Configuration {
send_mail: SendMail::ShellCommand("/usr/bin/false".to_string()),
db_path,
data_path: tmp_dir.path().to_path_buf(),
administrators: vec![],
};
let db = Connection::open_db(config.clone()).unwrap();
let list = db.lists().unwrap().remove(0);
// ------------------------------------------------------------
// list()
let cl = |url, config| async move {
let response = create_app(config)
.oneshot(
Request::builder()
.uri(&url)
.method(Method::GET)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
hyper::body::to_bytes(response.into_body()).await.unwrap()
};
assert_eq!(
cl(format!("/list/{}/", list.id), config.clone()).await,
cl(format!("/list/{}/", list.pk), config.clone()).await
);
// ------------------------------------------------------------
// help(), ssh_signin(), root()
for path in ["/help/", "/login/", "/"] {
let response = create_app(config.clone())
.oneshot(
Request::builder()
.uri(path)
.method(Method::GET)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
}
}
}

View File

@ -21,8 +21,6 @@
use super::*;
#[cfg(feature = "zstd")]
#[cfg(not(debug_assertions))]
mod compressed;
lazy_static::lazy_static! {
@ -54,28 +52,16 @@ lazy_static::lazy_static! {
post_eml_path
);
add!(filter pluralize);
#[cfg(not(feature = "zstd"))]
#[cfg(debug_assertions)]
env.set_source(minijinja::Source::from_path("web/src/templates/"));
#[cfg(feature = "zstd")]
#[cfg(debug_assertions)]
env.set_source(minijinja::Source::from_path("web/src/templates/"));
#[cfg(not(feature = "zstd"))]
#[cfg(not(debug_assertions))]
env.set_source(minijinja::Source::from_path("web/src/templates/"));
#[cfg(feature = "zstd")]
#[cfg(not(debug_assertions))]
{
// Load compressed templates. They are constructed in build.rs. See
// [ref:embed_templates]
let mut source = minijinja::Source::new();
for (name, bytes) in compressed::COMPRESSED {
let mut de_bytes = vec![];
zstd::stream::copy_decode(*bytes,&mut de_bytes).unwrap();
source.add_template(*name, String::from_utf8(de_bytes).unwrap()).unwrap();
}
env.set_source(source);
// Load compressed templates. They are constructed in build.rs. See
// [ref:embed_templates]
let mut source = minijinja::Source::new();
for (name, bytes) in compressed::COMPRESSED {
let mut de_bytes = vec![];
zstd::stream::copy_decode(*bytes,&mut de_bytes).unwrap();
source.add_template(*name, String::from_utf8(de_bytes).unwrap()).unwrap();
}
env.set_source(source);
env.add_global("root_url_prefix", Value::from_safe_string( std::env::var("ROOT_URL_PREFIX").unwrap_or_default()));
env.add_global("public_url",Value::from_safe_string(std::env::var("PUBLIC_URL").unwrap_or_default()));
env.add_global("site_title", Value::from_safe_string(std::env::var("SITE_TITLE").unwrap_or_else(|_| "mailing list archive".to_string())));