-
Notifications
You must be signed in to change notification settings - Fork 214
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
Don't call T.FatalX inside goroutines in tests #2151
Comments
Here's some sample code that does this in a relatively canonical way, for reference: go-spacemesh/cmd/node/app_test.go Lines 108 to 168 in 93216bb
|
Hi |
Hi @Amirhossein2000. That's an interesting idea, and one I hadn't previously considered. My understanding of golang's |
I changed your example and this is going to be like this but we can't separate timeout and fail errors now. // Scan and print the poet output, and catch errors early
l := lg.New(os.Stderr, "[poet]\t", 0)
ctx, cancel := context.WithTimeout(context.Background(), time.minute * 6)
go func(cancelFunc context.Cancel) {
scanner := bufio.NewScanner(io.MultiReader(poetHarness.Stdout, poetHarness.Stderr))
for scanner.Scan() {
line := scanner.Text()
matched, err := regexp.MatchString(`\bERROR\b`, line)
require.NoError(suite.T(), err)
// Fail fast if we encounter a poet error
// Must use a channel since we're running inside a goroutine
if matched {
cancelFunc()
suite.T().Fatalf("got error from poet: %s", line)
}
l.Println(line)
}
}()
rolacle := eligibility.New()
rng := BLS381.DefaultSeed()
gTime, err := time.Parse(time.RFC3339, genesisTime)
if err != nil {
log.Error("cannot parse genesis time %v", err)
}
ld := time.Duration(20) * time.Second
clock := timesync.NewClock(timesync.RealClock{}, ld, gTime, log.NewDefault("clock"))
suite.initMultipleInstances(cfg, rolacle, rng, 5, path, genesisTime, poetHarness.HTTPPoetClient, clock, net)
defer GracefulShutdown(suite.apps)
for _, a := range suite.apps {
a.startServices()
}
ActivateGrpcServer(suite.apps[0])
if err := poetHarness.Start([]string{"127.0.0.1:9092"}); err != nil {
suite.T().Fatalf("failed to start poet server: %v", err)
}
timeout := time.After(6 * time.Minute)
// Run setup first. We need to allow this to timeout, and monitor the failure channel too,
// as this can also loop forever.
doneChan := make(chan struct{})
go func() {
setupTests(suite)
close(doneChan)
}()
loopSetup:
for {
select {
case <-doneChan:
break loopSetup
case <-ctx.Done():
suite.T().Fatal("Test Failed")
}
} |
@Amirhossein2000 thanks for putting together this example, it's helpful. I think it could probably be made to work, but it seems like it's not idiomatic go. It seems like it's using context in a way that it's not intended to be used. Here are the sources I'm referring to: The first of these explains how Context is supposed to be used, and the second contains a wealth of information on how channels can be used to propagate cancel signals. Let me know if you disagree! |
Description
Many of the tests in https://github.com/spacemeshos/go-spacemesh/blob/develop/cmd/node/node_test.go use goroutines to run and interact with a process concurrently. They have require statements inside these goroutines, which is a no-no because when a require statement fails inside a goroutine it does not stop the test, in some cases causing tests to hang indefinitely. Here's one such example:
go-spacemesh/cmd/node/node_test.go
Lines 563 to 576 in a637292
Which is causing this: https://travis-ci.org/github/spacemeshos/go-spacemesh/jobs/730399257
Steps To Reproduce
require.FailNow()
inside one of these goroutinesExpected Behavior
The test should fail completely and cleanly when one of these test statements fails
Environment
Please complete the following information:
Additional Resources
For context see golang/go#15758
How to fix
Unclear. These tests do some messy concurrency. Either the tests need to be rewritten to add a
failChannel
and be smart enough to stop when a test fails (for inspiration see golang/mock#346 (comment)), or else we could just usepanic()
now as a workaround.The text was updated successfully, but these errors were encountered: