Skip to content

Commit e8a5353

Browse files
committed
runtime: fail TestGoroutineLeakProfile on data race
Some of the programs in testdata/testgoroutineleakprofile have data races because they were taken from a corpus that showcases general Go concurrency bugs, not just leaked goroutines. This causes some flakiness as tests might fail due to, for example, a concurrent map access, even outside of race mode. Let's just call data races a failure and fix them in the examples. As far as I can tell, there are only two that show up consistently. Fixes golang#75732. Change-Id: I160b3a1cdce4c2de3f2320b68b4083292e02b557 Reviewed-on: https://go-review.googlesource.com/c/go/+/710756 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> Auto-Submit: Michael Knyszek <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent e3be2d1 commit e8a5353

File tree

4 files changed

+31
-20
lines changed

4 files changed

+31
-20
lines changed

src/runtime/goroutineleakprofile_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ func TestGoroutineLeakProfile(t *testing.T) {
487487
testCases = append(testCases, patternTestCases...)
488488

489489
// Test cases must not panic or cause fatal exceptions.
490-
failStates := regexp.MustCompile(`fatal|panic`)
490+
failStates := regexp.MustCompile(`fatal|panic|DATA RACE`)
491491

492492
testApp := func(exepath string, testCases []testCase) {
493493

@@ -520,9 +520,9 @@ func TestGoroutineLeakProfile(t *testing.T) {
520520
t.Errorf("Test %s produced no output. Is the goroutine leak profile collected?", tcase.name)
521521
}
522522

523-
// Zero tolerance policy for fatal exceptions or panics.
523+
// Zero tolerance policy for fatal exceptions, panics, or data races.
524524
if failStates.MatchString(runOutput) {
525-
t.Errorf("unexpected fatal exception or panic!\noutput:\n%s\n\n", runOutput)
525+
t.Errorf("unexpected fatal exception or panic\noutput:\n%s\n\n", runOutput)
526526
}
527527

528528
output += runOutput + "\n\n"
@@ -540,7 +540,7 @@ func TestGoroutineLeakProfile(t *testing.T) {
540540
unexpectedLeaks := make([]string, 0, len(foundLeaks))
541541

542542
// Parse every leak and check if it is expected (maybe as a flaky leak).
543-
LEAKS:
543+
leaks:
544544
for _, leak := range foundLeaks {
545545
// Check if the leak is expected.
546546
// If it is, check whether it has been encountered before.
@@ -569,7 +569,7 @@ func TestGoroutineLeakProfile(t *testing.T) {
569569
for flakyLeak := range tcase.flakyLeaks {
570570
if flakyLeak.MatchString(leak) {
571571
// The leak is flaky. Carry on to the next line.
572-
continue LEAKS
572+
continue leaks
573573
}
574574
}
575575

src/runtime/testdata/testgoroutineleakprofile/goker/README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,22 @@ Jingling Xue ([email protected]):
2424

2525
White paper: https://lujie.ac.cn/files/papers/GoBench.pdf
2626

27-
The examples have been modified in order to run the goroutine leak
28-
profiler. Buggy snippets are moved from within a unit test to separate
29-
applications. Each is then independently executed, possibly as multiple
30-
copies within the same application in order to exercise more interleavings.
31-
Concurrently, the main program sets up a waiting period (typically 1ms), followed
32-
by a goroutine leak profile request. Other modifications may involve injecting calls
33-
to `runtime.Gosched()`, to more reliably exercise buggy interleavings, or reductions
34-
in waiting periods when calling `time.Sleep`, in order to reduce overall testing time.
35-
36-
The resulting goroutine leak profile is analyzed to ensure that no unexpected leaks occurred,
37-
and that the expected leaks did occur. If the leak is flaky, the only purpose of the expected
38-
leak list is to protect against unexpected leaks.
27+
The examples have been modified in order to run the goroutine leak profiler.
28+
Buggy snippets are moved from within a unit test to separate applications.
29+
Each is then independently executed, possibly as multiple copies within the
30+
same application in order to exercise more interleavings. Concurrently, the
31+
main program sets up a waiting period (typically 1ms), followed by a goroutine
32+
leak profile request. Other modifications may involve injecting calls to
33+
`runtime.Gosched()`, to more reliably exercise buggy interleavings, or reductions
34+
in waiting periods when calling `time.Sleep`, in order to reduce overall testing
35+
time.
36+
37+
The resulting goroutine leak profile is analyzed to ensure that no unexpecte
38+
leaks occurred, and that the expected leaks did occur. If the leak is flaky, the
39+
only purpose of the expected leak list is to protect against unexpected leaks.
40+
41+
The examples have also been modified to remove data races, since those create flaky
42+
test failures, when really all we care about are leaked goroutines.
3943

4044
The entries below document each of the corresponding leaks.
4145

@@ -1844,4 +1848,4 @@ c.inbox <- <================> [<-c.inbox]
18441848
. close(c.closed)
18451849
. <-c.dispatcherLoopStopped
18461850
---------------------G1,G2 leak-------------------------------
1847-
```
1851+
```

src/runtime/testdata/testgoroutineleakprofile/goker/cockroach1055.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ func (s *Stopper_cockroach1055) SetStopped() {
4444
func (s *Stopper_cockroach1055) Quiesce() {
4545
s.mu.Lock()
4646
defer s.mu.Unlock()
47-
s.draining = 1
47+
atomic.StoreInt32(&s.draining, 1)
4848
s.drain.Wait()
49-
s.draining = 0
49+
atomic.StoreInt32(&s.draining, 0)
5050
}
5151

5252
func (s *Stopper_cockroach1055) Stop() {

src/runtime/testdata/testgoroutineleakprofile/goker/moby27782.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ func (container *Container_moby27782) Reset() {
208208
}
209209

210210
type JSONFileLogger_moby27782 struct {
211+
mu sync.Mutex
211212
readers map[*LogWatcher_moby27782]struct{}
212213
}
213214

@@ -218,11 +219,17 @@ func (l *JSONFileLogger_moby27782) ReadLogs() *LogWatcher_moby27782 {
218219
}
219220

220221
func (l *JSONFileLogger_moby27782) readLogs(logWatcher *LogWatcher_moby27782) {
222+
l.mu.Lock()
223+
defer l.mu.Unlock()
224+
221225
l.readers[logWatcher] = struct{}{}
222226
followLogs_moby27782(logWatcher)
223227
}
224228

225229
func (l *JSONFileLogger_moby27782) Close() {
230+
l.mu.Lock()
231+
defer l.mu.Unlock()
232+
226233
for r := range l.readers {
227234
r.Close()
228235
delete(l.readers, r)

0 commit comments

Comments
 (0)