From cf210201be69501320833ed49391677f398a949e 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 | 4 +++- options.go | 16 ++++++++++++++++ options_test.go | 19 ++++++++++++++++++- utils_test.go | 4 ++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ded8e3..324d9d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] -- No changes yet. +### 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 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 }