Skip to content

Commit 9eff50e

Browse files
committed
Optimize test suite: 710s to under 50s
- Short dial timeouts (2s) on tests that expect connection failure - Configurable webhook retry backoff (10ms in tests vs 1s production) - Fast HTTP timeouts (200-500ms) for webhook tests hitting unreachable URLs - Fix TestSecureHandshakeTimeout: close pipe peer for instant EOF vs 10s wait - Reduce DLQ test sleeps (8s/2s to 500ms/200ms) with fast retry backoff - Unblock server before Close() in dropped counter tests to avoid drain timeout - TestEnv defaults: 500ms webhook HTTP timeout, 10ms retry backoff - Reap threshold test updated for 5-minute threshold
1 parent b14a84b commit 9eff50e

10 files changed

Lines changed: 70 additions & 45 deletions

tests/beacon_registry_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ func TestReapStaleNodes(t *testing.T) {
168168
t.Fatalf("lookup before reap: %v", err)
169169
}
170170

171-
// Advance clock past stale threshold (3 minutes)
172-
clk.Advance(4 * time.Minute)
171+
// Advance clock past stale threshold (5 minutes)
172+
clk.Advance(6 * time.Minute)
173173

174174
// Trigger reap
175175
reg.Reap()

tests/fuzz_secure_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,10 @@ func TestSecureHandshakeClosedMidExchange(t *testing.T) {
9191
}
9292

9393
func TestSecureHandshakeTimeout(t *testing.T) {
94-
c1, _ := net.Pipe() // c2 is intentionally unused — simulates slow peer
94+
c1, c2 := net.Pipe()
9595
defer c1.Close()
96-
97-
// Override timeout by setting a short deadline
98-
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
96+
// Close c2 immediately so c1 reads hit EOF (not a 10s handshake timeout).
97+
c2.Close()
9998

10099
_, err := secure.Handshake(c1, true)
101100
if err == nil {

tests/fuzz_webhook_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,16 @@ func TestWebhookClientServerError(t *testing.T) {
188188
}))
189189
defer ts.Close()
190190

191-
wc := daemon.NewWebhookClient(ts.URL, func() uint32 { return 1 })
191+
wc := daemon.NewWebhookClient(ts.URL, func() uint32 { return 1 },
192+
daemon.WithRetryBackoff(10*time.Millisecond))
192193
wc.Emit("test", nil) // server error should not crash
193194
wc.Close()
194195
}
195196

196197
func TestWebhookClientBadURL(t *testing.T) {
197-
wc := daemon.NewWebhookClient("http://127.0.0.1:1", func() uint32 { return 1 })
198+
wc := daemon.NewWebhookClient("http://127.0.0.1:1", func() uint32 { return 1 },
199+
daemon.WithHTTPTimeout(200*time.Millisecond),
200+
daemon.WithRetryBackoff(10*time.Millisecond))
198201
wc.Emit("test", nil) // connection refused should not crash
199202
wc.Close()
200203
}

tests/integration_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -983,13 +983,14 @@ func TestIntegration_WebhookDLQWithRealServer(t *testing.T) {
983983
}))
984984
defer failServer.Close()
985985

986-
rc, _, cleanup := startTestRegistryWithAdmin(t)
986+
rc, reg, cleanup := startTestRegistryWithAdmin(t)
987987
defer cleanup()
988988

989989
_, err := rc.SetWebhook(failServer.URL, TestAdminToken)
990990
if err != nil {
991991
t.Fatalf("set webhook: %v", err)
992992
}
993+
reg.SetWebhookRetryBackoff(10 * time.Millisecond) // fast retries in tests
993994

994995
// Trigger events
995996
ownerID, _ := registerTestNode(t, rc)
@@ -998,8 +999,8 @@ func TestIntegration_WebhookDLQWithRealServer(t *testing.T) {
998999
t.Fatalf("create network: %v", err)
9991000
}
10001001

1001-
// Wait for retries to exhaust (3 retries * exponential backoff)
1002-
time.Sleep(8 * time.Second)
1002+
// Wait for retries to exhaust (3 retries * fast backoff)
1003+
time.Sleep(500 * time.Millisecond)
10031004

10041005
whResp, err := rc.GetWebhook(TestAdminToken)
10051006
if err != nil {

tests/metrics_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ func TestPerNetworkMetrics(t *testing.T) {
528528
// TestWebhookDLQ verifies the dead letter queue for failed webhook deliveries.
529529
func TestWebhookDLQ(t *testing.T) {
530530
t.Parallel()
531-
rc, _, cleanup := startTestRegistryWithAdmin(t)
531+
rc, reg, cleanup := startTestRegistryWithAdmin(t)
532532
defer cleanup()
533533

534534
// Configure webhook to an endpoint that always returns 500
@@ -547,10 +547,11 @@ func TestWebhookDLQ(t *testing.T) {
547547
if err != nil {
548548
t.Fatalf("set webhook: %v", err)
549549
}
550+
reg.SetWebhookRetryBackoff(10 * time.Millisecond) // fast retries in tests
550551

551552
// Trigger audit events that will fail to deliver
552553
registerTestNode(t, rc)
553-
time.Sleep(2 * time.Second) // wait for retries
554+
time.Sleep(200 * time.Millisecond) // wait for retries
554555

555556
// Check webhook stats
556557
whResp, err := rc.GetWebhook(TestAdminToken)

tests/syn_trust_gate_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ func TestSYNFromUntrustedNodeRejected(t *testing.T) {
3535
// (e.g., from a cached previous session). The trust gate is defense-in-depth.
3636
client.Daemon.AddTunnelPeer(server.Daemon.NodeID(), localUDPAddr(server.Daemon))
3737

38-
// Server listens on port 7 (echo) by default, so dial should fail via trust gate
39-
_, err := client.Driver.DialAddr(server.Daemon.Addr(), 7)
38+
// Server listens on port 7 (echo) by default, so dial should fail via trust gate.
39+
// Use short timeout — we expect rejection, not a 30s dial timeout.
40+
_, err := client.Driver.DialAddrTimeout(server.Daemon.Addr(), 7, 2*time.Second)
4041
if err == nil {
4142
t.Fatal("expected dial to fail between untrusted nodes, but it succeeded")
4243
}
@@ -183,8 +184,9 @@ func TestSYNRejectionWebhook(t *testing.T) {
183184
// Pre-populate client's tunnel with server's address to bypass resolve
184185
client.Daemon.AddTunnelPeer(server.Daemon.NodeID(), localUDPAddr(server.Daemon))
185186

186-
// Attempt connection — should be rejected by trust gate
187-
_, _ = client.Driver.DialAddr(server.Daemon.Addr(), 7)
187+
// Attempt connection — should be rejected by trust gate.
188+
// Use short timeout — we expect rejection, not a 30s dial timeout.
189+
_, _ = client.Driver.DialAddrTimeout(server.Daemon.Addr(), 7, 2*time.Second)
188190

189191
// Wait for syn.rejected webhook event
190192
ev, ok := collector.WaitFor("syn.rejected", 3*time.Second)

tests/testenv.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,15 @@ func (env *TestEnv) AddDaemon(opts ...func(*daemon.Config)) *DaemonInfo {
123123
identityPath := filepath.Join(env.tmpDir, fmt.Sprintf("identity-%d.json", idx))
124124

125125
cfg := daemon.Config{
126-
RegistryAddr: env.RegistryAddr,
127-
BeaconAddr: env.BeaconAddr,
128-
ListenAddr: ":0",
129-
SocketPath: sockPath,
130-
IdentityPath: identityPath, // persist identity to avoid pubkey mismatch on restart
131-
Email: fmt.Sprintf("test-%d@pilot.local", idx),
132-
Public: true, // tests default to public for free connectivity
126+
RegistryAddr: env.RegistryAddr,
127+
BeaconAddr: env.BeaconAddr,
128+
ListenAddr: ":0",
129+
SocketPath: sockPath,
130+
IdentityPath: identityPath, // persist identity to avoid pubkey mismatch on restart
131+
Email: fmt.Sprintf("test-%d@pilot.local", idx),
132+
Public: true, // tests default to public for free connectivity
133+
WebhookHTTPTimeout: 500 * time.Millisecond, // fast webhook timeouts for tests
134+
WebhookRetryBackoff: 10 * time.Millisecond, // fast retry backoff for tests
133135
}
134136
for _, fn := range opts {
135137
fn(&cfg)
@@ -160,13 +162,15 @@ func (env *TestEnv) AddDaemonOnly(opts ...func(*daemon.Config)) (*daemon.Daemon,
160162
identityPath := filepath.Join(env.tmpDir, fmt.Sprintf("identity-%d.json", idx))
161163

162164
cfg := daemon.Config{
163-
RegistryAddr: env.RegistryAddr,
164-
BeaconAddr: env.BeaconAddr,
165-
ListenAddr: ":0",
166-
SocketPath: sockPath,
167-
IdentityPath: identityPath, // persist identity to avoid pubkey mismatch on restart
168-
Email: fmt.Sprintf("test-%d@pilot.local", idx),
169-
Public: true, // tests default to public for free connectivity
165+
RegistryAddr: env.RegistryAddr,
166+
BeaconAddr: env.BeaconAddr,
167+
ListenAddr: ":0",
168+
SocketPath: sockPath,
169+
IdentityPath: identityPath, // persist identity to avoid pubkey mismatch on restart
170+
Email: fmt.Sprintf("test-%d@pilot.local", idx),
171+
Public: true, // tests default to public for free connectivity
172+
WebhookHTTPTimeout: 500 * time.Millisecond, // fast webhook timeouts for tests
173+
WebhookRetryBackoff: 10 * time.Millisecond, // fast retry backoff for tests
170174
}
171175
for _, fn := range opts {
172176
fn(&cfg)

tests/tunnel_encrypt_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,9 @@ func TestTunnelEncryptionBackwardCompat(t *testing.T) {
147147

148148
t.Logf("daemon A: encrypted, daemon B: plaintext — expect dial failure")
149149

150-
// Plaintext daemon B should NOT be able to reach encrypted daemon A
151-
_, err := drvB.Dial(daemonA.Addr().String() + ":7")
150+
// Plaintext daemon B should NOT be able to reach encrypted daemon A.
151+
// Use short timeout — we expect rejection, not a 30s dial timeout.
152+
_, err := drvB.DialAddrTimeout(daemonA.Addr(), 7, 2*time.Second)
152153
if err == nil {
153154
t.Fatal("expected dial to fail: encrypted daemon should not accept plaintext connections")
154155
}

tests/webhook_reliability_test.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ func TestWebhookRetryMaxThreeAttempts(t *testing.T) {
5252
}))
5353
defer srv.Close()
5454

55-
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 })
55+
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 },
56+
daemon.WithRetryBackoff(10*time.Millisecond))
5657
wc.Emit("always-fail", nil)
5758
wc.Close()
5859

@@ -190,6 +191,7 @@ func TestWebhookDroppedCounterAccurate(t *testing.T) {
190191
t.Parallel()
191192

192193
ready := make(chan struct{})
194+
var blockOnce sync.Once
193195
block := make(chan struct{})
194196

195197
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -203,17 +205,19 @@ func TestWebhookDroppedCounterAccurate(t *testing.T) {
203205
w.WriteHeader(200)
204206
}))
205207
defer srv.Close()
206-
defer close(block)
208+
defer blockOnce.Do(func() { close(block) })
207209

208-
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 })
210+
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 },
211+
daemon.WithHTTPTimeout(200*time.Millisecond),
212+
daemon.WithRetryBackoff(10*time.Millisecond))
209213

210214
// Emit the first event to get the worker goroutine into the blocked HTTP request
211215
wc.Emit("trigger", nil)
212216

213217
// Wait until the worker is actually blocked in the server
214218
select {
215219
case <-ready:
216-
case <-time.After(5 * time.Second):
220+
case <-time.After(2 * time.Second):
217221
t.Fatal("timeout waiting for worker to start sending")
218222
}
219223

@@ -228,6 +232,8 @@ func TestWebhookDroppedCounterAccurate(t *testing.T) {
228232
t.Fatal("expected at least 1 dropped event when queue is overfull")
229233
}
230234
t.Logf("dropped %d events", dropped)
235+
236+
blockOnce.Do(func() { close(block) }) // unblock server so queued events drain with 200 OK
231237
wc.Close()
232238
}
233239

@@ -345,7 +351,8 @@ func TestWebhookRetryOn5xx(t *testing.T) {
345351
}))
346352
defer srv.Close()
347353

348-
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 })
354+
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 },
355+
daemon.WithRetryBackoff(10*time.Millisecond))
349356
wc.Emit("retry.test", nil)
350357
wc.Close()
351358

@@ -494,15 +501,18 @@ func TestWebhookDroppedCounter(t *testing.T) {
494501
t.Parallel()
495502

496503
// Create a server that blocks forever so the queue fills up
504+
var blockOnce sync.Once
497505
block := make(chan struct{})
498506
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
499507
<-block // block until test ends
500508
w.WriteHeader(200)
501509
}))
502510
defer srv.Close()
503-
defer close(block)
511+
defer blockOnce.Do(func() { close(block) })
504512

505-
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 })
513+
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 },
514+
daemon.WithHTTPTimeout(200*time.Millisecond),
515+
daemon.WithRetryBackoff(10*time.Millisecond))
506516

507517
// Fill the 1024-item buffer. The first event will be consumed by the run
508518
// goroutine and block in post(), so we need 1024+1 more to fill the queue
@@ -520,5 +530,6 @@ func TestWebhookDroppedCounter(t *testing.T) {
520530
}
521531
t.Logf("dropped %d events as expected", dropped)
522532

533+
blockOnce.Do(func() { close(block) }) // unblock server so queued events drain with 200 OK
523534
wc.Close()
524535
}

tests/webhook_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,20 @@ func TestWebhookClient_FailedPOSTDoesNotBlock(t *testing.T) {
226226
}))
227227
defer srv.Close()
228228

229-
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 })
229+
wc := daemon.NewWebhookClient(srv.URL, func() uint32 { return 1 },
230+
daemon.WithRetryBackoff(10*time.Millisecond))
230231
wc.Emit("fail.event", nil)
231232
wc.Close() // should not hang
232233
}
233234

234235
func TestWebhookClient_UnreachableDoesNotBlock(t *testing.T) {
235236
t.Parallel()
236-
// Point to a non-existent server.
237-
wc := daemon.NewWebhookClient("http://127.0.0.1:1", func() uint32 { return 1 })
237+
// Point to a non-existent server. Use short timeouts to avoid 15s wait.
238+
wc := daemon.NewWebhookClient("http://127.0.0.1:1", func() uint32 { return 1 },
239+
daemon.WithHTTPTimeout(200*time.Millisecond),
240+
daemon.WithRetryBackoff(10*time.Millisecond))
238241
wc.Emit("unreachable.event", nil)
239-
wc.Close() // should complete (5s HTTP timeout, but drain completes)
242+
wc.Close() // should complete quickly
240243
}
241244

242245
func TestWebhookClient_DoubleClose(t *testing.T) {
@@ -707,7 +710,7 @@ func TestWebhook_TrustRevoke(t *testing.T) {
707710
// B's webhook should have trust.revoked_by_peer (best-effort delivery —
708711
// the revoke notification is sent after the tunnel is torn down, so the
709712
// re-dial may not always succeed in local test environments)
710-
ev, ok = collectorB.WaitFor("trust.revoked_by_peer", 5*time.Second)
713+
ev, ok = collectorB.WaitFor("trust.revoked_by_peer", 1*time.Second)
711714
if !ok {
712715
t.Log("trust.revoked_by_peer not received on B (best-effort delivery, may not arrive after tunnel teardown)")
713716
} else {

0 commit comments

Comments
 (0)