-
Notifications
You must be signed in to change notification settings - Fork 280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use mock clock, unflake tests #813
Conversation
Fixing data race in benbjohnson/clock#42. |
Codecov Report
@@ Coverage Diff @@
## master #813 +/- ##
==========================================
- Coverage 99.25% 99.04% -0.21%
==========================================
Files 24 25 +1
Lines 941 946 +5
==========================================
+ Hits 934 937 +3
- Misses 6 7 +1
- Partials 1 2 +1
Continue to review full report at Codecov.
|
go.mod
Outdated
github.com/stretchr/testify v1.7.0 | ||
go.uber.org/dig v1.12.0 | ||
go.uber.org/goleak v1.1.11 | ||
go.uber.org/multierr v1.5.0 | ||
go.uber.org/zap v1.16.0 | ||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b | ||
) | ||
|
||
replace github.com/benbjohnson/clock => github.com/abhinav/clock v1.3.1-0.20211118204451-38de6f8a55b9 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably will not land this replace
directive.
I'd like to wait a few days for the change to be merged upstream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the code changes looks good to me, and yeah, waiting on merging this until the upstream change gets merged is probably better than pinning the fork :)
b49c226
to
5450aac
Compare
5450aac
to
cf899f7
Compare
This PR is now WIP while I'm digging further into this. |
bdca9bb
to
62d2b29
Compare
Add an internal fxclock package that provides a minimal Clock interface. We will use this to abstract away Fx's use of time operations to help address test flakiness issues.
e54a0b3
to
00653cb
Compare
Add a WithClock option to fx.App to inject an fxclock and use this clock for all time operations in App and Lifecycle. This option is only available from tests inside the same directory. We're intentionally not exposing this as part of our public API for now.
Use a mock clock for the tests in TestAppStart and TestAppStop that rely on blocking or sleeping. These tests were previously using a small timeout and blocking on `ctx.Done` indefinitely, or using `time.Sleep` directly. With a mock clock, we can use larger, more real timeouts and simply advance time to an even larger value. Besides making the tests more deterministic, this also makes them faster. Before: ``` $ go test -run TestAppStart -count 1 PASS ok go.uber.org/fx 1.066s $ go test -run TestAppStart -count 1 PASS ok go.uber.org/fx 1.060s ``` After: ``` $ go test -run TestAppStart -count 1 PASS ok go.uber.org/fx 0.083s $ go test -run TestAppStart -count 1 PASS ok go.uber.org/fx 0.064s ``` (TestAppStop was not affected similarly because it used a very small timeout to begin with.)
29082d1
to
85a3278
Compare
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. Note that the subtests for this test share hooks, but they can't share mock clocks (`clock.Add` is not thread-safe) so we instead use "hook builders" that build hooks given the mock clock.
85a3278
to
cf09130
Compare
This PR resolves flakiness of some tests in Fx
by abstracting our use of time operations behind a Clock interface
and using a mock clock for the relevant tests.
This adds an internal/fxclock package that defines the Clock interface.
This interface is a compliant subset of "benbjohnson/clock".Clock.
This intentionally does not use benbjohnson/clock directly outside of tests
to keep it a test-only dependency.
The new internal-only
WithClock
optionaccepts and plumbs an implementation of
fxclock.Clock
.Note that this option is declared in app_internal_test.go.
It's not part of the public API,
but it's accessible to external tests in the top-level Fx directory.
Finally, this switches to using the Clock for time operations where relevant,
and updates tests that rely on sleep/time-based blocking to use a mock clock.
Now,
time.Now
is only present in fxclock.System.time.Since
is only present in fxclock.System.time.Sleep
is only present in fxclock.System.context.WithTimeout
is present in fxclock.System,fxtest.App.Require{Start,Stop}
, andexample_test.go
.The latter two because fxclock.Clock is not part of our public API.
Resolves #799
Ref: GO-1001