From f49a2f7e145d9931796bfe679ed86d51e5877f1d Mon Sep 17 00:00:00 2001 From: liangshuo-1 Date: Thu, 14 May 2026 22:33:21 +0800 Subject: [PATCH] fix(registry): wait for background meta refresh before test reset (#894) * fix(registry): wait for background meta refresh before test reset TestComputeMinimumScopeSet can start doBackgroundRefresh via Init() while the next test's resetInit() mutates package-level globals the goroutine still reads (e.g. remoteMetaURL / configuredBrand), causing data races under -race in the coverage job. Track the refresh goroutine with a WaitGroup and drain it at the start of resetInit() in tests. --- internal/registry/remote.go | 11 +++++++++-- internal/registry/remote_test.go | 10 ++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/internal/registry/remote.go b/internal/registry/remote.go index 4fcaa357c..b229f641f 100644 --- a/internal/registry/remote.go +++ b/internal/registry/remote.go @@ -255,11 +255,18 @@ func doSyncFetch() { // --- background refresh --- -var refreshOnce sync.Once +var ( + refreshOnce sync.Once + bgRefreshInFlight sync.WaitGroup // tracks doBackgroundRefresh goroutines for test teardown (resetInit) +) func triggerBackgroundRefresh() { refreshOnce.Do(func() { - go doBackgroundRefresh() + bgRefreshInFlight.Add(1) + go func() { + defer bgRefreshInFlight.Done() + doBackgroundRefresh() + }() }) } diff --git a/internal/registry/remote_test.go b/internal/registry/remote_test.go index c8b2f77e8..0595ce9b9 100644 --- a/internal/registry/remote_test.go +++ b/internal/registry/remote_test.go @@ -17,8 +17,18 @@ import ( "github.com/larksuite/cli/internal/core" ) +// waitBackgroundRefresh blocks until any in-flight background refresh started by +// triggerBackgroundRefresh has finished. Lives in this _test file so production +// binaries cannot call it and accidentally block on test teardown state. +func waitBackgroundRefresh() { + bgRefreshInFlight.Wait() +} + // resetInit resets the package-level state so each test starts fresh. func resetInit() { + // Must wait: a prior test's Init() may have started doBackgroundRefresh which + // reads globals this function mutates (see CI race: TestComputeMinimumScopeSet → Tenant). + waitBackgroundRefresh() initOnce = sync.Once{} mergedServices = make(map[string]map[string]interface{}) mergedProjectList = nil