use std::time::Duration;
use freenet::test_utils::TestContext;
use freenet_macros::freenet_test;
use freenet_stdlib::client_api::{
ClientRequest, HostResponse, NodeDiagnosticsConfig, NodeQuery, QueryResponse, WebApi,
};
use tokio::time::timeout;
use tokio_tungstenite::connect_async;
const MAX_PLAUSIBLE_TEST_UPTIME_SECS: u64 = 300;
const GAP_SECS: u64 = 2;
async fn query_uptime_seconds(client: &mut WebApi) -> anyhow::Result<u64> {
let config = NodeDiagnosticsConfig {
include_node_info: true,
include_network_info: false,
include_subscriptions: false,
contract_keys: vec![],
include_system_metrics: false,
include_detailed_peer_info: false,
include_subscriber_peer_ids: false,
};
client
.send(ClientRequest::NodeQueries(NodeQuery::NodeDiagnostics {
config,
}))
.await?;
match timeout(Duration::from_secs(30), client.recv()).await {
Ok(Ok(HostResponse::QueryResponse(QueryResponse::NodeDiagnostics(response)))) => {
let node_info = response
.node_info
.ok_or_else(|| anyhow::anyhow!("diagnostics response missing node_info"))?;
Ok(node_info.uptime_seconds)
}
Ok(Ok(other)) => Err(anyhow::anyhow!(
"unexpected response to NodeDiagnostics query: {other:?}"
)),
Ok(Err(e)) => Err(anyhow::anyhow!("diagnostics query failed: {e}")),
Err(_) => Err(anyhow::anyhow!("diagnostics query timed out after 30s")),
}
}
#[freenet_test(nodes = ["gateway"], health_check_readiness = true, timeout_secs = 180)]
async fn test_node_diagnostics_reports_nonzero_increasing_uptime(
ctx: &mut TestContext,
) -> TestResult {
let gateway = ctx.gateway()?;
let (stream, _) = connect_async(&gateway.ws_url()).await?;
let mut client = WebApi::start(stream);
tokio::time::sleep(Duration::from_secs(GAP_SECS)).await;
let first = query_uptime_seconds(&mut client).await?;
assert!(
first > 0,
"uptime_seconds must be non-zero for a node that has been running for \
at least {GAP_SECS}s, got {first}. This is the #5223 regression: the \
field was hardcoded to 0, so reports R7JSRK / WEWYWY / R7W5NC all \
claimed zero uptime on nodes that had been up for hours."
);
assert!(
first < MAX_PLAUSIBLE_TEST_UPTIME_SECS,
"uptime_seconds of {first} is implausible for a node this test booted \
seconds ago — `started_at` is measuring from something other than \
node construction"
);
tokio::time::sleep(Duration::from_secs(GAP_SECS)).await;
let second = query_uptime_seconds(&mut client).await?;
assert!(
second > first,
"uptime_seconds must increase as the node keeps running: read {first} \
then {second} after a {GAP_SECS}s gap. An unchanged value means the \
field is a constant rather than a real elapsed-time measurement."
);
Ok(())
}