From 3358138cccb4f5d65692984334bcd20da0146c81 Mon Sep 17 00:00:00 2001
From: Riccardo Manfrin <3090891+riccardomanfrin@users.noreply.github.com>
Date: Thu, 23 Jul 2026 15:48:16 +0200
Subject: [PATCH] [client] Fix flaky Test_ConnectPeers busy-loop handshake wait
(#6871)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Describe your changes
`Test_ConnectPeers` in `client/iface` is flaky in CI, timing out with
`waiting for peer handshake timeout after 30s`.
The wait loop polled `getPeer()` in a tight busy-loop with no sleep
(a `select` with a `default` branch), pegging a CPU core. The peers run
userspace WireGuard (stdnet transport), so the spin starved the
wireguard-go goroutines that actually process the handshake, making the
30s wait flaky under CI load.
Poll on a 500ms ticker instead so the CPU is yielded between checks, and
check the handshake state before waiting. Same logic, no busy-spin.
## Issue ticket number and link
N/A — CI flakiness fix.
### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [ ] Created tests that fail without the change (if possible)
- [x] This change does **not** modify the public API, gRPC protocols,
functionality behavior, CLI / service flags, or introduce a new feature
## Documentation
- [x] Documentation is **not needed** for this change (test-only fix)
---
Need help on this PR? Tag @codesmith-bot with what you
need. Autofix is disabled.
## Summary by CodeRabbit
* **Tests**
* Improved peer connection test waiting behavior to avoid busy spinning.
* Added a timeout and periodic checks, with clearer failure handling
when a handshake does not complete.
---
client/iface/iface_test.go | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/client/iface/iface_test.go b/client/iface/iface_test.go
index 8ff2bbb54..43b3d8168 100644
--- a/client/iface/iface_test.go
+++ b/client/iface/iface_test.go
@@ -569,17 +569,17 @@ func Test_ConnectPeers(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- // todo: investigate why in some tests execution we need 30s
+ // The peers use userspace WireGuard (stdnet transport). A tight busy-loop
+ // here starves the wireguard-go goroutines that process the handshake, so
+ // poll on a ticker instead and yield the CPU between checks. WireGuard also
+ // only retries a lost handshake initiation every REKEY_TIMEOUT (5s), which
+ // is why the overall wait can occasionally stretch to tens of seconds.
timeout := 30 * time.Second
timeoutChannel := time.After(timeout)
+ ticker := time.NewTicker(500 * time.Millisecond)
+ defer ticker.Stop()
for {
- select {
- case <-timeoutChannel:
- t.Fatalf("waiting for peer handshake timeout after %s", timeout.String())
- default:
- }
-
peer, gpErr := getPeer(peer1ifaceName, peer2Key.PublicKey().String())
if gpErr != nil {
t.Fatal(gpErr)
@@ -588,6 +588,12 @@ func Test_ConnectPeers(t *testing.T) {
t.Log("peers successfully handshake")
break
}
+
+ select {
+ case <-timeoutChannel:
+ t.Fatalf("waiting for peer handshake timeout after %s", timeout.String())
+ case <-ticker.C:
+ }
}
}