use std::fs;
use std::path::PathBuf;
use std::process::{Command, Output};
use std::sync::atomic::{AtomicU64, Ordering};
static NEXT_FIXTURE: AtomicU64 = AtomicU64::new(0);
struct Fixture {
root: PathBuf,
}
impl Fixture {
fn new() -> Self {
let root = std::env::temp_dir().join(format!(
"noxid-wo38-queue-sqlite-{}-{}",
std::process::id(),
NEXT_FIXTURE.fetch_add(1, Ordering::Relaxed)
));
fs::create_dir_all(root.join("server/queues")).expect("create queue fixture");
fs::create_dir_all(root.join("data")).expect("create SQLite directory");
fs::write(
root.join("Noxid.toml"),
"[app]\ntitle = \"Queue SQLite refusal\"\n",
)
.expect("write manifest");
fs::write(root.join("package.json"), "{\"type\":\"module\"}\n")
.expect("write package marker");
fs::write(
root.join("server/queues/Work.nox"),
"queue Work { payload {} retry: 0 backoff: 1s }\n",
)
.expect("write queue");
fs::write(
root.join("server/host.js"),
"export const queues = Object.freeze({ \"queue:Work\": async () => null });\n",
)
.expect("write queue host");
Self { root }
}
fn run(&self, operation: &str, output: &str, database_url: Option<&str>) -> Output {
let mut command = Command::new(env!("CARGO_BIN_EXE_noxid"));
command.args([operation, ".", "--out-dir", output]);
if operation == "adapt" {
command.args(["--adapter", "node"]);
}
command.current_dir(&self.root);
match database_url {
Some(url) => command.env("DATABASE_URL", url),
None => command.env_remove("DATABASE_URL"),
};
command.output().expect("run queue build operation")
}
}
impl Drop for Fixture {
fn drop(&mut self) {
let _ = fs::remove_dir_all(&self.root);
}
}
#[test]
fn deferred_queue_on_sqlite_build_and_adapt_refuse_before_publishing_output() {
let fixture = Fixture::new();
let primed = fixture.run("build", "cached", None);
assert!(
primed.status.success(),
"URL-less queue build failed: {}",
String::from_utf8_lossy(&primed.stderr)
);
for (operation, output, database_url) in [
("build", "sqlite-file", "sqlite://data/app.db"),
("adapt", "sqlite-memory", "sqlite::memory:"),
] {
let refused = fixture.run(operation, output, Some(database_url));
let transcript = format!(
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&refused.stdout),
String::from_utf8_lossy(&refused.stderr)
);
assert!(!refused.status.success(), "{transcript}");
assert!(
transcript.contains("error[QUEUE_REQUIRES_SHARED_DATABASE]"),
"{transcript}"
);
assert!(transcript.contains("shared PostgreSQL"), "{transcript}");
assert!(
!fixture.root.join(output).exists(),
"refused {operation} published {output}"
);
}
}