mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 15:08:24 +00:00
docs(tests): clarify readiness and timestamp rationale
This commit is contained in:
@@ -71,7 +71,10 @@ impl AuditClient {
|
|||||||
client.add_relay(relay_url).await?;
|
client.add_relay(relay_url).await?;
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
|
|
||||||
// Wait for connection to establish (with retries)
|
// Wait up to ~5s for nostr-sdk's background relay task to finish the
|
||||||
|
// WebSocket handshake. Full audit suites can briefly starve the task
|
||||||
|
// scheduler under load, so the older ~2s window produced flakes even
|
||||||
|
// when the relay was already accepting connections.
|
||||||
let mut attempts = 0;
|
let mut attempts = 0;
|
||||||
let mut connected = false;
|
let mut connected = false;
|
||||||
while attempts < 50 {
|
while attempts < 50 {
|
||||||
@@ -141,7 +144,10 @@ impl AuditClient {
|
|||||||
client.add_relay(relay_url).await?;
|
client.add_relay(relay_url).await?;
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
|
|
||||||
// Wait for connection to establish (with retries)
|
// Wait up to ~5s for nostr-sdk's background relay task to finish the
|
||||||
|
// WebSocket handshake. Full audit suites can briefly starve the task
|
||||||
|
// scheduler under load, so the older ~2s window produced flakes even
|
||||||
|
// when the relay was already accepting connections.
|
||||||
let mut attempts = 0;
|
let mut attempts = 0;
|
||||||
let mut connected = false;
|
let mut connected = false;
|
||||||
while attempts < 50 {
|
while attempts < 50 {
|
||||||
|
|||||||
+13
-9
@@ -24,7 +24,7 @@ use crate::common::port::{self, PortReservation};
|
|||||||
/// How long to wait for the spawned ngit-grasp subprocess to handle HTTP
|
/// How long to wait for the spawned ngit-grasp subprocess to handle HTTP
|
||||||
/// requests before giving up on a single attempt.
|
/// requests before giving up on a single attempt.
|
||||||
const READY_TIMEOUT: Duration = Duration::from_secs(5);
|
const READY_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
/// How often to retry the TCP probe while waiting for readiness.
|
/// How often to retry the HTTP probe while waiting for readiness.
|
||||||
const READY_POLL: Duration = Duration::from_millis(100);
|
const READY_POLL: Duration = Duration::from_millis(100);
|
||||||
/// Extra grace after the HTTP service responds before declaring the relay
|
/// Extra grace after the HTTP service responds before declaring the relay
|
||||||
/// ready.
|
/// ready.
|
||||||
@@ -537,17 +537,18 @@ impl TestRelay {
|
|||||||
&self.relay_data_path
|
&self.relay_data_path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Probe the listener with async TCP connects until it accepts,
|
/// Probe the relay with a real HTTP request until it responds 200,
|
||||||
/// while concurrently watching for the subprocess to exit early
|
/// while concurrently watching for the subprocess to exit early (the
|
||||||
/// (the signature of a lost port-bind race). Without the early-exit
|
/// signature of a lost port-bind race). A raw TCP connect can succeed
|
||||||
/// check we'd burn the full [`READY_TIMEOUT`] on a process that's
|
/// before Hyper has installed the service that accepts test clients,
|
||||||
/// already dead.
|
/// so HTTP readiness is the point where WebSocket clients may safely
|
||||||
|
/// begin racing the relay.
|
||||||
async fn wait_for_ready_or_early_exit(&mut self) -> ReadyOutcome {
|
async fn wait_for_ready_or_early_exit(&mut self) -> ReadyOutcome {
|
||||||
let deadline = Instant::now() + READY_TIMEOUT;
|
let deadline = Instant::now() + READY_TIMEOUT;
|
||||||
loop {
|
loop {
|
||||||
// Check whether the subprocess has already exited. If so the
|
// Check whether the subprocess has already exited. If so no
|
||||||
// TCP probe will never succeed — bail immediately so the
|
// readiness probe can succeed — bail immediately so the caller
|
||||||
// caller can retry with a fresh port.
|
// can retry with a fresh port.
|
||||||
match self.process.try_wait() {
|
match self.process.try_wait() {
|
||||||
Ok(Some(status)) => return ReadyOutcome::EarlyExit { status },
|
Ok(Some(status)) => return ReadyOutcome::EarlyExit { status },
|
||||||
Ok(None) => { /* still running */ }
|
Ok(None) => { /* still running */ }
|
||||||
@@ -579,6 +580,9 @@ impl TestRelay {
|
|||||||
async fn probe_http_ready(&self) -> std::io::Result<()> {
|
async fn probe_http_ready(&self) -> std::io::Result<()> {
|
||||||
let probe = async {
|
let probe = async {
|
||||||
let mut stream = tokio::net::TcpStream::connect(("127.0.0.1", self.port)).await?;
|
let mut stream = tokio::net::TcpStream::connect(("127.0.0.1", self.port)).await?;
|
||||||
|
// Use the relay's HTTP handler rather than a bare TCP connect:
|
||||||
|
// this verifies the accept loop and Hyper service are both live,
|
||||||
|
// which is what the immediately-following WebSocket tests need.
|
||||||
let request = format!(
|
let request = format!(
|
||||||
"GET / HTTP/1.1\r\nHost: 127.0.0.1:{}\r\nConnection: close\r\n\r\n",
|
"GET / HTTP/1.1\r\nHost: 127.0.0.1:{}\r\nConnection: close\r\n\r\n",
|
||||||
self.port
|
self.port
|
||||||
|
|||||||
@@ -74,10 +74,11 @@ async fn newer_30618_supersedes_older_and_preserves_old_in_history() {
|
|||||||
.expect("create audit client");
|
.expect("create audit client");
|
||||||
|
|
||||||
let (_announcement, repo_id) = publish_served_repo(&client, "history-30618").await;
|
let (_announcement, repo_id) = publish_served_repo(&client, "history-30618").await;
|
||||||
// The fixture published by `publish_served_repo` already saved a 30618
|
// `publish_served_repo` already saved a 30618 for this coordinate. Nostr
|
||||||
// for this coordinate. Use a deterministic later timestamp so this test's
|
// replaceable ordering is only second-granular, so a same-second "old"
|
||||||
// "old" version is always a valid replacement instead of racing the
|
// event can be rejected instead of superseding the fixture event. Start the
|
||||||
// fixture event within the same one-second Nostr timestamp bucket.
|
// test sequence in a deterministic future second to make both replacements
|
||||||
|
// strictly newer.
|
||||||
let base_ts = Timestamp::from_secs(Timestamp::now().as_secs() + 1);
|
let base_ts = Timestamp::from_secs(Timestamp::now().as_secs() + 1);
|
||||||
let old_state = build_state_version(&client, &repo_id, base_ts, "state-v1");
|
let old_state = build_state_version(&client, &repo_id, base_ts, "state-v1");
|
||||||
let new_state = build_state_version(
|
let new_state = build_state_version(
|
||||||
@@ -102,6 +103,9 @@ async fn newer_30618_supersedes_older_and_preserves_old_in_history() {
|
|||||||
let records = history
|
let records = history
|
||||||
.superseded_records_for_coordinate_before(
|
.superseded_records_for_coordinate_before(
|
||||||
&coordinate,
|
&coordinate,
|
||||||
|
// The deterministic future timestamps can be ahead of wall-clock
|
||||||
|
// `Timestamp::now()`, so query just after the newest test event
|
||||||
|
// rather than using "now" as the history cutoff.
|
||||||
Timestamp::from_secs(new_state.created_at.as_secs() + 1),
|
Timestamp::from_secs(new_state.created_at.as_secs() + 1),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -251,8 +255,9 @@ async fn serving_behavior_unchanged_latest_version_is_still_served() {
|
|||||||
.expect("create audit client");
|
.expect("create audit client");
|
||||||
|
|
||||||
let (_announcement, repo_id) = publish_served_repo(&client, "history-serving").await;
|
let (_announcement, repo_id) = publish_served_repo(&client, "history-serving").await;
|
||||||
// The helper publishes an initial 30618 for this coordinate. Ensure the
|
// `publish_served_repo` already saved a 30618 for this coordinate. Keep the
|
||||||
// state versions created here are strictly newer than that fixture event.
|
// explicit state sequence in future seconds so the relay's second-granular
|
||||||
|
// replaceable ordering cannot tie it with the fixture event.
|
||||||
let base_ts = Timestamp::from_secs(Timestamp::now().as_secs() + 1);
|
let base_ts = Timestamp::from_secs(Timestamp::now().as_secs() + 1);
|
||||||
let old_state = build_state_version(&client, &repo_id, base_ts, "state-old");
|
let old_state = build_state_version(&client, &repo_id, base_ts, "state-old");
|
||||||
let new_state = build_state_version(
|
let new_state = build_state_version(
|
||||||
|
|||||||
Reference in New Issue
Block a user