fix(clitest): use separate channel when waiting for exit (#7231)

This commit is contained in:
Colin Adler
2023-04-20 14:37:44 -05:00
committed by GitHub
parent ad0070354f
commit 34c6ad671c

View File

@ -127,8 +127,8 @@ func extractTar(t *testing.T, data []byte, directory string) {
} }
} }
// Start runs the command in a goroutine and cleans it up when // Start runs the command in a goroutine and cleans it up when the test
// the test completed. // completed.
func Start(t *testing.T, inv *clibase.Invocation) { func Start(t *testing.T, inv *clibase.Invocation) {
t.Helper() t.Helper()
@ -170,7 +170,7 @@ func (w *ErrorWaiter) Wait() error {
var ok bool var ok bool
w.cachedError, ok = <-w.c w.cachedError, ok = <-w.c
if !ok { if !ok {
panic("unexpoected channel close") panic("unexpected channel close")
} }
}) })
return w.cachedError return w.cachedError
@ -196,18 +196,18 @@ func (w *ErrorWaiter) RequireAs(want interface{}) {
require.ErrorAs(w.t, w.Wait(), want) require.ErrorAs(w.t, w.Wait(), want)
} }
// StartWithWaiter runs the command in a goroutine but returns the error // StartWithWaiter runs the command in a goroutine but returns the error instead
// instead of asserting it. This is useful for testing error cases. // of asserting it. This is useful for testing error cases.
func StartWithWaiter(t *testing.T, inv *clibase.Invocation) *ErrorWaiter { func StartWithWaiter(t *testing.T, inv *clibase.Invocation) *ErrorWaiter {
t.Helper() t.Helper()
errCh := make(chan error, 1)
var cleaningUp atomic.Bool
var ( var (
ctx = inv.Context() ctx = inv.Context()
cancel func() cancel func()
cleaningUp atomic.Bool
errCh = make(chan error, 1)
doneCh = make(chan struct{})
) )
if _, ok := ctx.Deadline(); !ok { if _, ok := ctx.Deadline(); !ok {
ctx, cancel = context.WithDeadline(ctx, time.Now().Add(testutil.WaitMedium)) ctx, cancel = context.WithDeadline(ctx, time.Now().Add(testutil.WaitMedium))
@ -218,12 +218,13 @@ func StartWithWaiter(t *testing.T, inv *clibase.Invocation) *ErrorWaiter {
inv = inv.WithContext(ctx) inv = inv.WithContext(ctx)
go func() { go func() {
defer close(doneCh)
defer close(errCh) defer close(errCh)
err := inv.Run() err := inv.Run()
if cleaningUp.Load() && errors.Is(err, context.DeadlineExceeded) { if cleaningUp.Load() && errors.Is(err, context.DeadlineExceeded) {
// If we're cleaning up, this error is likely related to the // If we're cleaning up, this error is likely related to the CLI
// CLI teardown process. E.g., the server could be slow to shut // teardown process. E.g., the server could be slow to shut down
// down Postgres. // Postgres.
t.Logf("command %q timed out during test cleanup", inv.Command.FullName()) t.Logf("command %q timed out during test cleanup", inv.Command.FullName())
} }
// Whether or not this fails the test is left to the caller. // Whether or not this fails the test is left to the caller.
@ -235,7 +236,7 @@ func StartWithWaiter(t *testing.T, inv *clibase.Invocation) *ErrorWaiter {
t.Cleanup(func() { t.Cleanup(func() {
cancel() cancel()
cleaningUp.Store(true) cleaningUp.Store(true)
<-errCh <-doneCh
}) })
return &ErrorWaiter{c: errCh, t: t} return &ErrorWaiter{c: errCh, t: t}
} }