github.com/rish1988/moby@v25.0.2+incompatible/integration/internal/container/exec.go (about) 1 package container 2 3 import ( 4 "bytes" 5 "context" 6 "testing" 7 8 "github.com/docker/docker/api/types" 9 "github.com/docker/docker/client" 10 ) 11 12 // ExecResult represents a result returned from Exec() 13 type ExecResult struct { 14 ExitCode int 15 outBuffer *bytes.Buffer 16 errBuffer *bytes.Buffer 17 } 18 19 // Stdout returns stdout output of a command run by Exec() 20 func (res ExecResult) Stdout() string { 21 return res.outBuffer.String() 22 } 23 24 // Stderr returns stderr output of a command run by Exec() 25 func (res ExecResult) Stderr() string { 26 return res.errBuffer.String() 27 } 28 29 // Combined returns combined stdout and stderr output of a command run by Exec() 30 func (res ExecResult) Combined() string { 31 return res.outBuffer.String() + res.errBuffer.String() 32 } 33 34 // AssertSuccess fails the test and stops execution if the command exited with a 35 // nonzero status code. 36 func (res ExecResult) AssertSuccess(t testing.TB) { 37 t.Helper() 38 if res.ExitCode != 0 { 39 t.Logf("expected exit code 0, got %d", res.ExitCode) 40 t.Logf("stdout: %s", res.Stdout()) 41 t.Logf("stderr: %s", res.Stderr()) 42 t.FailNow() 43 } 44 } 45 46 // Exec executes a command inside a container, returning the result 47 // containing stdout, stderr, and exit code. Note: 48 // - this is a synchronous operation; 49 // - cmd stdin is closed. 50 func Exec(ctx context.Context, apiClient client.APIClient, id string, cmd []string, ops ...func(*types.ExecConfig)) (ExecResult, error) { 51 // prepare exec 52 execConfig := types.ExecConfig{ 53 AttachStdout: true, 54 AttachStderr: true, 55 Cmd: cmd, 56 } 57 58 for _, op := range ops { 59 op(&execConfig) 60 } 61 62 cresp, err := apiClient.ContainerExecCreate(ctx, id, execConfig) 63 if err != nil { 64 return ExecResult{}, err 65 } 66 execID := cresp.ID 67 68 // run it, with stdout/stderr attached 69 aresp, err := apiClient.ContainerExecAttach(ctx, execID, types.ExecStartCheck{}) 70 if err != nil { 71 return ExecResult{}, err 72 } 73 74 // read the output 75 s, err := demultiplexStreams(ctx, aresp) 76 if err != nil { 77 return ExecResult{}, err 78 } 79 80 // get the exit code 81 iresp, err := apiClient.ContainerExecInspect(ctx, execID) 82 if err != nil { 83 return ExecResult{}, err 84 } 85 86 return ExecResult{ExitCode: iresp.ExitCode, outBuffer: &s.stdout, errBuffer: &s.stderr}, nil 87 } 88 89 // ExecT calls Exec() and aborts the test if an error occurs. 90 func ExecT(ctx context.Context, t testing.TB, apiClient client.APIClient, id string, cmd []string, ops ...func(*types.ExecConfig)) ExecResult { 91 t.Helper() 92 res, err := Exec(ctx, apiClient, id, cmd, ops...) 93 if err != nil { 94 t.Fatal(err) 95 } 96 return res 97 }