Skip to content

Commit b269400

Browse files
committed
Switch to using goleaks to check for leaks
This switches to using the goleaks package to check for leaks, which should give us a more complete picture of the particular goroutine that's leaking, and should avoid issues where we leak a goroutine, but also stop an old one. This also force-closes keep-alive connections in the leak tests, since those look like leaks, but will actually time out after 30s (outside the timescope of the test).
1 parent d045fcf commit b269400

File tree

6 files changed

+45
-23
lines changed

6 files changed

+45
-23
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require (
1515
github.com/onsi/gomega v1.10.1
1616
github.com/prometheus/client_golang v1.7.1
1717
github.com/prometheus/client_model v0.2.0
18+
go.uber.org/goleak v1.1.10
1819
go.uber.org/zap v1.15.0
1920
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
2021
gomodules.xyz/jsonpatch/v2 v2.1.0

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
255255
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
256256
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
257257
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
258+
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
258259
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
259260
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
260261
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
@@ -374,6 +375,8 @@ go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
374375
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
375376
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
376377
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
378+
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
379+
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
377380
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
378381
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
379382
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
@@ -521,6 +524,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
521524
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
522525
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
523526
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
527+
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
524528
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
525529
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
526530
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=

pkg/controller/controller_suite_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package controller_test
1818

1919
import (
20+
"net/http"
2021
"testing"
2122

2223
. "github.com/onsi/ginkgo"
@@ -45,6 +46,9 @@ var testenv *envtest.Environment
4546
var cfg *rest.Config
4647
var clientset *kubernetes.Clientset
4748

49+
// clientTransport is used to force-close keep-alives in tests that check for leaks
50+
var clientTransport *http.Transport
51+
4852
var _ = BeforeSuite(func(done Done) {
4953
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
5054

@@ -64,6 +68,9 @@ var _ = BeforeSuite(func(done Done) {
6468
cfg, err = testenv.Start()
6569
Expect(err).NotTo(HaveOccurred())
6670

71+
clientTransport = &http.Transport{}
72+
cfg.Transport = clientTransport
73+
6774
clientset, err = kubernetes.NewForConfig(cfg)
6875
Expect(err).NotTo(HaveOccurred())
6976

pkg/controller/controller_test.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@ package controller_test
1919
import (
2020
"context"
2121
"fmt"
22-
"os"
23-
rt "runtime"
24-
"runtime/pprof"
2522

2623
. "github.com/onsi/ginkgo"
2724
. "github.com/onsi/gomega"
25+
"go.uber.org/goleak"
2826

2927
"sigs.k8s.io/controller-runtime/pkg/client"
3028
"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -97,35 +95,38 @@ var _ = Describe("controller.Controller", func() {
9795
})
9896

9997
It("should not leak goroutines when stopped", func() {
100-
// NB(directxman12): this test was flaky before on CI, but my guess
101-
// is that the flakiness was caused by an expect on the count.
102-
// Eventually should fix it, but if not, consider disabling again.
98+
currentGRs := goleak.IgnoreCurrent()
99+
103100
m, err := manager.New(cfg, manager.Options{})
104101
Expect(err).NotTo(HaveOccurred())
105102

106103
_, err = controller.New("new-controller", m, controller.Options{Reconciler: rec})
107104
Expect(err).NotTo(HaveOccurred())
108105

109-
startGoroutines := rt.NumGoroutine()
110106
s := make(chan struct{})
111107
close(s)
112108

113-
Expect(m.Start(s)).NotTo(HaveOccurred())
114-
Eventually(rt.NumGoroutine /* pass the function, don't call it */).Should(Equal(startGoroutines))
109+
Expect(m.Start(s)).To(Succeed())
110+
111+
// force-close keep-alive connections. These'll time anyway (after
112+
// like 30s or so) but force it to speed up the tests.
113+
clientTransport.CloseIdleConnections()
114+
Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
115115
})
116116

117117
It("should not create goroutines if never started", func() {
118-
startGoroutines := rt.NumGoroutine()
119-
Expect(pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)).To(Succeed())
118+
currentGRs := goleak.IgnoreCurrent()
120119

121120
m, err := manager.New(cfg, manager.Options{})
122121
Expect(err).NotTo(HaveOccurred())
123122

124123
_, err = controller.New("new-controller", m, controller.Options{Reconciler: rec})
125124
Expect(err).NotTo(HaveOccurred())
126125

127-
Expect(pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)).To(Succeed())
128-
Eventually(rt.NumGoroutine /* pass func, don't call */).Should(Equal(startGoroutines))
126+
// force-close keep-alive connections. These'll time anyway (after
127+
// like 30s or so) but force it to speed up the tests.
128+
clientTransport.CloseIdleConnections()
129+
Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
129130
})
130131
})
131132
})

pkg/manager/manager_suite_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package manager
1818

1919
import (
20+
"net/http"
2021
"testing"
2122

2223
. "github.com/onsi/ginkgo"
@@ -40,6 +41,9 @@ var testenv *envtest.Environment
4041
var cfg *rest.Config
4142
var clientset *kubernetes.Clientset
4243

44+
// clientTransport is used to force-close keep-alives in tests that check for leaks
45+
var clientTransport *http.Transport
46+
4347
var _ = BeforeSuite(func(done Done) {
4448
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
4549

@@ -49,6 +53,9 @@ var _ = BeforeSuite(func(done Done) {
4953
cfg, err = testenv.Start()
5054
Expect(err).NotTo(HaveOccurred())
5155

56+
clientTransport = &http.Transport{}
57+
cfg.Transport = clientTransport
58+
5259
clientset, err = kubernetes.NewForConfig(cfg)
5360
Expect(err).NotTo(HaveOccurred())
5461

pkg/manager/manager_test.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"net"
2525
"net/http"
2626
"path"
27-
rt "runtime"
2827
"strings"
2928
"sync"
3029
"time"
@@ -33,6 +32,7 @@ import (
3332
. "github.com/onsi/ginkgo"
3433
. "github.com/onsi/gomega"
3534
"github.com/prometheus/client_golang/prometheus"
35+
"go.uber.org/goleak"
3636
corev1 "k8s.io/api/core/v1"
3737
"k8s.io/apimachinery/pkg/api/meta"
3838
"k8s.io/apimachinery/pkg/runtime"
@@ -1204,25 +1204,24 @@ var _ = Describe("manger.Manager", func() {
12041204
})
12051205
})
12061206

1207-
// This test has been marked as pending because it has been causing lots of flakes in CI.
1208-
// It should be rewritten at some point later in the future.
12091207
It("should not leak goroutines when stopped", func() {
1210-
// NB(directxman12): this test was flaky before on CI, but my guess
1211-
// is that the flakiness was caused by an expect on the count.
1212-
// Eventually should fix it, but if not, consider disabling again.
1208+
currentGRs := goleak.IgnoreCurrent()
1209+
12131210
m, err := New(cfg, Options{})
12141211
Expect(err).NotTo(HaveOccurred())
1215-
startGoroutines := rt.NumGoroutine()
12161212

12171213
s := make(chan struct{})
12181214
close(s)
12191215
Expect(m.Start(s)).NotTo(HaveOccurred())
12201216

1221-
Eventually(rt.NumGoroutine /* pass the function, don't call it */).Should(Equal(startGoroutines))
1217+
// force-close keep-alive connections. These'll time anyway (after
1218+
// like 30s or so) but force it to speed up the tests.
1219+
clientTransport.CloseIdleConnections()
1220+
Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
12221221
})
12231222

12241223
It("should not leak goroutines if the default event broadcaster is used & events are emitted", func() {
1225-
startGoroutines := rt.NumGoroutine()
1224+
currentGRs := goleak.IgnoreCurrent()
12261225

12271226
m, err := New(cfg, Options{ /* implicit: default setting for EventBroadcaster */ })
12281227
Expect(err).NotTo(HaveOccurred())
@@ -1261,7 +1260,10 @@ var _ = Describe("manger.Manager", func() {
12611260
close(stopCh)
12621261
<-doneCh
12631262

1264-
Eventually(rt.NumGoroutine /* pass the function, don't call it */).Should(Equal(startGoroutines))
1263+
// force-close keep-alive connections. These'll time anyway (after
1264+
// like 30s or so) but force it to speed up the tests.
1265+
clientTransport.CloseIdleConnections()
1266+
Eventually(func() error { return goleak.Find(currentGRs) }).Should(Succeed())
12651267
})
12661268

12671269
It("should provide a function to get the Config", func() {

0 commit comments

Comments
 (0)