use std::process::Command;
fn run(root: &std::path::Path, args: &[&str]) -> std::process::Output {
Command::new(env!("CARGO_BIN_EXE_solid-pod-rs-server"))
.env_remove("JSS_STORAGE_ROOT")
.arg("invite")
.arg("--root")
.arg(root)
.args(args)
.output()
.expect("run binary")
}
fn field(out: &str, key: &str) -> String {
out.lines()
.find_map(|l| l.strip_prefix(key))
.unwrap_or_else(|| panic!("no {key} in {out}"))
.trim()
.to_string()
}
#[test]
fn create_list_revoke_persist_between_processes() {
let dir = tempfile::tempdir().unwrap();
let empty = run(dir.path(), &["list"]);
assert!(empty.status.success());
assert!(String::from_utf8_lossy(&empty.stdout).contains("No invite codes found"));
let created = run(dir.path(), &["create", "-u", "3"]);
assert!(created.status.success(), "{created:?}");
let token = field(&String::from_utf8_lossy(&created.stdout), "token:");
let listed = run(dir.path(), &["list"]);
let text = String::from_utf8_lossy(&listed.stdout).to_string();
assert!(!text.contains(&token), "{text}");
assert!(text.contains("ID USES"), "{text}");
let raw = std::fs::read_to_string(dir.path().join(".server/invites.json")).unwrap();
assert!(!raw.contains(&token), "token must not be stored in clear");
assert!(text.contains("0/3"), "{text}");
let revoked = run(dir.path(), &["revoke", &token]);
assert!(revoked.status.success());
assert!(String::from_utf8_lossy(&revoked.stdout).contains("Revoked invite code"));
let again = run(dir.path(), &["revoke", &token]);
assert!(!again.status.success());
let after = run(dir.path(), &["list"]);
assert!(String::from_utf8_lossy(&after.stdout).contains("No invite codes found"));
}
#[tokio::test]
async fn revoke_accepts_a_token_beginning_with_a_hyphen() {
use solid_pod_rs_idp::{Invite, InviteStore};
use solid_pod_rs_server::cli::FileInviteStore;
let dir = tempfile::tempdir().unwrap();
FileInviteStore::new(dir.path())
.insert(Invite {
token: "-hyphen-led-token".into(),
max_uses: Some(1),
expires_at: None,
})
.await
.unwrap();
let revoked = run(dir.path(), &["revoke", "-hyphen-led-token"]);
assert!(revoked.status.success(), "{revoked:?}");
assert!(String::from_utf8_lossy(&revoked.stdout).contains("Revoked invite code"));
}