test(uptime): assert on the wire value, not the rendered table
The test read uptime with split_whitespace().nth(4), which assumed the column held a single token. That held only because the test measures about a second of uptime; once the formatter emits two tokens above a minute, raising the sleep would have shifted every later column while the assertion kept passing. Call the list RPC directly and assert on ServerSummary::uptime_secs. The daemon produces that value and the test only reads it, so the assertion no longer depends on a layout the project wrote itself. Mutation-proved: replacing the handler's elapsed().as_secs() with 0 fails the test on uptime_secs: Some(0). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D9BWMXKKNpid7XM6oFbyYq
This commit is contained in:
@@ -5,6 +5,8 @@ use std::process::Stdio;
|
||||
use std::time::Duration;
|
||||
use tempfile::TempDir;
|
||||
use tokio::process::{Child, Command};
|
||||
use xy_ipc::Client;
|
||||
use xy_protocol::rpc::{ServerSummary, methods};
|
||||
|
||||
pub struct Harness {
|
||||
pub tmp: TempDir,
|
||||
@@ -62,6 +64,16 @@ impl Harness {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `list` RPC result straight off the wire, before any CLI rendering.
|
||||
pub async fn list_rpc(&self) -> Vec<ServerSummary> {
|
||||
let mut client = Client::connect(&self.socket).await.expect("connect daemon");
|
||||
|
||||
client
|
||||
.call_no_params(methods::LIST)
|
||||
.await
|
||||
.expect("list rpc")
|
||||
}
|
||||
|
||||
pub async fn run_cli(&self, xy_bin: &PathBuf, args: &[&str]) -> (i32, String, String) {
|
||||
let out = Command::new(xy_bin)
|
||||
.args(args)
|
||||
|
||||
+14
-17
@@ -1,5 +1,6 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
use xy_protocol::ServerState;
|
||||
|
||||
#[tokio::test]
|
||||
async fn uptime_grows_while_a_server_stays_running() {
|
||||
@@ -10,8 +11,11 @@ async fn uptime_grows_while_a_server_stays_running() {
|
||||
h.start_daemon(&xy).await;
|
||||
|
||||
for _ in 0..40 {
|
||||
let (_c, out, _e) = h.run_cli(&xy, &["list"]).await;
|
||||
if out.contains("alpha") && out.contains("running") {
|
||||
let rows = h.list_rpc().await;
|
||||
if rows
|
||||
.iter()
|
||||
.any(|r| r.name == "alpha" && r.state == ServerState::Running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
@@ -19,22 +23,15 @@ async fn uptime_grows_while_a_server_stays_running() {
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1_200)).await;
|
||||
|
||||
let (code, out, _e) = h.run_cli(&xy, &["list"]).await;
|
||||
let rows = h.list_rpc().await;
|
||||
|
||||
assert_eq!(code, 0);
|
||||
let alpha = rows
|
||||
.iter()
|
||||
.find(|r| r.name == "alpha")
|
||||
.unwrap_or_else(|| panic!("no alpha row in: {rows:?}"));
|
||||
|
||||
let row = out
|
||||
.lines()
|
||||
.find(|l| l.starts_with("alpha"))
|
||||
.unwrap_or_else(|| panic!("no alpha row in:\n{out}"));
|
||||
|
||||
let uptime = row
|
||||
.split_whitespace()
|
||||
.nth(4)
|
||||
.unwrap_or_else(|| panic!("no uptime column in row: {row:?}"));
|
||||
|
||||
assert_ne!(
|
||||
uptime, "0s",
|
||||
"a server running for over a second must not report 0s uptime; row: {row:?}"
|
||||
assert!(
|
||||
alpha.uptime_secs.is_some_and(|secs| secs >= 1),
|
||||
"a server running for over a second must report at least 1s of uptime; row: {alpha:?}"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user