Skip to content

Commit

Permalink
Add option to ignore current goroutines (#49)
Browse files Browse the repository at this point in the history
This allows usage specific tests in big projects that recently started to use go-leak check.

Signed-off-by: denis-tingajkin <denis.tingajkin@xored.com>


## Motivation

#48
  • Loading branch information
denis-tingaikin committed Jul 17, 2020
1 parent 4eaa857 commit 100c34b
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 0 deletions.
88 changes: 88 additions & 0 deletions leaks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package goleak

import (
"fmt"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -83,6 +84,93 @@ func TestVerifyNone(t *testing.T) {
bg.unblock()
}

func TestIgnoreCurrent(t *testing.T) {
t.Run("Should ignore current", func(t *testing.T) {
defer VerifyNone(t)

done := make(chan struct{})
go func() {
<-done
}()

// We expect the above goroutine to be ignored.
VerifyNone(t, IgnoreCurrent())
close(done)
})

t.Run("Should detect new leaks", func(t *testing.T) {
defer VerifyNone(t)

// There are no leaks currently.
VerifyNone(t)

done1 := make(chan struct{})
done2 := make(chan struct{})

go func() {
<-done1
}()

err := Find()
require.Error(t, err, "Expected to find background goroutine as leak")

opt := IgnoreCurrent()
VerifyNone(t, opt)

// A second goroutine started after IgnoreCurrent is a leak
go func() {
<-done2
}()

err = Find(opt)
require.Error(t, err, "Expect second goroutine to be flagged as a leak")

close(done1)
close(done2)
})

t.Run("Should not ignore false positive", func(t *testing.T) {
defer VerifyNone(t)

const goroutinesCount = 5
var wg sync.WaitGroup
done := make(chan struct{})

// Spawn few goroutines before checking leaks
for i := 0; i < goroutinesCount; i++ {
wg.Add(1)
go func() {
<-done
wg.Done()
}()
}

// Store all goroutines
option := IgnoreCurrent()

// Free goroutines
close(done)
wg.Wait()

// We expect the below goroutines to be founded.
for i := 0; i < goroutinesCount; i++ {
ch := make(chan struct{})

go func() {
<-ch
}()

require.Error(t, Find(option), "Expect spawned goroutine to be flagged as a leak")

// Free spawned goroutine
close(ch)

// Make sure that there are no leaks
VerifyNone(t)
}
})
}

func TestVerifyParallel(t *testing.T) {
t.Run("parallel", func(t *testing.T) {
t.Parallel()
Expand Down
12 changes: 12 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ func IgnoreTopFunction(f string) Option {
})
}

// IgnoreCurrent records all current goroutines when the option is created, and ignores
// them in any future Find/Verify calls.
func IgnoreCurrent() Option {
excludeIDSet := map[int]bool{}
for _, s := range stack.All() {
excludeIDSet[s.ID()] = true
}
return addFilter(func(s stack.Stack) bool {
return excludeIDSet[s.ID()]
})
}

func maxSleep(d time.Duration) Option {
return optionFunc(func(opts *opts) {
opts.maxSleep = d
Expand Down

0 comments on commit 100c34b

Please sign in to comment.