mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 19:39:57 +00:00
TUN-8158: Bring back commit e653741885
and fixes infinite loop on linux when the socket is closed
This commit is contained in:
16
vendor/github.com/fortytw2/leaktest/.travis.yml
generated
vendored
Normal file
16
vendor/github.com/fortytw2/leaktest/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.8
|
||||
- 1.9
|
||||
- "1.10"
|
||||
- "1.11"
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v -race -parallel 5 -coverprofile=coverage.txt -covermode=atomic ./
|
||||
- go test github.com/fortytw2/leaktest -run ^TestEmptyLeak$
|
||||
|
||||
before_install:
|
||||
- pip install --user codecov
|
||||
after_success:
|
||||
- codecov
|
27
vendor/github.com/fortytw2/leaktest/LICENSE
generated
vendored
Normal file
27
vendor/github.com/fortytw2/leaktest/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
64
vendor/github.com/fortytw2/leaktest/README.md
generated
vendored
Normal file
64
vendor/github.com/fortytw2/leaktest/README.md
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
## Leaktest [](https://travis-ci.org/fortytw2/leaktest) [](https://codecov.io/gh/fortytw2/leaktest) [](https://sourcegraph.com/github.com/fortytw2/leaktest?badge) [](http://godoc.org/github.com/fortytw2/leaktest)
|
||||
|
||||
Refactored, tested variant of the goroutine leak detector found in both
|
||||
`net/http` tests and the `cockroachdb` source tree.
|
||||
|
||||
Takes a snapshot of running goroutines at the start of a test, and at the end -
|
||||
compares the two and _voila_. Ignores runtime/sys goroutines. Doesn't play nice
|
||||
with `t.Parallel()` right now, but there are plans to do so.
|
||||
|
||||
### Installation
|
||||
|
||||
Go 1.7+
|
||||
|
||||
```
|
||||
go get -u github.com/fortytw2/leaktest
|
||||
```
|
||||
|
||||
Go 1.5/1.6 need to use the tag `v1.0.0`, as newer versions depend on
|
||||
`context.Context`.
|
||||
|
||||
### Example
|
||||
|
||||
These tests fail, because they leak a goroutine
|
||||
|
||||
```go
|
||||
// Default "Check" will poll for 5 seconds to check that all
|
||||
// goroutines are cleaned up
|
||||
func TestPool(t *testing.T) {
|
||||
defer leaktest.Check(t)()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Helper function to timeout after X duration
|
||||
func TestPoolTimeout(t *testing.T) {
|
||||
defer leaktest.CheckTimeout(t, time.Second)()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Use Go 1.7+ context.Context for cancellation
|
||||
func TestPoolContext(t *testing.T) {
|
||||
ctx, _ := context.WithTimeout(context.Background(), time.Second)
|
||||
defer leaktest.CheckContext(ctx, t)()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
```
|
||||
|
||||
## LICENSE
|
||||
|
||||
Same BSD-style as Go, see LICENSE
|
153
vendor/github.com/fortytw2/leaktest/leaktest.go
generated
vendored
Normal file
153
vendor/github.com/fortytw2/leaktest/leaktest.go
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package leaktest provides tools to detect leaked goroutines in tests.
|
||||
// To use it, call "defer leaktest.Check(t)()" at the beginning of each
|
||||
// test that may use goroutines.
|
||||
// copied out of the cockroachdb source tree with slight modifications to be
|
||||
// more re-useable
|
||||
package leaktest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type goroutine struct {
|
||||
id uint64
|
||||
stack string
|
||||
}
|
||||
|
||||
type goroutineByID []*goroutine
|
||||
|
||||
func (g goroutineByID) Len() int { return len(g) }
|
||||
func (g goroutineByID) Less(i, j int) bool { return g[i].id < g[j].id }
|
||||
func (g goroutineByID) Swap(i, j int) { g[i], g[j] = g[j], g[i] }
|
||||
|
||||
func interestingGoroutine(g string) (*goroutine, error) {
|
||||
sl := strings.SplitN(g, "\n", 2)
|
||||
if len(sl) != 2 {
|
||||
return nil, fmt.Errorf("error parsing stack: %q", g)
|
||||
}
|
||||
stack := strings.TrimSpace(sl[1])
|
||||
if strings.HasPrefix(stack, "testing.RunTests") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if stack == "" ||
|
||||
// Ignore HTTP keep alives
|
||||
strings.Contains(stack, ").readLoop(") ||
|
||||
strings.Contains(stack, ").writeLoop(") ||
|
||||
// Below are the stacks ignored by the upstream leaktest code.
|
||||
strings.Contains(stack, "testing.Main(") ||
|
||||
strings.Contains(stack, "testing.(*T).Run(") ||
|
||||
strings.Contains(stack, "runtime.goexit") ||
|
||||
strings.Contains(stack, "created by runtime.gc") ||
|
||||
strings.Contains(stack, "interestingGoroutines") ||
|
||||
strings.Contains(stack, "runtime.MHeap_Scavenger") ||
|
||||
strings.Contains(stack, "signal.signal_recv") ||
|
||||
strings.Contains(stack, "sigterm.handler") ||
|
||||
strings.Contains(stack, "runtime_mcall") ||
|
||||
strings.Contains(stack, "goroutine in C code") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Parse the goroutine's ID from the header line.
|
||||
h := strings.SplitN(sl[0], " ", 3)
|
||||
if len(h) < 3 {
|
||||
return nil, fmt.Errorf("error parsing stack header: %q", sl[0])
|
||||
}
|
||||
id, err := strconv.ParseUint(h[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing goroutine id: %s", err)
|
||||
}
|
||||
|
||||
return &goroutine{id: id, stack: strings.TrimSpace(g)}, nil
|
||||
}
|
||||
|
||||
// interestingGoroutines returns all goroutines we care about for the purpose
|
||||
// of leak checking. It excludes testing or runtime ones.
|
||||
func interestingGoroutines(t ErrorReporter) []*goroutine {
|
||||
buf := make([]byte, 2<<20)
|
||||
buf = buf[:runtime.Stack(buf, true)]
|
||||
var gs []*goroutine
|
||||
for _, g := range strings.Split(string(buf), "\n\n") {
|
||||
gr, err := interestingGoroutine(g)
|
||||
if err != nil {
|
||||
t.Errorf("leaktest: %s", err)
|
||||
continue
|
||||
} else if gr == nil {
|
||||
continue
|
||||
}
|
||||
gs = append(gs, gr)
|
||||
}
|
||||
sort.Sort(goroutineByID(gs))
|
||||
return gs
|
||||
}
|
||||
|
||||
// ErrorReporter is a tiny subset of a testing.TB to make testing not such a
|
||||
// massive pain
|
||||
type ErrorReporter interface {
|
||||
Errorf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// Check snapshots the currently-running goroutines and returns a
|
||||
// function to be run at the end of tests to see whether any
|
||||
// goroutines leaked, waiting up to 5 seconds in error conditions
|
||||
func Check(t ErrorReporter) func() {
|
||||
return CheckTimeout(t, 5*time.Second)
|
||||
}
|
||||
|
||||
// CheckTimeout is the same as Check, but with a configurable timeout
|
||||
func CheckTimeout(t ErrorReporter, dur time.Duration) func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
fn := CheckContext(ctx, t)
|
||||
return func() {
|
||||
timer := time.AfterFunc(dur, cancel)
|
||||
fn()
|
||||
// Remember to clean up the timer and context
|
||||
timer.Stop()
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// CheckContext is the same as Check, but uses a context.Context for
|
||||
// cancellation and timeout control
|
||||
func CheckContext(ctx context.Context, t ErrorReporter) func() {
|
||||
orig := map[uint64]bool{}
|
||||
for _, g := range interestingGoroutines(t) {
|
||||
orig[g.id] = true
|
||||
}
|
||||
return func() {
|
||||
var leaked []string
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Errorf("leaktest: timed out checking goroutines")
|
||||
default:
|
||||
leaked = make([]string, 0)
|
||||
for _, g := range interestingGoroutines(t) {
|
||||
if !orig[g.id] {
|
||||
leaked = append(leaked, g.stack)
|
||||
}
|
||||
}
|
||||
if len(leaked) == 0 {
|
||||
return
|
||||
}
|
||||
// don't spin needlessly
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
for _, g := range leaked {
|
||||
t.Errorf("leaktest: leaked goroutine: %v", g)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user