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  }