github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/container_logs_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "runtime" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/containerd/nerdctl/pkg/testutil" 27 ) 28 29 func TestLogs(t *testing.T) { 30 t.Parallel() 31 base := testutil.NewBase(t) 32 containerName := testutil.Identifier(t) 33 const expected = `foo 34 bar` 35 36 defer base.Cmd("rm", containerName).Run() 37 base.Cmd("run", "-d", "--name", containerName, testutil.CommonImage, 38 "sh", "-euxc", "echo foo; echo bar").AssertOK() 39 40 //test since / until flag 41 time.Sleep(3 * time.Second) 42 base.Cmd("logs", "--since", "1s", containerName).AssertNoOut(expected) 43 base.Cmd("logs", "--since", "10s", containerName).AssertOutContains(expected) 44 base.Cmd("logs", "--until", "10s", containerName).AssertNoOut(expected) 45 base.Cmd("logs", "--until", "1s", containerName).AssertOutContains(expected) 46 47 // Ensure follow flag works as expected: 48 base.Cmd("logs", "-f", containerName).AssertOutContains("bar") 49 base.Cmd("logs", "-f", containerName).AssertOutContains("foo") 50 51 //test timestamps flag 52 base.Cmd("logs", "-t", containerName).AssertOutContains(time.Now().Format("2006-01-02")) 53 54 //test tail flag 55 base.Cmd("logs", "-n", "all", containerName).AssertOutContains(expected) 56 57 base.Cmd("logs", "-n", "1", containerName).AssertOutWithFunc(func(stdout string) error { 58 if !(stdout == "bar\n" || stdout == "") { 59 return fmt.Errorf("expected %q or %q, got %q", "bar", "", stdout) 60 } 61 return nil 62 }) 63 64 base.Cmd("rm", "-f", containerName).AssertOK() 65 } 66 67 // Tests whether `nerdctl logs` properly separates stdout/stderr output 68 // streams for containers using the jsonfile logging driver: 69 func TestLogsOutStreamsSeparated(t *testing.T) { 70 t.Parallel() 71 base := testutil.NewBase(t) 72 containerName := testutil.Identifier(t) 73 74 defer base.Cmd("rm", containerName).Run() 75 base.Cmd("run", "-d", "--name", containerName, testutil.CommonImage, 76 "sh", "-euc", "echo stdout1; echo stderr1 >&2; echo stdout2; echo stderr2 >&2").AssertOK() 77 time.Sleep(3 * time.Second) 78 79 base.Cmd("logs", containerName).AssertOutStreamsExactly("stdout1\nstdout2\n", "stderr1\nstderr2\n") 80 } 81 82 func TestLogsWithInheritedFlags(t *testing.T) { 83 t.Parallel() 84 base := testutil.NewBase(t) 85 for k, v := range base.Args { 86 if strings.HasPrefix(v, "--namespace=") { 87 base.Args[k] = "-n=" + testutil.Namespace 88 } 89 } 90 containerName := testutil.Identifier(t) 91 92 defer base.Cmd("rm", containerName).Run() 93 base.Cmd("run", "-d", "--name", containerName, testutil.CommonImage, 94 "sh", "-euxc", "echo foo; echo bar").AssertOK() 95 96 // test rootCmd alias `-n` already used in logs subcommand 97 base.Cmd("logs", "-n", "1", containerName).AssertOutWithFunc(func(stdout string) error { 98 if !(stdout == "bar\n" || stdout == "") { 99 return fmt.Errorf("expected %q or %q, got %q", "bar", "", stdout) 100 } 101 return nil 102 }) 103 } 104 105 func TestLogsOfJournaldDriver(t *testing.T) { 106 t.Parallel() 107 testutil.RequireExecutable(t, "journalctl") 108 base := testutil.NewBase(t) 109 containerName := testutil.Identifier(t) 110 111 defer base.Cmd("rm", containerName).Run() 112 base.Cmd("run", "-d", "--network", "none", "--log-driver", "journald", "--name", containerName, testutil.CommonImage, 113 "sh", "-euxc", "echo foo; echo bar").AssertOK() 114 115 time.Sleep(3 * time.Second) 116 base.Cmd("logs", containerName).AssertOutContains("bar") 117 // Run logs twice, make sure that the logs are not removed 118 base.Cmd("logs", containerName).AssertOutContains("foo") 119 120 base.Cmd("logs", "--since", "5s", containerName).AssertOutWithFunc(func(stdout string) error { 121 if !strings.Contains(stdout, "bar") { 122 return fmt.Errorf("expected bar, got %s", stdout) 123 } 124 if !strings.Contains(stdout, "foo") { 125 return fmt.Errorf("expected foo, got %s", stdout) 126 } 127 return nil 128 }) 129 130 base.Cmd("rm", "-f", containerName).AssertOK() 131 } 132 133 func TestLogsWithFailingContainer(t *testing.T) { 134 t.Parallel() 135 base := testutil.NewBase(t) 136 containerName := testutil.Identifier(t) 137 defer base.Cmd("rm", containerName).Run() 138 base.Cmd("run", "-d", "--name", containerName, testutil.CommonImage, 139 "sh", "-euxc", "echo foo; echo bar; exit 42; echo baz").AssertOK() 140 time.Sleep(3 * time.Second) 141 // AssertOutContains also asserts that the exit code of the logs command == 0, 142 // even when the container is failing 143 base.Cmd("logs", "-f", containerName).AssertOutContains("bar") 144 base.Cmd("logs", "-f", containerName).AssertNoOut("baz") 145 base.Cmd("rm", "-f", containerName).AssertOK() 146 } 147 148 func TestLogsWithForegroundContainers(t *testing.T) { 149 t.Parallel() 150 if runtime.GOOS == "windows" { 151 t.Skip("dual logging is not supported on Windows") 152 } 153 base := testutil.NewBase(t) 154 tid := testutil.Identifier(t) 155 156 // unbuffer(1) emulates tty, which is required by `nerdctl run -t`. 157 // unbuffer(1) can be installed with `apt-get install expect`. 158 unbuffer := []string{"unbuffer"} 159 160 testCases := []struct { 161 name string 162 flags []string 163 tty bool 164 }{ 165 { 166 name: "foreground", 167 flags: nil, 168 tty: false, 169 }, 170 { 171 name: "interactive", 172 flags: []string{"-i"}, 173 tty: false, 174 }, 175 { 176 name: "PTY", 177 flags: []string{"-t"}, 178 tty: true, 179 }, 180 { 181 name: "interactivePTY", 182 flags: []string{"-i", "-t"}, 183 tty: true, 184 }, 185 } 186 187 for _, tc := range testCases { 188 tc := tc 189 func(t *testing.T) { 190 containerName := tid + "-" + tc.name 191 var cmdArgs []string 192 defer base.Cmd("rm", "-f", containerName).Run() 193 cmdArgs = append(cmdArgs, "run", "--name", containerName) 194 cmdArgs = append(cmdArgs, tc.flags...) 195 cmdArgs = append(cmdArgs, testutil.CommonImage, "sh", "-euxc", "echo foo; echo bar") 196 197 if tc.tty { 198 base.CmdWithHelper(unbuffer, cmdArgs...).AssertOK() 199 } else { 200 base.Cmd(cmdArgs...).AssertOK() 201 } 202 203 base.Cmd("logs", containerName).AssertOutContains("foo") 204 base.Cmd("logs", containerName).AssertOutContains("bar") 205 base.Cmd("logs", containerName).AssertNoOut("baz") 206 }(t) 207 } 208 }