// Subnet-probe rate-limit tests. The full Noise XX handshake side of the // transport requires a live WebSocket peer, so we exercise the cooldown // ledger directly — it is the only Phase 2 invariant we want to pin // regardless of network reachability. import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { _resetSubnetProbeCooldown, probeSubnetForPeer, subnetProbeOnCooldown, SUBNET_PROBE_COOLDOWN_MS, } from "./chirp-sync-transport"; const PEER_PUBKEY = "ab".repeat(32); describe("subnetProbeOnCooldown", () => { beforeEach(() => _resetSubnetProbeCooldown()); afterEach(() => _resetSubnetProbeCooldown()); it("returns false before any probe has happened", () => { expect(subnetProbeOnCooldown(PEER_PUBKEY)).toBe(false); }); it("returns true within the cooldown window after a probe", async () => { const now = 1_000_000; // Fire-and-forget; the probe itself fails fast because no peer exists. // We only care about the ledger side-effect of recording `now`. await probeSubnetForPeer( "10.0.0", 49142, new Uint8Array(32), new Uint8Array(32), PEER_PUBKEY, { batch: 254, timeoutMs: 1, now }, ); expect(subnetProbeOnCooldown(PEER_PUBKEY, now + 1)).toBe(true); expect(subnetProbeOnCooldown(PEER_PUBKEY, now + SUBNET_PROBE_COOLDOWN_MS - 1)).toBe(true); }); it("releases the cooldown after the window expires", async () => { const now = 1_000_000; await probeSubnetForPeer( "10.0.0", 49142, new Uint8Array(32), new Uint8Array(32), PEER_PUBKEY, { batch: 254, timeoutMs: 1, now }, ); expect(subnetProbeOnCooldown(PEER_PUBKEY, now + SUBNET_PROBE_COOLDOWN_MS)).toBe(false); }); it("returns null and skips the scan when on cooldown", async () => { const now = 1_000_000; await probeSubnetForPeer( "10.0.0", 49142, new Uint8Array(32), new Uint8Array(32), PEER_PUBKEY, { batch: 254, timeoutMs: 1, now }, ); // Second call within the window must short-circuit before any // WebSocket attempt is made. We can't easily observe "no WebSocket" // directly here, but null + cooldown=true is the contract. const result = await probeSubnetForPeer( "10.0.0", 49142, new Uint8Array(32), new Uint8Array(32), PEER_PUBKEY, { batch: 254, timeoutMs: 1, now: now + 1_000 }, ); expect(result).toBeNull(); }); it("tracks cooldown independently per peer pubkey", async () => { const now = 1_000_000; const other = "cd".repeat(32); await probeSubnetForPeer( "10.0.0", 49142, new Uint8Array(32), new Uint8Array(32), PEER_PUBKEY, { batch: 254, timeoutMs: 1, now }, ); expect(subnetProbeOnCooldown(PEER_PUBKEY, now + 1)).toBe(true); expect(subnetProbeOnCooldown(other, now + 1)).toBe(false); }); });