start_stop_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. Copyright 2020 Docker Compose CLI authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package e2e
  14. import (
  15. "fmt"
  16. "strings"
  17. "testing"
  18. testify "github.com/stretchr/testify/assert"
  19. "gotest.tools/v3/assert"
  20. "gotest.tools/v3/icmd"
  21. )
  22. func TestStartStop(t *testing.T) {
  23. c := NewParallelCLI(t)
  24. const projectName = "e2e-start-stop-no-dependencies"
  25. getProjectRegx := func(status string) string {
  26. // match output with random spaces like:
  27. // e2e-start-stop running(3)
  28. return fmt.Sprintf("%s\\s+%s\\(%d\\)", projectName, status, 2)
  29. }
  30. getServiceRegx := func(service string, status string) string {
  31. // match output with random spaces like:
  32. // e2e-start-stop-db-1 "echo hello" db running
  33. return fmt.Sprintf("%s-%s-1.+%s\\s+%s", projectName, service, service, status)
  34. }
  35. t.Run("Up a project", func(t *testing.T) {
  36. res := c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "up",
  37. "-d")
  38. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-no-dependencies-simple-1 Started"), res.Combined())
  39. res = c.RunDockerComposeCmd(t, "ls", "--all")
  40. testify.Regexp(t, getProjectRegx("running"), res.Stdout())
  41. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps")
  42. testify.Regexp(t, getServiceRegx("simple", "running"), res.Stdout())
  43. testify.Regexp(t, getServiceRegx("another", "running"), res.Stdout())
  44. })
  45. t.Run("stop project", func(t *testing.T) {
  46. c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "stop")
  47. res := c.RunDockerComposeCmd(t, "ls")
  48. assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies"), res.Combined())
  49. res = c.RunDockerComposeCmd(t, "ls", "--all")
  50. testify.Regexp(t, getProjectRegx("exited"), res.Stdout())
  51. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps")
  52. assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies-words-1"), res.Combined())
  53. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--all")
  54. testify.Regexp(t, getServiceRegx("simple", "exited"), res.Stdout())
  55. testify.Regexp(t, getServiceRegx("another", "exited"), res.Stdout())
  56. })
  57. t.Run("start project", func(t *testing.T) {
  58. c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "start")
  59. res := c.RunDockerComposeCmd(t, "ls")
  60. testify.Regexp(t, getProjectRegx("running"), res.Stdout())
  61. })
  62. t.Run("down", func(t *testing.T) {
  63. _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
  64. })
  65. }
  66. func TestStartStopWithDependencies(t *testing.T) {
  67. c := NewParallelCLI(t)
  68. const projectName = "e2e-start-stop-with-dependencies"
  69. defer c.RunDockerComposeCmd(t, "--project-name", projectName, "rm", "-fsv")
  70. t.Run("Up", func(t *testing.T) {
  71. res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName,
  72. "up", "-d")
  73. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined())
  74. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined())
  75. })
  76. t.Run("stop foo", func(t *testing.T) {
  77. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop", "foo")
  78. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Stopped"), res.Combined())
  79. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--status", "running")
  80. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined())
  81. assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined())
  82. })
  83. t.Run("start foo", func(t *testing.T) {
  84. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop")
  85. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Stopped"), res.Combined())
  86. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "start", "foo")
  87. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined())
  88. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined())
  89. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--status", "running")
  90. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined())
  91. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined())
  92. })
  93. t.Run("Up no-deps links", func(t *testing.T) {
  94. _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
  95. res := c.RunDockerComposeCmd(t, "-f", "./fixtures/links/compose.yaml", "--project-name", projectName, "up",
  96. "--no-deps", "-d", "foo")
  97. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined())
  98. assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined())
  99. })
  100. t.Run("down", func(t *testing.T) {
  101. _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
  102. })
  103. }
  104. func TestStartStopWithOneOffs(t *testing.T) {
  105. c := NewParallelCLI(t)
  106. const projectName = "e2e-start-stop-with-oneoffs"
  107. t.Run("Up", func(t *testing.T) {
  108. res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName,
  109. "up", "-d")
  110. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-oneoffs-foo-1 Started"), res.Combined())
  111. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-oneoffs-bar-1 Started"), res.Combined())
  112. })
  113. t.Run("run one-off", func(t *testing.T) {
  114. c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName, "run", "-d", "bar", "sleep", "infinity")
  115. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a")
  116. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined())
  117. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined())
  118. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined())
  119. })
  120. t.Run("stop (not one-off containers)", func(t *testing.T) {
  121. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop")
  122. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined())
  123. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined())
  124. assert.Assert(t, !strings.Contains(res.Combined(), "e2e_start_stop_with_oneoffs_bar_run"), res.Combined())
  125. res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a", "--status", "running")
  126. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined())
  127. })
  128. t.Run("start (not one-off containers)", func(t *testing.T) {
  129. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "start")
  130. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined())
  131. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined())
  132. assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined())
  133. })
  134. t.Run("restart (not one-off containers)", func(t *testing.T) {
  135. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "restart")
  136. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined())
  137. assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined())
  138. assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined())
  139. })
  140. t.Run("down", func(t *testing.T) {
  141. c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--remove-orphans")
  142. res := c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a", "--status", "running")
  143. assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar"), res.Combined())
  144. })
  145. }
  146. func TestStartAlreadyRunning(t *testing.T) {
  147. cli := NewParallelCLI(t, WithEnv(
  148. "COMPOSE_PROJECT_NAME=e2e-start-stop-svc-already-running",
  149. "COMPOSE_FILE=./fixtures/start-stop/compose.yaml"))
  150. t.Cleanup(func() {
  151. cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
  152. })
  153. cli.RunDockerComposeCmd(t, "up", "-d", "--wait")
  154. res := cli.RunDockerComposeCmd(t, "start", "simple")
  155. assert.Equal(t, res.Stdout(), "", "No output should have been written to stdout")
  156. }
  157. func TestStopAlreadyStopped(t *testing.T) {
  158. cli := NewParallelCLI(t, WithEnv(
  159. "COMPOSE_PROJECT_NAME=e2e-start-stop-svc-already-stopped",
  160. "COMPOSE_FILE=./fixtures/start-stop/compose.yaml"))
  161. t.Cleanup(func() {
  162. cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
  163. })
  164. cli.RunDockerComposeCmd(t, "up", "-d", "--wait")
  165. // stop the container
  166. cli.RunDockerComposeCmd(t, "stop", "simple")
  167. // attempt to stop it again
  168. res := cli.RunDockerComposeCmdNoCheck(t, "stop", "simple")
  169. // TODO: for consistency, this should NOT write any output because the
  170. // container is already stopped
  171. res.Assert(t, icmd.Expected{
  172. ExitCode: 0,
  173. Err: "Container e2e-start-stop-svc-already-stopped-simple-1 Stopped",
  174. })
  175. }
  176. func TestStartStopMultipleServices(t *testing.T) {
  177. cli := NewParallelCLI(t, WithEnv(
  178. "COMPOSE_PROJECT_NAME=e2e-start-stop-svc-multiple",
  179. "COMPOSE_FILE=./fixtures/start-stop/compose.yaml"))
  180. t.Cleanup(func() {
  181. cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
  182. })
  183. cli.RunDockerComposeCmd(t, "up", "-d", "--wait")
  184. res := cli.RunDockerComposeCmd(t, "stop", "simple", "another")
  185. services := []string{"simple", "another"}
  186. for _, svc := range services {
  187. stopMsg := fmt.Sprintf("Container e2e-start-stop-svc-multiple-%s-1 Stopped", svc)
  188. assert.Assert(t, strings.Contains(res.Stderr(), stopMsg),
  189. fmt.Sprintf("Missing stop message for %s\n%s", svc, res.Combined()))
  190. }
  191. res = cli.RunDockerComposeCmd(t, "start", "simple", "another")
  192. for _, svc := range services {
  193. startMsg := fmt.Sprintf("Container e2e-start-stop-svc-multiple-%s-1 Started", svc)
  194. assert.Assert(t, strings.Contains(res.Stderr(), startMsg),
  195. fmt.Sprintf("Missing start message for %s\n%s", svc, res.Combined()))
  196. }
  197. }
  198. func TestStartSingleServiceAndDependency(t *testing.T) {
  199. cli := NewParallelCLI(t, WithEnv(
  200. "COMPOSE_PROJECT_NAME=e2e-start-single-deps",
  201. "COMPOSE_FILE=./fixtures/start-stop/start-stop-deps.yaml"))
  202. t.Cleanup(func() {
  203. cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
  204. })
  205. cli.RunDockerComposeCmd(t, "create", "desired")
  206. res := cli.RunDockerComposeCmd(t, "start", "desired")
  207. desiredServices := []string{"desired", "dep_1", "dep_2"}
  208. for _, s := range desiredServices {
  209. startMsg := fmt.Sprintf("Container e2e-start-single-deps-%s-1 Started", s)
  210. assert.Assert(t, strings.Contains(res.Combined(), startMsg),
  211. fmt.Sprintf("Missing start message for service: %s\n%s", s, res.Combined()))
  212. }
  213. undesiredServices := []string{"another", "another_2"}
  214. for _, s := range undesiredServices {
  215. assert.Assert(t, !strings.Contains(res.Combined(), s),
  216. fmt.Sprintf("Shouldn't have message for service: %s\n%s", s, res.Combined()))
  217. }
  218. }
  219. func TestStartStopMultipleFiles(t *testing.T) {
  220. cli := NewParallelCLI(t, WithEnv("COMPOSE_PROJECT_NAME=e2e-start-stop-svc-multiple-files"))
  221. t.Cleanup(func() {
  222. cli.RunDockerComposeCmd(t, "-p", "e2e-start-stop-svc-multiple-files", "down", "--remove-orphans")
  223. })
  224. cli.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "up", "-d")
  225. cli.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/other.yaml", "up", "-d")
  226. res := cli.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "stop")
  227. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-simple-1 Stopped"), res.Combined())
  228. assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-another-1 Stopped"), res.Combined())
  229. assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-a-different-one-1 Stopped"), res.Combined())
  230. assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-and-another-one-1 Stopped"), res.Combined())
  231. }