mirror of
https://github.com/golang/go
synced 2024-11-23 14:40:02 -07:00
context: fix a flaky timeout in TestLayersTimeout
In CL 223019, I reduced the short timeout in the testLayers helper to be even shorter than it was. That exposed a racy (time-dependent) select later in the function, which failed in one of the slower builders (android-386-emu). Also streamline the test to make it easier to test with a very high -count flag: - Run tests that sleep for shortDuration in parallel to reduce latency. - Use shorter durations in examples to reduce test running time. - Avoid mutating global state (in package math/rand) in testLayers. After this change (but not before it), 'go test -run=TestLayersTimeout -count=100000 context' passes on my workstation. Fixes #38161 Change-Id: Iaf4abe7ac308b2100d8828267cda9f4f8ae4be82 Reviewed-on: https://go-review.googlesource.com/c/go/+/226457 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
5db079d2e5
commit
5d2ddcd3f5
@ -27,6 +27,7 @@ type testingT interface {
|
|||||||
Log(args ...interface{})
|
Log(args ...interface{})
|
||||||
Logf(format string, args ...interface{})
|
Logf(format string, args ...interface{})
|
||||||
Name() string
|
Name() string
|
||||||
|
Parallel()
|
||||||
Skip(args ...interface{})
|
Skip(args ...interface{})
|
||||||
SkipNow()
|
SkipNow()
|
||||||
Skipf(format string, args ...interface{})
|
Skipf(format string, args ...interface{})
|
||||||
@ -284,6 +285,8 @@ func testDeadline(c Context, name string, t testingT) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func XTestDeadline(t testingT) {
|
func XTestDeadline(t testingT) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
c, _ := WithDeadline(Background(), time.Now().Add(shortDuration))
|
c, _ := WithDeadline(Background(), time.Now().Add(shortDuration))
|
||||||
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
|
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
|
||||||
t.Errorf("c.String() = %q want prefix %q", got, prefix)
|
t.Errorf("c.String() = %q want prefix %q", got, prefix)
|
||||||
@ -307,6 +310,8 @@ func XTestDeadline(t testingT) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func XTestTimeout(t testingT) {
|
func XTestTimeout(t testingT) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
c, _ := WithTimeout(Background(), shortDuration)
|
c, _ := WithTimeout(Background(), shortDuration)
|
||||||
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
|
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
|
||||||
t.Errorf("c.String() = %q want prefix %q", got, prefix)
|
t.Errorf("c.String() = %q want prefix %q", got, prefix)
|
||||||
@ -417,9 +422,9 @@ func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(
|
|||||||
gccgoLimit: 3,
|
gccgoLimit: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "WithTimeout(bg, 15*time.Millisecond)",
|
desc: "WithTimeout(bg, 1*time.Nanosecond)",
|
||||||
f: func() {
|
f: func() {
|
||||||
c, _ := WithTimeout(bg, 15*time.Millisecond)
|
c, _ := WithTimeout(bg, 1*time.Nanosecond)
|
||||||
<-c.Done()
|
<-c.Done()
|
||||||
},
|
},
|
||||||
limit: 12,
|
limit: 12,
|
||||||
@ -545,7 +550,9 @@ func XTestLayersTimeout(t testingT) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testLayers(t testingT, seed int64, testTimeout bool) {
|
func testLayers(t testingT, seed int64, testTimeout bool) {
|
||||||
rand.Seed(seed)
|
t.Parallel()
|
||||||
|
|
||||||
|
r := rand.New(rand.NewSource(seed))
|
||||||
errorf := func(format string, a ...interface{}) {
|
errorf := func(format string, a ...interface{}) {
|
||||||
t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
|
t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
|
||||||
}
|
}
|
||||||
@ -560,7 +567,7 @@ func testLayers(t testingT, seed int64, testTimeout bool) {
|
|||||||
ctx = Background()
|
ctx = Background()
|
||||||
)
|
)
|
||||||
for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
|
for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
|
||||||
switch rand.Intn(3) {
|
switch r.Intn(3) {
|
||||||
case 0:
|
case 0:
|
||||||
v := new(value)
|
v := new(value)
|
||||||
ctx = WithValue(ctx, v, v)
|
ctx = WithValue(ctx, v, v)
|
||||||
@ -587,10 +594,12 @@ func testLayers(t testingT, seed int64, testTimeout bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
select {
|
if !testTimeout {
|
||||||
case <-ctx.Done():
|
select {
|
||||||
errorf("ctx should not be canceled yet")
|
case <-ctx.Done():
|
||||||
default:
|
errorf("ctx should not be canceled yet")
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
|
if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
|
||||||
t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
|
t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
|
||||||
@ -608,7 +617,7 @@ func testLayers(t testingT, seed int64, testTimeout bool) {
|
|||||||
}
|
}
|
||||||
checkValues("after timeout")
|
checkValues("after timeout")
|
||||||
} else {
|
} else {
|
||||||
cancel := cancels[rand.Intn(len(cancels))]
|
cancel := cancels[r.Intn(len(cancels))]
|
||||||
cancel()
|
cancel()
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const shortDuration = 1 * time.Millisecond // a reasonable duration to block in an example
|
||||||
|
|
||||||
// This example demonstrates the use of a cancelable context to prevent a
|
// This example demonstrates the use of a cancelable context to prevent a
|
||||||
// goroutine leak. By the end of the example function, the goroutine started
|
// goroutine leak. By the end of the example function, the goroutine started
|
||||||
// by gen will return without leaking.
|
// by gen will return without leaking.
|
||||||
@ -55,7 +57,7 @@ func ExampleWithCancel() {
|
|||||||
// This example passes a context with an arbitrary deadline to tell a blocking
|
// This example passes a context with an arbitrary deadline to tell a blocking
|
||||||
// function that it should abandon its work as soon as it gets to it.
|
// function that it should abandon its work as soon as it gets to it.
|
||||||
func ExampleWithDeadline() {
|
func ExampleWithDeadline() {
|
||||||
d := time.Now().Add(50 * time.Millisecond)
|
d := time.Now().Add(shortDuration)
|
||||||
ctx, cancel := context.WithDeadline(context.Background(), d)
|
ctx, cancel := context.WithDeadline(context.Background(), d)
|
||||||
|
|
||||||
// Even though ctx will be expired, it is good practice to call its
|
// Even though ctx will be expired, it is good practice to call its
|
||||||
@ -79,7 +81,7 @@ func ExampleWithDeadline() {
|
|||||||
func ExampleWithTimeout() {
|
func ExampleWithTimeout() {
|
||||||
// Pass a context with a timeout to tell a blocking function that it
|
// Pass a context with a timeout to tell a blocking function that it
|
||||||
// should abandon its work after the timeout elapses.
|
// should abandon its work after the timeout elapses.
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
Loading…
Reference in New Issue
Block a user