From 8398ff3d86a58a55dc0ef618a40a2af3d437b407 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Sat, 21 Oct 2023 13:41:25 -0700 Subject: [PATCH] options: Add IgnoreAnyFunction Adds a new IgnoreAnyFunction option to ignore stacks that have the provided function anywhere in the stack, not just the top. To test this better, the helper blockedG.run function was split into two. Supersedes #80 --- CHANGELOG.md | 3 +++ options.go | 16 ++++++++++++++++ options_test.go | 19 ++++++++++++++++++- utils_test.go | 4 ++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e589c8d..a2db308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Built-in ignores now match function names more accurately. They will no longer ignore stacks because of file names that look similar to function names. +### Added +- Add an `IgnoreAnyFunction` option to ignore stack traces + that have the provided function anywhere in the stack. ## [1.2.1] ### Changed diff --git a/options.go b/options.go index 31b0c18..ad5e77b 100644 --- a/options.go +++ b/options.go @@ -83,6 +83,22 @@ func IgnoreTopFunction(f string) Option { }) } +// IgnoreAnyFunction ignores goroutines where the specified function +// is present anywhere in the stack. +// +// The function name must be fully qualified, e.g., +// +// go.uber.org/goleak.IgnoreAnyFunction +// +// For methods, the fully qualified form looks like: +// +// go.uber.org/goleak.(*MyType).MyMethod +func IgnoreAnyFunction(f string) Option { + return addFilter(func(s stack.Stack) bool { + return s.HasFunction(f) + }) +} + // Cleanup sets up a cleanup function that will be executed at the // end of the leak check. // When passed to [VerifyTestMain], the exit code passed to cleanupFunc diff --git a/options_test.go b/options_test.go index 11438da..16c5f19 100644 --- a/options_test.go +++ b/options_test.go @@ -61,10 +61,27 @@ func TestOptionsFilters(t *testing.T) { require.Equal(t, 1, countUnfiltered(), "Expected blockedG goroutine to not match any filter") // If we add an extra filter to ignore blockTill, it shouldn't match. - opts = buildOpts(IgnoreTopFunction("go.uber.org/goleak.(*blockedG).run")) + opts = buildOpts(IgnoreTopFunction("go.uber.org/goleak.(*blockedG).block")) require.Zero(t, countUnfiltered(), "blockedG should be filtered out. running: %v", stack.All()) } +func TestOptionsIgnoreAnyFunction(t *testing.T) { + cur := stack.Current() + opts := buildOpts(IgnoreAnyFunction("go.uber.org/goleak.(*blockedG).run")) + + for _, s := range stack.All() { + if s.ID() == cur.ID() { + continue + } + + if opts.filter(s) { + continue + } + + t.Errorf("Unexpected goroutine: %v", s) + } +} + func TestBuildOptions(t *testing.T) { // With default options. opts := buildOpts() diff --git a/utils_test.go b/utils_test.go index 7d6b0f1..5504774 100644 --- a/utils_test.go +++ b/utils_test.go @@ -45,6 +45,10 @@ func startBlockedG() *blockedG { func (bg *blockedG) run() { close(bg.started) + bg.block() +} + +func (bg *blockedG) block() { <-bg.wait }