From f0016f6cf94ea5072ff774f0dc15d2c6ec6188a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0?= <77561975+AyaseEli-Bing@users.noreply.github.com> Date: Fri, 9 Oct 2026 04:02:46 +0800 Subject: [PATCH] test: stop swapping http.DefaultTransport in the Happ network test (#6742) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: stop swapping http.DefaultTransport in the Happ network test The Happ local-generation test replaced the http.DefaultTransport global to refuse sockets. resolvePublicIPsInBackground fires a fire-and-forget resolver (ServerService.GetStatus -> resolvePublicIPs -> getPublicIP), and that goroutine can outlive the test that scheduled it, so a later test writes the global while the resolver is reading it: a data race that `make race` (-shuffle=on) only reports when the status test happens to run first. Route the lookup transport through an atomic swap point and count in-flight lookups, so the test stubs its own path and waits for earlier resolvers to settle before installing it. That also stops another test's dials from landing in this test's zero-network tally. Reproduced on the parent commit with -shuffle=6 (read in getPublicIP, previous write in TestHappGenerateLocallyWithoutNetwork); the same seed is clean with this change, across repeats and for the whole package under -race. * test: prove the Happ network guard intercepts panel egress The PR review pointed out that HappService.Generate never reaches a stub installed only on the public-IP lookup, so the "zero network attempts" assertion could not fail. Move the override onto the panel's shared egress seam — getPublicIP and SettingService.NewProxiedHTTPClient — and gate the test on a canary request that must be refused and must move the tally, so a future outbound call from local generation is reported instead of passing unnoticed. * test(service): stop the cold-status test leaking a public-IP resolver The race CI hit (run 37345781756) came from TestCurrentStatusSamplesBeforeFirstTick: its CurrentStatus call starts resolvePublicIPsInBackground, a goroutine that makes real internet requests and outlives the test. On a runner without IPv6 every lookup waits out its 3s timeout, so the goroutine is still building clients from http.DefaultTransport when the Happ test swaps it. Pre-settling the IP cache keeps that test from starting the resolver at all, so no unit test reaches the internet or leaks the goroutine. This replaces the earlier panelEgressTransport / panelEgressLookups seam, which added test-only hooks to production code without removing the leak. Reproduced in golang:1.27-bookworm with egress routed to a blackhole (HTTPS_PROXY=http://10.255.255.1:9, -race -count=3 on the two tests): the same server.go:406 race as CI before, clean over -count=5 after. --------- Co-authored-by: MHSanaei --- internal/web/service/server_cold_status_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/web/service/server_cold_status_test.go b/internal/web/service/server_cold_status_test.go index fd83803a9..150346254 100644 --- a/internal/web/service/server_cold_status_test.go +++ b/internal/web/service/server_cold_status_test.go @@ -14,7 +14,9 @@ func TestCurrentStatusSamplesBeforeFirstTick(t *testing.T) { t.Setenv("XUI_DB_FOLDER", dbDir) dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db")) - svc := &ServerService{} + // A settled IP cache keeps GetStatus from starting a public-IP resolver that + // outlives this test and races http.DefaultTransport in later ones. + svc := &ServerService{cachedIPv4: "192.0.2.1", noIPv6: true} if svc.LastStatus() != nil { t.Fatal("a fresh ServerService should hold no snapshot yet") }