mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 15:08:24 +00:00
The merged wait helper checked elapsed time only after awaiting its condition, so a stuck query could defeat the advertised deadline. Apply Tokio's timeout to the whole polling future while keeping the existing condition, polling interval and diagnostic message. Add a paused-time regression with a permanently pending condition and an outer guard. It fails if the helper lacks its own deadline, without requiring wall-clock sleeps or hanging the test runner. Production relay behavior and existing test assertions are unchanged. Validation: the targeted regression, formatting and all-target Clippy pass. Three complete workspace runs follow this commit. Assisted-by: Codex (GPT-6)
74 lines
2.4 KiB
Rust
74 lines
2.4 KiB
Rust
//! Accepted connections must not outlive the fixture that owns them.
|
|
mod common;
|
|
|
|
use std::time::Duration;
|
|
|
|
use common::{
|
|
censoring_proxy::CensoringProxy, flapping_relay::FlappingRelay,
|
|
neg_limiting_proxy::NegLimitingProxy, req_limiting_proxy::ReqLimitingProxy,
|
|
setup_drop_relay::SetupDropRelay, MockRelay,
|
|
};
|
|
use futures_util::StreamExt;
|
|
|
|
macro_rules! check_shutdown {
|
|
($fixture:expr) => {{
|
|
tokio::time::timeout(Duration::from_secs(10), async {
|
|
let fixture = $fixture;
|
|
let (mut connection, _) = tokio_tungstenite::connect_async(fixture.url())
|
|
.await
|
|
.expect("fixture must finish the WebSocket handshake");
|
|
fixture.stop().await;
|
|
while let Some(message) = connection.next().await {
|
|
if message.is_err() || message.unwrap().is_close() {
|
|
break;
|
|
}
|
|
}
|
|
})
|
|
.await
|
|
.expect("fixture stop must close accepted connections");
|
|
}};
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn censoring_proxy_closes_connections_on_stop() {
|
|
let backend = MockRelay::start().await;
|
|
check_shutdown!(CensoringProxy::start(backend.url()).await);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn req_limiting_proxy_closes_connections_on_stop() {
|
|
let backend = MockRelay::start().await;
|
|
check_shutdown!(ReqLimitingProxy::start(backend.url(), 2).await);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn neg_limiting_proxy_closes_connections_on_stop() {
|
|
let backend = MockRelay::start().await;
|
|
check_shutdown!(NegLimitingProxy::start(backend.url(), 2).await);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn flapping_relay_closes_connections_on_stop() {
|
|
check_shutdown!(FlappingRelay::start().await);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn setup_drop_relay_closes_connections_on_stop() {
|
|
check_shutdown!(SetupDropRelay::start().await);
|
|
}
|
|
|
|
#[tokio::test(start_paused = true)]
|
|
#[should_panic(expected = "stalled query did not hold within")]
|
|
async fn observable_wait_deadline_cancels_a_stalled_query() {
|
|
// The outer timer makes a missing inner deadline fail deterministically
|
|
// rather than hanging this regression. Paused time avoids a wall-clock wait.
|
|
tokio::time::timeout(
|
|
Duration::from_secs(20),
|
|
common::wait_for("stalled query", Duration::from_secs(10), || {
|
|
std::future::pending::<bool>()
|
|
}),
|
|
)
|
|
.await
|
|
.expect("wait helper failed to enforce its own deadline");
|
|
}
|