1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
use std::env;
use anyhow::Context;
use base64::URL_SAFE_NO_PAD;
use futures::channel::oneshot::channel;
use minor_skulk::{build, db::Db};
use password_hash::rand_core::OsRng;
use rand::RngCore;
use rocket::{
fairing::AdHoc,
tokio::{process::Command, spawn},
};
use time::{Duration, OffsetDateTime};
#[macro_use]
extern crate rocket;
extern crate anyhow;
async fn run_pytest(
markers: &'static str,
port_offset: u16,
invite_admin: Option<&'static str>,
) -> anyhow::Result<()> {
dotenv::dotenv().ok();
// at this point this is only a test runner to be used by the nix build.
env::set_var("ROCKET_LOG_LEVEL", "off");
// allow multiple runs of the server, with different port offsets.
let port = 8000 + port_offset;
let mail_port = 2525 + port_offset;
let (tx, rx) = channel();
let rocket = rocket::build();
let figment = rocket
.figment()
.clone()
.merge((rocket::Config::PORT, port))
.merge(("location", format!("http://localhost:{}", port)))
.merge(("mail_port", mail_port));
let figment = if let Some(admin) = invite_admin {
figment.merge(("invite_only", true)).merge(("invite_admin_address", admin))
} else {
figment.merge(("invite_only", false))
};
let rocket = build(rocket.configure(figment)).await?.attach(AdHoc::on_liftoff(
"notify startup",
move |rocket| {
Box::pin(async move {
// add an invite code as-if generated during startup and move it to an
// env var, emulating the user looking at the logs and copying the code.
// invite_only needs this to function.
if invite_admin.is_some() {
let db = rocket.state::<Db>().unwrap();
let tx = db.begin().await.unwrap();
let mut code = [0; 32];
OsRng.fill_bytes(&mut code);
let code = base64::encode_config(code, URL_SAFE_NO_PAD);
tx.add_invite_code(&code, OffsetDateTime::now_utc() + Duration::minutes(5))
.await
.unwrap();
tx.commit().await.unwrap();
env::set_var("INVITE_CODE", code);
}
tx.send(()).unwrap();
})
},
));
spawn(async move { rocket.launch().await });
let test = spawn(async move {
rx.await.expect("test trigger failed");
let mut child = Command::new("pytest")
.arg("-vvv")
.arg("-m")
.arg(markers)
.env("API_PORT", port.to_string())
.env("MAIL_PORT", mail_port.to_string())
.kill_on_drop(true)
.spawn()
.expect("failed to spawn");
child.wait().await
});
assert!(test.await.context("starting pytest")?.context("running pytest")?.success());
Ok(())
}
#[async_test]
async fn open() -> anyhow::Result<()> {
run_pytest("not invite", 100, None).await
}
#[async_test]
async fn invite_only() -> anyhow::Result<()> {
run_pytest("invite", 200, Some("test.account.invite@test-auth")).await
}
|