mod common;
use common::{EngineProcess, ScratchDb, client};
const INSTANCES: usize = 10;
const ROUNDS: usize = 5;
async fn one_round(round: usize) -> Vec<String> {
let Some(db) = ScratchDb::create().await else {
return Vec::new();
};
let dir = tempfile::tempdir().expect("tempdir");
let backend = format!("[backend]\ntype = \"postgres\"\nurl = \"{}\"", db.url());
let mut engines: Vec<EngineProcess> = (0..INSTANCES)
.map(|i| EngineProcess::spawn(dir.path(), &format!("{round}-{i}"), &backend))
.collect();
let client = client();
let mut failures = Vec::new();
for (i, engine) in engines.iter_mut().enumerate() {
if let Err(why) = engine.wait_ready(&client).await {
failures.push(format!("--- round {round}, engine {i} ---\n{why}"));
}
}
failures
}
#[tokio::test(flavor = "multi_thread")]
async fn concurrent_first_boot_all_start_pg() {
if ScratchDb::create().await.is_none() {
eprintln!("skipped: TEST_DATABASE_URL not set");
return;
}
let mut failures = Vec::new();
for round in 0..ROUNDS {
failures.extend(one_round(round).await);
}
assert!(
failures.is_empty(),
"{} engines failed to boot across {ROUNDS} rounds of {INSTANCES} simultaneous starts:\n{}",
failures.len(),
failures.join("\n")
);
}