docker_cli_stats_test.go 6.0 KB

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