github.com/rawahars/moby@v24.0.4+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 pollTimeout := time.Second * 10 128 if testEnv.OSType == "windows" { 129 pollTimeout = StopContainerWindowsPollTimeout 130 } 131 132 for _, tC := range testCases { 133 tC := tC 134 t.Run(tC.desc, func(t *testing.T) { 135 t.Parallel() 136 tty := tC.tty 137 id := container.Run(ctx, t, client, 138 container.WithCmd("sh", "-c", "echo -n this is fine; echo -n accidents happen >&2"), 139 container.WithTty(tty), 140 container.WithLogDriver(logDriver), 141 ) 142 defer client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true}) 143 144 poll.WaitOn(t, container.IsStopped(ctx, client, id), 145 poll.WithDelay(time.Millisecond*100), 146 poll.WithTimeout(pollTimeout)) 147 148 logs, err := client.ContainerLogs(ctx, id, tC.logOps) 149 assert.NilError(t, err) 150 defer logs.Close() 151 152 var stdout, stderr bytes.Buffer 153 if tty { 154 // TTY, only one output stream 155 _, err = io.Copy(&stdout, logs) 156 } else { 157 _, err = stdcopy.StdCopy(&stdout, &stderr, logs) 158 } 159 assert.NilError(t, err) 160 161 stdoutStr := stdout.String() 162 163 if tty && testEnv.OSType == "windows" { 164 stdoutStr = stripEscapeCodes(t, stdoutStr) 165 166 // Special case for Windows Server 2019 167 // Check only that the raw output stream contains strings 168 // that were printed to container's stdout and stderr. 169 // This is a workaround for the backspace being outputted in an unexpected place 170 // which breaks the parsed output: https://github.com/moby/moby/issues/43710 171 if strings.Contains(testEnv.DaemonInfo.OperatingSystem, "Windows Server Version 1809") { 172 if tC.logOps.ShowStdout { 173 assert.Check(t, cmp.Contains(stdout.String(), "this is fine")) 174 assert.Check(t, cmp.Contains(stdout.String(), "accidents happen")) 175 } else { 176 assert.DeepEqual(t, stdoutStr, "") 177 } 178 return 179 } 180 } 181 182 assert.DeepEqual(t, stdoutStr, tC.expectedOut) 183 assert.DeepEqual(t, stderr.String(), tC.expectedErr) 184 }) 185 } 186 } 187 188 // This hack strips the escape codes that appear in the Windows TTY output and don't have 189 // any effect on the text content. 190 // This doesn't handle all escape sequences, only ones that were encountered during testing. 191 func stripEscapeCodes(t *testing.T, input string) string { 192 t.Logf("Stripping: %q\n", input) 193 output, err := termtest.StripANSICommands(input) 194 assert.NilError(t, err) 195 return output 196 }