github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/integration-cli/docker_cli_stats_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"os/exec"
     7  	"regexp"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/docker/docker/integration-cli/cli"
    13  	"gotest.tools/v3/assert"
    14  	is "gotest.tools/v3/assert/cmp"
    15  )
    16  
    17  type DockerCLIStatsSuite struct {
    18  	ds *DockerSuite
    19  }
    20  
    21  func (s *DockerCLIStatsSuite) TearDownTest(ctx context.Context, c *testing.T) {
    22  	s.ds.TearDownTest(ctx, c)
    23  }
    24  
    25  func (s *DockerCLIStatsSuite) OnTimeout(c *testing.T) {
    26  	s.ds.OnTimeout(c)
    27  }
    28  
    29  func (s *DockerCLIStatsSuite) TestStatsNoStream(c *testing.T) {
    30  	// Windows does not support stats
    31  	testRequires(c, DaemonIsLinux)
    32  	id := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
    33  	id = strings.TrimSpace(id)
    34  	cli.WaitRun(c, id)
    35  
    36  	statsCmd := exec.Command(dockerBinary, "stats", "--no-stream", id)
    37  	type output struct {
    38  		out []byte
    39  		err error
    40  	}
    41  
    42  	ch := make(chan output, 1)
    43  	go func() {
    44  		out, err := statsCmd.Output()
    45  		ch <- output{out, err}
    46  	}()
    47  
    48  	select {
    49  	case outerr := <-ch:
    50  		assert.NilError(c, outerr.err, "Error running stats: %v", outerr.err)
    51  		assert.Assert(c, is.Contains(string(outerr.out), id[:12]), "running container wasn't present in output")
    52  	case <-time.After(3 * time.Second):
    53  		statsCmd.Process.Kill()
    54  		c.Fatalf("stats did not return immediately when not streaming")
    55  	}
    56  }
    57  
    58  func (s *DockerCLIStatsSuite) TestStatsContainerNotFound(c *testing.T) {
    59  	// Windows does not support stats
    60  	testRequires(c, DaemonIsLinux)
    61  
    62  	out, _, err := dockerCmdWithError("stats", "notfound")
    63  	assert.ErrorContains(c, err, "")
    64  	assert.Assert(c, is.Contains(out, "No such container: notfound"), "Expected to fail on not found container stats, got %q instead", out)
    65  
    66  	out, _, err = dockerCmdWithError("stats", "--no-stream", "notfound")
    67  	assert.ErrorContains(c, err, "")
    68  	assert.Assert(c, is.Contains(out, "No such container: notfound"), "Expected to fail on not found container stats with --no-stream, got %q instead", out)
    69  }
    70  
    71  func (s *DockerCLIStatsSuite) TestStatsAllRunningNoStream(c *testing.T) {
    72  	// Windows does not support stats
    73  	testRequires(c, DaemonIsLinux)
    74  
    75  	id1 := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
    76  	id1 = strings.TrimSpace(id1)[:12]
    77  	cli.WaitRun(c, id1)
    78  	id2 := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
    79  	id2 = strings.TrimSpace(id2)[:12]
    80  	cli.WaitRun(c, id2)
    81  	id3 := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
    82  	id3 = strings.TrimSpace(id3)[:12]
    83  	cli.WaitRun(c, id3)
    84  	cli.DockerCmd(c, "stop", id3)
    85  
    86  	out := cli.DockerCmd(c, "stats", "--no-stream").Combined()
    87  	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
    88  		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
    89  	}
    90  	if strings.Contains(out, id3) {
    91  		c.Fatalf("Did not expect %s in stats, got %s", id3, out)
    92  	}
    93  
    94  	// check output contains real data, but not all zeros
    95  	reg, _ := regexp.Compile("[1-9]+")
    96  	// split output with "\n", outLines[1] is id2's output
    97  	// outLines[2] is id1's output
    98  	outLines := strings.Split(out, "\n")
    99  	// check stat result of id2 contains real data
   100  	realData := reg.Find([]byte(outLines[1][12:]))
   101  	assert.Assert(c, realData != nil, "stat result are empty: %s", out)
   102  	// check stat result of id1 contains real data
   103  	realData = reg.Find([]byte(outLines[2][12:]))
   104  	assert.Assert(c, realData != nil, "stat result are empty: %s", out)
   105  }
   106  
   107  func (s *DockerCLIStatsSuite) TestStatsAllNoStream(c *testing.T) {
   108  	// Windows does not support stats
   109  	testRequires(c, DaemonIsLinux)
   110  
   111  	id1 := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
   112  	id1 = strings.TrimSpace(id1)[:12]
   113  	cli.WaitRun(c, id1)
   114  	cli.DockerCmd(c, "stop", id1)
   115  	id2 := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
   116  	id2 = strings.TrimSpace(id2)[:12]
   117  	cli.WaitRun(c, id2)
   118  
   119  	out := cli.DockerCmd(c, "stats", "--all", "--no-stream").Combined()
   120  	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
   121  		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
   122  	}
   123  
   124  	// check output contains real data, but not all zeros
   125  	reg, _ := regexp.Compile("[1-9]+")
   126  	// split output with "\n", outLines[1] is id2's output
   127  	outLines := strings.Split(out, "\n")
   128  	// check stat result of id2 contains real data
   129  	realData := reg.Find([]byte(outLines[1][12:]))
   130  	assert.Assert(c, realData != nil, "stat result of %s is empty: %s", id2, out)
   131  
   132  	// check stat result of id1 contains all zero
   133  	realData = reg.Find([]byte(outLines[2][12:]))
   134  	assert.Assert(c, realData == nil, "stat result of %s should be empty : %s", id1, out)
   135  }
   136  
   137  func (s *DockerCLIStatsSuite) TestStatsAllNewContainersAdded(c *testing.T) {
   138  	// Windows does not support stats
   139  	testRequires(c, DaemonIsLinux)
   140  
   141  	id := make(chan string)
   142  	addedChan := make(chan struct{})
   143  
   144  	runSleepingContainer(c, "-d")
   145  	statsCmd := exec.Command(dockerBinary, "stats")
   146  	stdout, err := statsCmd.StdoutPipe()
   147  	assert.NilError(c, err)
   148  	assert.NilError(c, statsCmd.Start())
   149  	go statsCmd.Wait()
   150  	defer statsCmd.Process.Kill()
   151  
   152  	go func() {
   153  		containerID := <-id
   154  		matchID := regexp.MustCompile(containerID)
   155  
   156  		scanner := bufio.NewScanner(stdout)
   157  		for scanner.Scan() {
   158  			switch {
   159  			case matchID.MatchString(scanner.Text()):
   160  				close(addedChan)
   161  				return
   162  			}
   163  		}
   164  	}()
   165  
   166  	out := runSleepingContainer(c, "-d")
   167  	cli.WaitRun(c, out)
   168  	id <- strings.TrimSpace(out)[:12]
   169  
   170  	select {
   171  	case <-time.After(30 * time.Second):
   172  		c.Fatal("failed to observe new container created added to stats")
   173  	case <-addedChan:
   174  		// ignore, done
   175  	}
   176  }
   177  
   178  func (s *DockerCLIStatsSuite) TestStatsFormatAll(c *testing.T) {
   179  	// Windows does not support stats
   180  	testRequires(c, DaemonIsLinux)
   181  
   182  	cli.DockerCmd(c, "run", "-d", "--name=RunningOne", "busybox", "top")
   183  	cli.WaitRun(c, "RunningOne")
   184  	cli.DockerCmd(c, "run", "-d", "--name=ExitedOne", "busybox", "top")
   185  	cli.DockerCmd(c, "stop", "ExitedOne")
   186  	cli.WaitExited(c, "ExitedOne", 5*time.Second)
   187  
   188  	out := cli.DockerCmd(c, "stats", "--no-stream", "--format", "{{.Name}}").Combined()
   189  	assert.Assert(c, is.Contains(out, "RunningOne"))
   190  	assert.Assert(c, !strings.Contains(out, "ExitedOne"))
   191  
   192  	out = cli.DockerCmd(c, "stats", "--all", "--no-stream", "--format", "{{.Name}}").Combined()
   193  	assert.Assert(c, is.Contains(out, "RunningOne"))
   194  	assert.Assert(c, is.Contains(out, "ExitedOne"))
   195  }