From bdcdbaf23afb6efb814168f0171f2df5306c9fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Fri, 16 Oct 2026 10:09:46 +0200 Subject: [PATCH] Test harness: pick a port that is free for UDP as well as TCP The DNS listeners bind TCP and UDP on one port, and the harness probed TCP only. Under a full parallel run the port could be one another test's ephemeral UDP client socket held, the listener failed to bind, and the queries saw connection refused. That made TestConsoleEditsReachTheResolver fail once in a full suite and pass 12 of 12 on its own. Co-Authored-By: Claude Sonnet 5.5 --- internal/app/harness_test.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/internal/app/harness_test.go b/internal/app/harness_test.go index cec5f02..c8302a5 100644 --- a/internal/app/harness_test.go +++ b/internal/app/harness_test.go @@ -182,16 +182,27 @@ func newHarness(t *testing.T, mutate func(*config.Config), opts ...func(*Options return &harness{t: t, app: a, addr: dnsAddr, api: a.Addr(), key: "test-key", up: up, dir: dir, config: doc} } -// freePort returns a currently-free TCP port on the loopback interface. +// freePort returns a port that is free for both TCP and UDP on the loopback +// interface. The DNS listeners bind both on one port, and a TCP-only probe can +// hand out a port that another test's ephemeral UDP client socket is holding, +// which made the listener fail to bind and the queries see "connection refused". func freePort(t *testing.T) int { t.Helper() - ln, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("free port: %v", err) + for range 50 { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("free port: %v", err) + } + port := ln.Addr().(*net.TCPAddr).Port + pc, perr := net.ListenPacket("udp", fmt.Sprintf("127.0.0.1:%d", port)) + _ = ln.Close() + if perr == nil { + _ = pc.Close() + return port + } } - port := ln.Addr().(*net.TCPAddr).Port - _ = ln.Close() - return port + t.Fatal("no loopback port was free for TCP and UDP at once") + return 0 } func (h *harness) query(name string, qtype uint16) *dns.Msg {