refactor(tests): share one soulfind fixture across the e2e suites

The TUI suite had grown its own copy of the soulfind spawner the protocol
suite already carried, and its own copy of the CLI suite's in-process
client and settle helpers. All four suites now spawn, log in, settle and
skip through `tests/common`: the CLI suite's own server goes too, and
the fixture checks its child is still alive before calling the port
answered, so a lost port cannot pass another server off as ours.
This commit is contained in:
Michel de Graaf
2026-09-08 13:12:12 +02:00
parent 76f4854169
commit 3ef78c6de1
7 changed files with 189 additions and 332 deletions
+2 -72
View File
@@ -13,7 +13,7 @@
mod common;
use common::{CLI_ENV_VARS, free_port, soulfind_binary};
use common::{CLI_ENV_VARS, Soulfind, free_port};
use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;
use std::path::{Path, PathBuf};
@@ -215,17 +215,7 @@ macro_rules! daemon_or_skip {
match Daemon::start() {
Some(daemon) => daemon,
None => {
let required = std::env::var("SOULSEEK_E2E_REQUIRED")
.is_ok_and(|v| v != "0" && !v.is_empty());
assert!(
!required,
"SOULSEEK_E2E_REQUIRED is set but no daemon could be \
started (set SOULFIND_BIN)"
);
println!(
"daemon protocol e2e skipped: no soulfind server (set \
SOULFIND_BIN to run)"
);
common::no_server("daemon protocol e2e");
return;
}
}
@@ -431,66 +421,6 @@ fn discover_serves_a_contract_whose_parameters_match_what_is_accepted() {
// Fixtures
// ---------------------------------------------------------------------------
struct Soulfind {
child: Child,
db: PathBuf,
port: u16,
}
impl Soulfind {
fn start() -> Option<Self> {
let port = free_port()?;
let db = std::env::temp_dir().join(format!("soulfind-proto-{port}.db"));
let _ = std::fs::remove_file(&db);
let child = Self::spawn(port, &db)?;
Some(Self { child, db, port })
}
fn spawn(port: u16, db: &Path) -> Option<Child> {
let bin = soulfind_binary()?;
let mut child = Command::new(bin)
.args(["-d", db.to_str()?, "-p", &port.to_string()])
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.ok()?;
let deadline = Instant::now() + Duration::from_secs(10);
while Instant::now() < deadline {
if TcpStream::connect(("127.0.0.1", port)).is_ok() {
return Some(child);
}
std::thread::sleep(Duration::from_millis(100));
}
let _ = child.kill();
let _ = child.wait();
None
}
fn address(&self) -> String {
format!("127.0.0.1:{}", self.port)
}
fn stop(&mut self) {
let _ = self.child.kill();
let _ = self.child.wait();
}
fn restart(&mut self) -> Option<()> {
self.stop();
self.child = Self::spawn(self.port, &self.db)?;
Some(())
}
}
impl Drop for Soulfind {
fn drop(&mut self) {
self.stop();
let _ = std::fs::remove_file(&self.db);
}
}
fn wait_until(timeout: Duration, mut f: impl FnMut() -> bool) -> bool {
let deadline = Instant::now() + timeout;
while Instant::now() < deadline {