| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /*
- Copyright 2020 Docker Compose CLI authors
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package e2e
- import (
- "encoding/json"
- "fmt"
- "net"
- "net/http"
- "os"
- "testing"
- "time"
- "github.com/stretchr/testify/require"
- "gotest.tools/v3/icmd"
- )
- func TestPause(t *testing.T) {
- if _, ok := os.LookupEnv("CI"); ok {
- t.Skip("Skipping test on CI... flaky")
- }
- cli := NewParallelCLI(t, WithEnv(
- "COMPOSE_PROJECT_NAME=e2e-pause",
- "COMPOSE_FILE=./fixtures/pause/compose.yaml"))
- cleanup := func() {
- cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0")
- }
- cleanup()
- t.Cleanup(cleanup)
- // launch both services and verify that they are accessible
- cli.RunDockerComposeCmd(t, "up", "-d")
- urls := map[string]string{
- "a": urlForService(t, cli, "a", 80),
- "b": urlForService(t, cli, "b", 80),
- }
- for _, url := range urls {
- HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 20*time.Second)
- }
- // pause a and verify that it can no longer be hit but b still can
- cli.RunDockerComposeCmd(t, "pause", "a")
- httpClient := http.Client{Timeout: 250 * time.Millisecond}
- resp, err := httpClient.Get(urls["a"])
- if resp != nil {
- _ = resp.Body.Close()
- }
- require.Error(t, err, "a should no longer respond")
- require.True(t, err.(net.Error).Timeout(), "Error should have indicated a timeout")
- HTTPGetWithRetry(t, urls["b"], http.StatusOK, 50*time.Millisecond, 5*time.Second)
- // unpause a and verify that both containers work again
- cli.RunDockerComposeCmd(t, "unpause", "a")
- for _, url := range urls {
- HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 5*time.Second)
- }
- }
- func TestPauseServiceNotRunning(t *testing.T) {
- cli := NewParallelCLI(t, WithEnv(
- "COMPOSE_PROJECT_NAME=e2e-pause-svc-not-running",
- "COMPOSE_FILE=./fixtures/pause/compose.yaml"))
- cleanup := func() {
- cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0")
- }
- cleanup()
- t.Cleanup(cleanup)
- // pause a and verify that it can no longer be hit but b still can
- res := cli.RunDockerComposeCmdNoCheck(t, "pause", "a")
- // TODO: `docker pause` errors in this case, should Compose be consistent?
- res.Assert(t, icmd.Expected{ExitCode: 0})
- }
- func TestPauseServiceAlreadyPaused(t *testing.T) {
- cli := NewParallelCLI(t, WithEnv(
- "COMPOSE_PROJECT_NAME=e2e-pause-svc-already-paused",
- "COMPOSE_FILE=./fixtures/pause/compose.yaml"))
- cleanup := func() {
- cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0")
- }
- cleanup()
- t.Cleanup(cleanup)
- // launch a and wait for it to come up
- cli.RunDockerComposeCmd(t, "up", "-d", "a")
- HTTPGetWithRetry(t, urlForService(t, cli, "a", 80), http.StatusOK, 50*time.Millisecond, 10*time.Second)
- // pause a twice - first time should pass, second time fail
- cli.RunDockerComposeCmd(t, "pause", "a")
- res := cli.RunDockerComposeCmdNoCheck(t, "pause", "a")
- res.Assert(t, icmd.Expected{ExitCode: 1, Err: "already paused"})
- }
- func TestPauseServiceDoesNotExist(t *testing.T) {
- cli := NewParallelCLI(t, WithEnv(
- "COMPOSE_PROJECT_NAME=e2e-pause-svc-not-exist",
- "COMPOSE_FILE=./fixtures/pause/compose.yaml"))
- cleanup := func() {
- cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0")
- }
- cleanup()
- t.Cleanup(cleanup)
- // pause a and verify that it can no longer be hit but b still can
- res := cli.RunDockerComposeCmdNoCheck(t, "pause", "does_not_exist")
- // TODO: `compose down does_not_exist` and similar error, this should too
- res.Assert(t, icmd.Expected{ExitCode: 0})
- }
- func urlForService(t testing.TB, cli *CLI, service string, targetPort int) string {
- t.Helper()
- return fmt.Sprintf(
- "http://localhost:%d",
- publishedPortForService(t, cli, service, targetPort),
- )
- }
- func publishedPortForService(t testing.TB, cli *CLI, service string, targetPort int) int {
- t.Helper()
- res := cli.RunDockerComposeCmd(t, "ps", "--format=json", service)
- var psOut []struct {
- Publishers []struct {
- TargetPort int
- PublishedPort int
- }
- }
- require.NoError(t, json.Unmarshal([]byte(res.Stdout()), &psOut),
- "Failed to parse `%s` output", res.Cmd.String())
- require.Len(t, psOut, 1, "Expected exactly 1 service")
- svc := psOut[0]
- for _, pp := range svc.Publishers {
- if pp.TargetPort == targetPort {
- return pp.PublishedPort
- }
- }
- require.Failf(t, "No published port for target port",
- "Target port: %d\nService: %s", targetPort, res.Combined())
- return -1
- }
|