Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RunOnFailure option #129

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions leaks.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ func Find(options ...Option) error {
if opts.cleanup != nil {
return errors.New("Cleanup can only be passed to VerifyNone or VerifyTestMain")
}
if opts.runOnFailure {
return errors.New("RunOnFailure can only be passed to VerifyTestMain")
}
var stacks []stack.Stack
retry := true
for i := 0; retry; i++ {
Expand Down
18 changes: 14 additions & 4 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ type Option interface {
const _defaultRetries = 20

type opts struct {
filters []func(stack.Stack) bool
maxRetries int
maxSleep time.Duration
cleanup func(int)
filters []func(stack.Stack) bool
maxRetries int
maxSleep time.Duration
cleanup func(int)
runOnFailure bool
}

// implement apply so that opts struct itself can be used as
Expand All @@ -51,6 +52,7 @@ func (o *opts) apply(opts *opts) {
opts.maxRetries = o.maxRetries
opts.maxSleep = o.maxSleep
opts.cleanup = o.cleanup
opts.runOnFailure = o.runOnFailure
}

// optionFunc lets us easily write options without a custom type.
Expand Down Expand Up @@ -107,6 +109,14 @@ func IgnoreCurrent() Option {
})
}

// RunOnFailure makes goleak look for leaking goroutines upon test failures.
// By default goleak only looks for leaking goroutines when tests succeed.
func RunOnFailure() Option {
return optionFunc(func(opts *opts) {
opts.runOnFailure = true
})
}

func maxSleep(d time.Duration) Option {
return optionFunc(func(opts *opts) {
opts.maxSleep = d
Expand Down
22 changes: 19 additions & 3 deletions testmain.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,26 @@ func VerifyTestMain(m TestingM, options ...Option) {
}
defer func() { cleanup(exitCode) }()

if exitCode == 0 {
var (
run bool
errorMsg string
)

if !opts.runOnFailure && exitCode == 0 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think opts.runOnFailure should matter here.
to keep the old behaviour, we only need to check on exitCode.

	if exitCode == 0 {
		errorMsg = "goleak: Errors on successful test run:%v\n"
		run = true
	} else if opts.runOnFailure {
		errorMsg = "goleak: Errors on unsuccessful test run: %v\n"
		run = true
	}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened #132 in case this went unnoticed

errorMsg = "goleak: Errors on successful test run:%v\n"
run = true
} else if opts.runOnFailure {
errorMsg = "goleak: Errors on unsuccessful test run: %v\n"
run = true
}

if run {
if err := Find(opts); err != nil {
fmt.Fprintf(_osStderr, "goleak: Errors on successful test run: %v\n", err)
exitCode = 1
fmt.Fprintf(_osStderr, errorMsg, err)
// rewrite exitCode if test passed and is set to 0.
if exitCode == 0 {
exitCode = 1
}
}
}
}
4 changes: 4 additions & 0 deletions testmain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func TestVerifyTestMain(t *testing.T) {
assert.Equal(t, 7, <-exitCode, "Exit code should not be modified")
assert.NotContains(t, <-stderr, "goleak: Errors", "Ignore leaks on unsuccessful runs")

VerifyTestMain(dummyTestMain(7), RunOnFailure())
assert.Equal(t, 7, <-exitCode, "Exit code should not be modified")
assert.Contains(t, <-stderr, "goleak: Errors", "Find leaks on unsuccessful runs with RunOnFailure specified")

VerifyTestMain(dummyTestMain(0))
assert.Equal(t, 1, <-exitCode, "Expect error due to leaks on successful runs")
assert.Contains(t, <-stderr, "goleak: Errors", "Find leaks on successful runs")
Expand Down
Loading