//! The `user` subcommands, run as the real binary against a scratch database. use std::io::Write; use std::process::{Command, Output, Stdio}; fn run(db: &std::path::Path, args: &[&str], stdin: &str) -> Output { let mut child = Command::new(env!("CARGO_BIN_EXE_mtgc-server")) .args(args) .env("MTGC_DB", db) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() .unwrap(); child.stdin.take().unwrap().write_all(stdin.as_bytes()).unwrap(); child.wait_with_output().unwrap() } fn out(o: &Output) -> String { format!("{}{}", String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr)) } #[test] fn local_accounts_can_be_added_changed_listed_and_removed() { let dir = std::env::temp_dir().join(format!("mtgc-server-cli-{}", std::process::id())); let _ = std::fs::remove_dir_all(&dir); std::fs::create_dir_all(&dir).unwrap(); let db = dir.join("server.db"); let o = run(&db, &["user", "add", "Alice", "--display-name", "Alice A."], "a long password\n"); assert!(o.status.success(), "{}", out(&o)); let o = run(&db, &["user", "add", "alice"], "a long password\n"); assert!(!o.status.success(), "duplicate names must be refused"); let o = run(&db, &["user", "add", "bob"], "short\n"); assert!(!o.status.success(), "short passwords must be refused"); let o = run(&db, &["user", "passwd", "alice"], "another long password\n"); assert!(o.status.success(), "{}", out(&o)); let conn = mtgc_server::db::open(&db).unwrap(); let (_, hash) = mtgc_server::db::local_user(&conn, "alice").unwrap().unwrap(); assert!(hash.starts_with("$argon2id$")); drop(conn); let o = run(&db, &["user", "list"], ""); assert!(out(&o).contains("alice") && out(&o).contains("Alice A."), "{}", out(&o)); let o = run(&db, &["user", "remove", "alice"], ""); assert!(!o.status.success(), "removal must be confirmed"); let o = run(&db, &["user", "remove", "alice", "--yes"], ""); assert!(o.status.success(), "{}", out(&o)); let o = run(&db, &["user", "list"], ""); assert!(!out(&o).contains("alice"), "{}", out(&o)); std::fs::remove_dir_all(&dir).unwrap(); }