diff --git a/cmd/root_test.go b/cmd/root_test.go index eba07cdf8..aa58aeba5 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -13,6 +13,8 @@ import ( . "github.com/onsi/gomega" ) +var _ = pprof.NewProfile("nd-profiler-test") + var _ = Describe("profilerHandler", func() { // Mirrors how server.MountRouter mounts the handler. mount := func() http.Handler { @@ -23,9 +25,6 @@ var _ = Describe("profilerHandler", func() { BeforeEach(func() { DeferCleanup(configtest.SetupConfig()) - if pprof.Lookup("nd-profiler-test") == nil { - pprof.NewProfile("nd-profiler-test") - } }) DescribeTable("serves a named profile", @@ -33,7 +32,7 @@ var _ = Describe("profilerHandler", func() { conf.Server.BasePath = basePath w := httptest.NewRecorder() - target := path.Join(basePath, "/debug/pprof/nd-profiler-test") + "?debug=1" + target := basePath + "/debug/pprof/nd-profiler-test?debug=1" mount().ServeHTTP(w, httptest.NewRequest(http.MethodGet, target, nil)) Expect(w.Code).To(Equal(http.StatusOK)) diff --git a/plugins/host_cache_test.go b/plugins/host_cache_test.go index e3dbf6946..5e91b04ec 100644 --- a/plugins/host_cache_test.go +++ b/plugins/host_cache_test.go @@ -603,37 +603,33 @@ var _ = Describe("CacheService Integration", Ordered, func() { }) var _ = Describe("newCacheService", func() { - // Background goroutines wind down late, so poll for two consecutive equal samples. - settleGoroutines := func() int { - prev := -1 - for range 100 { + // The suite above leaves goroutines winding down, so settle before sampling. + settledBaseline := func() int { + var n int + Eventually(func() int { runtime.GC() - n := runtime.NumGoroutine() - if n == prev { - return n - } - prev = n - time.Sleep(10 * time.Millisecond) - } - return prev + prev := n + n = runtime.NumGoroutine() + return n - prev + }).WithTimeout(10 * time.Second).WithPolling(20 * time.Millisecond).Should(BeZero()) + return n } It("stops the janitor goroutine once the service is unreachable", func() { - const numServices = 20 + const numServices = 5 + baseline := settledBaseline() - baseline := settleGoroutines() + func() { + services := make([]*cacheServiceImpl, 0, numServices) + for i := range numServices { + services = append(services, newCacheService(fmt.Sprintf("plugin_%d", i))) + } + Expect(runtime.NumGoroutine()).To(BeNumerically(">=", baseline+numServices), + "expected one janitor goroutine per cache service") + }() - services := make([]*cacheServiceImpl, 0, numServices) - for i := range numServices { - services = append(services, newCacheService(fmt.Sprintf("plugin_%d", i))) - } - Expect(runtime.NumGoroutine()).To(BeNumerically(">=", baseline+numServices), - "expected one janitor goroutine per cache service") - - services = nil - Expect(services).To(BeNil()) - - Expect(settleGoroutines()).To(BeNumerically("<", baseline+numServices), - "janitor goroutines leaked after the services became unreachable") + Eventually(func() int { runtime.GC(); return runtime.NumGoroutine() }). + WithTimeout(10*time.Second).WithPolling(20*time.Millisecond). + Should(BeNumerically("<=", baseline), "janitor goroutines leaked") }) }) diff --git a/scanner/scanner_benchmark_test.go b/scanner/scanner_benchmark_test.go index 97ade09a7..91381aa0a 100644 --- a/scanner/scanner_benchmark_test.go +++ b/scanner/scanner_benchmark_test.go @@ -35,7 +35,7 @@ func BenchmarkScan(b *testing.B) { goleak.IgnoreTopFunction("github.com/rjeczalik/notify.(*recursiveTree).dispatch"), ) - // Benchmarks run without the suite's TestMain, so the config defaults must be loaded here + // go test -bench runs with -run=XXX, so TestScanner never loads the test config tests.Init(b, false) tmpDir := b.TempDir() diff --git a/server/backgrounds/handler_test.go b/server/backgrounds/handler_test.go index 31197f895..e8c77380f 100644 --- a/server/backgrounds/handler_test.go +++ b/server/backgrounds/handler_test.go @@ -10,10 +10,6 @@ import ( . "github.com/onsi/gomega" ) -type testItem string - -func (i testItem) Key() string { return string(i) } - type recordingBody struct { io.Reader closed *bool @@ -53,7 +49,7 @@ var _ = Describe("serveImage", func() { It("closes the response body when the hosting service returns an error", func() { stubStatus(http.StatusNotFound) - _, err := (&Handler{}).serveImage(context.Background(), testItem("some-image.webp")) + _, err := (&Handler{}).serveImage(context.Background(), cacheKey("some-image.webp")) Expect(err).To(MatchError(ContainSubstring("unexpected status code"))) Expect(closed).To(BeTrue(), "response body was left open") @@ -62,7 +58,7 @@ var _ = Describe("serveImage", func() { It("hands the still-open body to the caller on success", func() { stubStatus(http.StatusOK) - reader, err := (&Handler{}).serveImage(context.Background(), testItem("some-image.webp")) + reader, err := (&Handler{}).serveImage(context.Background(), cacheKey("some-image.webp")) Expect(err).ToNot(HaveOccurred()) Expect(closed).To(BeFalse(), "response body must stay open for the CachedStream wrapper")