github.1git.de/docker/cli@v26.1.3+incompatible/internal/test/cmd.go (about) 1 package test 2 3 import ( 4 "context" 5 "os" 6 "syscall" 7 "testing" 8 "time" 9 10 "github.com/docker/cli/cli/command" 11 "github.com/docker/cli/cli/streams" 12 "github.com/spf13/cobra" 13 "gotest.tools/v3/assert" 14 ) 15 16 func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli *FakeCli) { 17 t.Helper() 18 19 errChan := make(chan error) 20 defer close(errChan) 21 22 // wrap the out stream to detect when the prompt is ready 23 writerHookChan := make(chan struct{}) 24 defer close(writerHookChan) 25 26 outStream := streams.NewOut(NewWriterWithHook(cli.OutBuffer(), func(p []byte) { 27 writerHookChan <- struct{}{} 28 })) 29 cli.SetOut(outStream) 30 31 r, _, err := os.Pipe() 32 assert.NilError(t, err) 33 cli.SetIn(streams.NewIn(r)) 34 35 go func() { 36 errChan <- cmd.ExecuteContext(ctx) 37 }() 38 39 writeCtx, writeCancel := context.WithTimeout(ctx, 100*time.Millisecond) 40 defer writeCancel() 41 42 // wait for the prompt to be ready 43 select { 44 case <-writeCtx.Done(): 45 t.Fatalf("command %s did not write prompt to stdout", cmd.Name()) 46 case <-writerHookChan: 47 // drain the channel for future buffer writes 48 go func() { 49 for { 50 select { 51 case <-ctx.Done(): 52 return 53 case <-writerHookChan: 54 } 55 } 56 }() 57 } 58 59 assert.Check(t, cli.OutBuffer().Len() > 0) 60 61 // a small delay to ensure the plugin is prompting 62 time.Sleep(100 * time.Microsecond) 63 64 errCtx, errCancel := context.WithTimeout(ctx, 100*time.Millisecond) 65 defer errCancel() 66 67 // sigint and sigterm are caught by the prompt 68 // this allows us to gracefully exit the prompt with a 0 exit code 69 syscall.Kill(syscall.Getpid(), syscall.SIGINT) 70 71 select { 72 case <-errCtx.Done(): 73 t.Logf("command stdout:\n%s\n", cli.OutBuffer().String()) 74 t.Logf("command stderr:\n%s\n", cli.ErrBuffer().String()) 75 t.Fatalf("command %s did not return after SIGINT", cmd.Name()) 76 case err := <-errChan: 77 assert.ErrorIs(t, err, command.ErrPromptTerminated) 78 } 79 }