From 3e4e5427d918b0433de7f8ef97114ef6d683c89e Mon Sep 17 00:00:00 2001 From: sneak Date: Fri, 2 Oct 2026 07:54:14 +0000 Subject: [PATCH] Discard fx's own log in tests that build an fx app (closes #230) fxtest.New sends fx's event log to t.Logf. When a start or stop runs past fx's time limit, Start or Stop returns while the hook keeps running in a goroutine, and that goroutine logs to the test after the test has returned, which the race detector reports. Every fxtest.New now passes fx.NopLogger, so nothing fx runs can reach the test. The fxtest.Lifecycle sites are unchanged: they run hooks on the goroutine that calls Start or Stop, which is always the test or its cleanup. Model: opus-5-5 --- internal/config/config_test.go | 12 ++++++++++++ internal/gormlog/firstboot_test.go | 4 ++++ internal/handlers/handlers_test.go | 4 ++++ internal/resetpw/resetpw_test.go | 4 ++++ internal/server/routes_test.go | 4 ++++ 5 files changed, 28 insertions(+) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e3682e0..e5f76b3 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -124,6 +124,11 @@ func testEnvironmentConfigSuccess( app := fxtest.New( t, + // fx's own log is discarded, not sent to t.Logf: a hook still + // running after a start or stop timeout would write there after + // the test has returned. The same holds for every fxtest.New + // below. + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -272,6 +277,7 @@ func testRetentionSweepIntervalSuccess( app := fxtest.New( t, + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -364,6 +370,7 @@ func testSessionIdleTimeoutSuccess( app := fxtest.New( t, + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -404,6 +411,7 @@ func TestDefaultDataDir(t *testing.T) { app := fxtest.New( t, + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -534,6 +542,7 @@ func testReceiverRateLimitSuccess( app := fxtest.New( t, + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -650,6 +659,7 @@ func testTrustedProxiesSuccess( app := fxtest.New( t, + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -763,6 +773,7 @@ func testAllowedEgressCIDRsSuccess( app := fxtest.New( t, + fx.NopLogger, fx.Provide( globals.New, logger.New, @@ -1006,6 +1017,7 @@ func assertMetricsAuthAccepted(t *testing.T, expectAuth bool) { app := fxtest.New( t, + fx.NopLogger, fx.Provide(globals.New, logger.New, config.New), fx.Populate(&cfg), ) diff --git a/internal/gormlog/firstboot_test.go b/internal/gormlog/firstboot_test.go index 6fab1a5..8a9dd89 100644 --- a/internal/gormlog/firstboot_test.go +++ b/internal/gormlog/firstboot_test.go @@ -137,6 +137,10 @@ func bootAtDebug(t *testing.T, dataDir string) string { app := fxtest.New( t, + // fx's own log is discarded, not sent to t.Logf: a hook still + // running after a start or stop timeout would write there after + // the test has returned. + fx.NopLogger, fx.Provide( globals.New, logger.New, diff --git a/internal/handlers/handlers_test.go b/internal/handlers/handlers_test.go index c9fa103..7266b62 100644 --- a/internal/handlers/handlers_test.go +++ b/internal/handlers/handlers_test.go @@ -86,6 +86,10 @@ func newTestApp( return fxtest.New( t, + // fx's own log is discarded, not sent to t.Logf: a hook still + // running after a start or stop timeout would write there after + // the test has returned. + fx.NopLogger, fx.Provide( globals.New, logger.New, diff --git a/internal/resetpw/resetpw_test.go b/internal/resetpw/resetpw_test.go index 1d3aa0a..927f774 100644 --- a/internal/resetpw/resetpw_test.go +++ b/internal/resetpw/resetpw_test.go @@ -152,6 +152,10 @@ func newServerApp( app := fxtest.New( t, + // fx's own log is discarded, not sent to t.Logf: a hook still + // running after a start or stop timeout would write there after + // the test has returned. + fx.NopLogger, fx.Provide( globals.New, logger.New, diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go index e9766a7..567d3ee 100644 --- a/internal/server/routes_test.go +++ b/internal/server/routes_test.go @@ -104,6 +104,10 @@ func newTestEnvWithConfig( app := fxtest.New( t, + // fx's own log is discarded, not sent to t.Logf: a hook still + // running after a start or stop timeout would write there after + // the test has returned. + fx.NopLogger, fx.Provide( globals.New, logger.New, -- 2.54.0