github.com/rumpl/bof@v23.0.0-rc.2+incompatible/integration/container/logs_test.go (about) 1 package container // import "github.com/docker/docker/integration/container" 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/daemon/logger/jsonfilelog" 13 "github.com/docker/docker/daemon/logger/local" 14 "github.com/docker/docker/integration/internal/container" 15 "github.com/docker/docker/integration/internal/termtest" 16 "github.com/docker/docker/pkg/stdcopy" 17 "gotest.tools/v3/assert" 18 "gotest.tools/v3/assert/cmp" 19 "gotest.tools/v3/poll" 20 "gotest.tools/v3/skip" 21 ) 22 23 // Regression test for #35370 24 // Makes sure that when following we don't get an EOF error when there are no logs 25 func TestLogsFollowTailEmpty(t *testing.T) { 26 // FIXME(vdemeester) fails on a e2e run on linux... 27 skip.If(t, testEnv.IsRemoteDaemon) 28 defer setupTest(t)() 29 client := testEnv.APIClient() 30 ctx := context.Background() 31 32 id := container.Run(ctx, t, client, container.WithCmd("sleep", "100000")) 33 34 logs, err := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"}) 35 if logs != nil { 36 defer logs.Close() 37 } 38 assert.Check(t, err) 39 40 _, err = stdcopy.StdCopy(io.Discard, io.Discard, logs) 41 assert.Check(t, err) 42 } 43 44 func TestLogs(t *testing.T) { 45 drivers := []string{local.Name, jsonfilelog.Name} 46 47 for _, logDriver := range drivers { 48 t.Run("driver "+logDriver, func(t *testing.T) { 49 testLogs(t, logDriver) 50 }) 51 } 52 } 53 54 func testLogs(t *testing.T, logDriver string) { 55 defer setupTest(t)() 56 client := testEnv.APIClient() 57 ctx := context.Background() 58 59 testCases := []struct { 60 desc string 61 logOps types.ContainerLogsOptions 62 expectedOut string 63 expectedErr string 64 tty bool 65 }{ 66 // TTY, only one output stream 67 { 68 desc: "tty/stdout and stderr", 69 tty: true, 70 logOps: types.ContainerLogsOptions{ 71 ShowStdout: true, 72 ShowStderr: true, 73 }, 74 expectedOut: "this is fineaccidents happen", 75 }, 76 { 77 desc: "tty/only stdout", 78 tty: true, 79 logOps: types.ContainerLogsOptions{ 80 ShowStdout: true, 81 ShowStderr: false, 82 }, 83 expectedOut: "this is fineaccidents happen", 84 }, 85 { 86 desc: "tty/only stderr", 87 tty: true, 88 logOps: types.ContainerLogsOptions{ 89 ShowStdout: false, 90 ShowStderr: true, 91 }, 92 expectedOut: "", 93 }, 94 // Without TTY, both stdout and stderr 95 { 96 desc: "without tty/stdout and stderr", 97 tty: false, 98 logOps: types.ContainerLogsOptions{ 99 ShowStdout: true, 100 ShowStderr: true, 101 }, 102 expectedOut: "this is fine", 103 expectedErr: "accidents happen", 104 }, 105 { 106 desc: "without tty/only stdout", 107 tty: false, 108 logOps: types.ContainerLogsOptions{ 109 ShowStdout: true, 110 ShowStderr: false, 111 }, 112 expectedOut: "this is fine", 113 expectedErr: "", 114 }, 115 { 116 desc: "without tty/only stderr", 117 tty: false, 118 logOps: types.ContainerLogsOptions{ 119 ShowStdout: false, 120 ShowStderr: true, 121 }, 122 expectedOut: "", 123 expectedErr: "accidents happen", 124 }, 125 } 126 127 for _, tC := range testCases { 128 tC := tC 129 t.Run(tC.desc, func(t *testing.T) { 130 t.Parallel() 131 tty := tC.tty 132 id := container.Run(ctx, t, client, 133 container.WithCmd("sh", "-c", "echo -n this is fine; echo -n accidents happen >&2"), 134 container.WithTty(tty), 135 container.WithLogDriver(logDriver), 136 ) 137 defer client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true}) 138 139 poll.WaitOn(t, container.IsStopped(ctx, client, id), poll.WithDelay(time.Millisecond*100)) 140 141 logs, err := client.ContainerLogs(ctx, id, tC.logOps) 142 assert.NilError(t, err) 143 defer logs.Close() 144 145 var stdout, stderr bytes.Buffer 146 if tty { 147 // TTY, only one output stream 148 _, err = io.Copy(&stdout, logs) 149 } else { 150 _, err = stdcopy.StdCopy(&stdout, &stderr, logs) 151 } 152 assert.NilError(t, err) 153 154 stdoutStr := stdout.String() 155 156 if tty && testEnv.OSType == "windows" { 157 stdoutStr = stripEscapeCodes(t, stdoutStr) 158 159 // Special case for Windows Server 2019 160 // Check only that the raw output stream contains strings 161 // that were printed to container's stdout and stderr. 162 // This is a workaround for the backspace being outputted in an unexpected place 163 // which breaks the parsed output: https://github.com/moby/moby/issues/43710 164 if strings.Contains(testEnv.DaemonInfo.OperatingSystem, "Windows Server Version 1809") { 165 if tC.logOps.ShowStdout { 166 assert.Check(t, cmp.Contains(stdout.String(), "this is fine")) 167 assert.Check(t, cmp.Contains(stdout.String(), "accidents happen")) 168 } else { 169 assert.DeepEqual(t, stdoutStr, "") 170 } 171 return 172 } 173 } 174 175 assert.DeepEqual(t, stdoutStr, tC.expectedOut) 176 assert.DeepEqual(t, stderr.String(), tC.expectedErr) 177 }) 178 } 179 } 180 181 // This hack strips the escape codes that appear in the Windows TTY output and don't have 182 // any effect on the text content. 183 // This doesn't handle all escape sequences, only ones that were encountered during testing. 184 func stripEscapeCodes(t *testing.T, input string) string { 185 t.Logf("Stripping: %q\n", input) 186 output, err := termtest.StripANSICommands(input) 187 assert.NilError(t, err) 188 return output 189 }