github.com/moby/docker@v26.1.3+incompatible/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 }