From 5f03f7140469c21f861cfb62b57bf19906db1202 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 --- options.go | 16 ++++++++++++++++ options_test.go | 19 ++++++++++++++++++- utils_test.go | 4 ++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/options.go b/options.go index 345eab1..21d237d 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 }