Skip to content

Commit

Permalink
TestAppRunTimeout: Fix OnStop_timeout flakiness
Browse files Browse the repository at this point in the history
The OnStop_timeout test was flaky
because of the very small StartTimeout.

We would sometimes hit a condition where:
App.Run calls App.Start with a timeout of 1 millisecond.
This takes just long enough that App.Start gives up.
As a result, App.Run does not call App.Stop,
which causes the test to fail
because we don't see the Stop event.

Resolve the flakiness with the use of a mock clock.
Now, time doesn't advance while the start hook is running,
so we can be certain that the really long OnStop hook is invoked
and has a chance to time out.
  • Loading branch information
abhinav committed Nov 18, 2021
1 parent 68f69ea commit 61f65ba
Showing 1 changed file with 10 additions and 13 deletions.
23 changes: 10 additions & 13 deletions app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -753,20 +753,16 @@ func TestTimeoutOptions(t *testing.T) {
func TestAppRunTimeout(t *testing.T) {
t.Parallel()

// This context is only valid as long as this test is running.
// It lets us have goroutines that block forever
// (as far as the test is concerned) without leaking them.
testCtx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
mockClock := clock.NewMock()

// Fails with an error immediately.
failure := func(context.Context) error {
return errors.New("great sadness")
}

// Blocks forever--or at least until this test finishes running.
blockForever := func(context.Context) error {
<-testCtx.Done()
// Takes much longer than the application timeout.
takeVeryLong := func(context.Context) error {
mockClock.Add(time.Hour)
return errors.New("user should not see this")
}

Expand All @@ -782,7 +778,7 @@ func TestAppRunTimeout(t *testing.T) {
// Timeout starting an application.
desc: "OnStart timeout",
hooks: []Hook{
{OnStart: blockForever},
{OnStart: takeVeryLong},
},
wantEventType: &fxevent.Started{},
},
Expand All @@ -792,7 +788,7 @@ func TestAppRunTimeout(t *testing.T) {
hooks: []Hook{
// The hooks are separate because
// OnStop will not be run if that hook failed.
{OnStop: blockForever},
{OnStop: takeVeryLong},
{OnStart: failure},
},
wantEventType: &fxevent.Started{},
Expand All @@ -801,7 +797,7 @@ func TestAppRunTimeout(t *testing.T) {
// Timeout during a stop.
desc: "OnStop timeout",
hooks: []Hook{
{OnStop: blockForever},
{OnStop: takeVeryLong},
},
wantEventType: &fxevent.Stopped{},
},
Expand Down Expand Up @@ -838,9 +834,10 @@ func TestAppRunTimeout(t *testing.T) {
}

app, spy := NewSpied(
StartTimeout(time.Millisecond),
StopTimeout(time.Millisecond),
StartTimeout(time.Second),
StopTimeout(time.Second),
WithExit(exit),
WithClock(mockClock),
Invoke(func(lc Lifecycle) {
for _, h := range tt.hooks {
lc.Append(h)
Expand Down

0 comments on commit 61f65ba

Please sign in to comment.