Watch
0
0
Fork
You've already forked hyperhive
0

bound swarm webhook registration with the forge deadline

This commit is contained in:
atlas 2026-10-17 15:22:55 +02:00 • committed by mara
commit 592ac8a5f2

View file

@ -1563,8 +1563,23 @@ impl Client {
/// ///
/// Returns the first failure. A listing failure is not fatal — it falls /// Returns the first failure. A listing failure is not fatal — it falls
/// through to the create attempt, which is idempotent server-side by way /// through to the create attempt, which is idempotent server-side by way
/// of the already-exists fold. /// of the already-exists fold. A forge that does not answer within
/// [`FORGE_DEADLINE`] is a failure too.
pub async fn ensure_swarm_webhooks(&self, public_base: &str, secret: &str) -> Result<()> { pub async fn ensure_swarm_webhooks(&self, public_base: &str, secret: &str) -> Result<()> {
within_forge_deadline(
"register swarm webhooks",
self.ensure_all_swarm_hooks(public_base, secret),
)
.await
.unwrap_or_else(|| {
anyhow::bail!(
"the forge did not answer within {}s",
FORGE_DEADLINE.as_secs()
)
})
}
async fn ensure_all_swarm_hooks(&self, public_base: &str, secret: &str) -> Result<()> {
for kind in DeliveryKind::ALL { for kind in DeliveryKind::ALL {
let target_url = kind.target_url(public_base); let target_url = kind.target_url(public_base);
let (event, scope) = match kind { let (event, scope) = match kind {
@ -2078,6 +2093,28 @@ mod tests {
assert_eq!(within_forge_deadline("test", async { 7 }).await, Some(7)); assert_eq!(within_forge_deadline("test", async { 7 }).await, Some(7));
} }
/// A forge that accepts the connection and never answers fails the
/// registration at the deadline, so the caller's retry advances. The
/// paused clock jumps to the deadline once nothing else can run.
#[tokio::test(start_paused = true)]
async fn swarm_webhook_registration_fails_at_the_deadline_when_the_forge_never_answers() {
// Bound but never accepted: the handshake completes, no response comes.
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let url = url::Url::parse(&format!("http://{}/", listener.local_addr().unwrap())).unwrap();
let client = Client::for_test_forge(url);
let start = tokio::time::Instant::now();
// The outer bound turns a missing deadline into a failure, not a hang.
let err = tokio::time::timeout(
FORGE_DEADLINE * 2,
client.ensure_swarm_webhooks("https://swarm.example", "s3cret"),
)
.await
.expect("registration returns by itself")
.expect_err("no answer is a failure");
assert_eq!(start.elapsed(), FORGE_DEADLINE);
assert!(format!("{err:#}").contains("did not answer"), "{err:#}");
}
#[tokio::test] #[tokio::test]
async fn page_search_results_pages_past_a_full_first_page() { async fn page_search_results_pages_past_a_full_first_page() {
#[derive(Clone)] #[derive(Clone)]