...

Source file src/github.com/onsi/gomega/gleak/doc.go

Documentation: github.com/onsi/gomega/gleak

     1  /*
     2  package gleak complements the Gingko/Gomega testing and matchers framework with
     3  matchers for Goroutine leakage detection.
     4  
     5  # Basics of gleak
     6  
     7  To start with,
     8  
     9  	Goroutines()
    10  
    11  returns information about all (non-dead) goroutines at a particular moment. This
    12  is useful to capture a known correct snapshot and then later taking a new
    13  snapshot and comparing these two snapshots for leaked goroutines.
    14  
    15  Next, the matcher
    16  
    17  	HaveLeaked(...)
    18  
    19  filters out well-known and expected "non-leaky" goroutines from an actual list
    20  of goroutines (passed from Eventually or Expect), hopefully ending up with an
    21  empty list of leaked goroutines. If there are still goroutines left after
    22  filtering, then HaveLeaked() will succeed ... which usually is actually
    23  considered to be failure. So, this can be rather declared to be "suckcess"
    24  because no one wants leaked goroutines.
    25  
    26  A typical pattern to detect goroutines leaked in individual tests is as follows:
    27  
    28  	var ignoreGood []Goroutine
    29  
    30  	BeforeEach(func() {
    31  	    ignoreGood = Goroutines()
    32  	})
    33  
    34  	AfterEach(func() {
    35  	    // Note: it's "Goroutines", but not "Goroutines()", when using with Eventually!
    36  	    Eventually(Goroutines).ShouldNot(HaveLeaked(ignoreGood))
    37  	})
    38  
    39  Using Eventually instead of Expect ensures that there is some time given for
    40  temporary goroutines to finally wind down. Gomega's default values apply: the 1s
    41  timeout and 10ms polling interval.
    42  
    43  Please note that the form
    44  
    45  	HaveLeaked(ignoreGood)
    46  
    47  is the same as the slightly longer, but also more expressive variant:
    48  
    49  	HaveLeaked(IgnoringGoroutines(ignoreGood))
    50  
    51  # Leak-Related Matchers
    52  
    53  Depending on your tests and the dependencies used, you might need to identify
    54  additional goroutines as not being leaks. The gleak packages comes with the
    55  following predefined goroutine "filter" matchers that can be specified as
    56  arguments to HaveLeaked(...):
    57  
    58  	IgnoringTopFunction("foo.bar")                // exactly "foo.bar"
    59  	IgnoringTopFunction("foo.bar...")             // top function name with prefix "foo.bar." (note the trailing dot!)
    60  	IgnoringTopFunction("foo.bar [chan receive]") // exactly "foo.bar" with state starting with "chan receive"
    61  	IgnoringGoroutines(expectedGoroutines)        // ignore specified goroutines with these IDs
    62  	IgnoringInBacktrace("foo.bar.baz")            // "foo.bar.baz" within the backtrace
    63  	IgnoringCreator("foo.bar")                    // exact creator function name "foo.bar"
    64  	IgnoringCreator("foo.bar...")                 // creator function name with prefix "foo.bar."
    65  
    66  In addition, you can use any other GomegaMatcher, as long as it can work on a
    67  (single) Goroutine. For instance, Gomega's HaveField and WithTransform
    68  matchers are good foundations for writing project-specific gleak matchers.
    69  
    70  # Leaked Goroutine Dump
    71  
    72  By default, when gleak's HaveLeaked matcher finds one or more leaked
    73  goroutines, it dumps the goroutine backtraces in a condensed format that uses
    74  only a single line per call instead of two lines. Moreover, the backtraces
    75  abbreviate the source file location in the form of package/source.go:lineno:
    76  
    77  	goroutine 42 [flabbergasted]
    78  	    main.foo.func1() at foo/test.go:6
    79  	    created by main.foo at foo/test.go:5
    80  
    81  By setting gleak.ReportFilenameWithPath=true the leaky goroutine backtraces
    82  will show full path names for each source file:
    83  
    84  	goroutine 42 [flabbergasted]
    85  	    main.foo.func1() at /home/go/foo/test.go:6
    86  	    created by main.foo at home/go/foo/test.go:5
    87  
    88  # Acknowledgement
    89  
    90  gleak has been heavily inspired by the Goroutine leak detector
    91  github.com/uber-go/goleak. That's definitely a fine piece of work!
    92  
    93  But then why another goroutine leak package? After a deep analysis of Uber's
    94  goleak we decided against crunching goleak somehow half-assed into the Gomega
    95  TDD matcher ecosystem. In particular, reusing and wrapping of the existing Uber
    96  implementation would have become very awkward: goleak.Find combines all the
    97  different elements of getting actual goroutines information, filtering them,
    98  arriving at a leak conclusion, and even retrying multiple times all in just one
    99  single exported function. Unfortunately, goleak makes gathering information
   100  about all goroutines an internal matter, so we cannot reuse such functionality
   101  elsewhere.
   102  
   103  Users of the Gomega ecosystem are already experienced in arriving at conclusions
   104  and retrying temporarily failing expectations: Gomega does it in form of
   105  Eventually().ShouldNot(), and (without the trying aspect) with Expect().NotTo().
   106  So what is missing is only a goroutine leak detector in form of the HaveLeaked
   107  matcher, as well as the ability to specify goroutine filters in order to sort
   108  out the non-leaking (and therefore expected) goroutines, using a few filter
   109  criteria. That is, a few new goroutine-related matchers. In this architecture,
   110  even existing Gomega matchers can optionally be (re)used as the need arises.
   111  
   112  # References
   113  
   114  https://github.com/onsi/gomega and https://github.com/onsi/ginkgo.
   115  */
   116  package gleak
   117  

View as plain text