mirror of https://github.com/docker/compose.git
541 lines
17 KiB
Go
541 lines
17 KiB
Go
/*
|
|
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 main
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gotest.tools/v3/assert"
|
|
"gotest.tools/v3/golden"
|
|
"gotest.tools/v3/icmd"
|
|
|
|
. "github.com/docker/compose-cli/utils/e2e"
|
|
)
|
|
|
|
var binDir string
|
|
|
|
func TestMain(m *testing.M) {
|
|
p, cleanup, err := SetupExistingCLI()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
binDir = p
|
|
exitCode := m.Run()
|
|
cleanup()
|
|
os.Exit(exitCode)
|
|
}
|
|
|
|
func TestContextDefault(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("show", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "show")
|
|
res.Assert(t, icmd.Expected{Out: "default"})
|
|
})
|
|
|
|
t.Run("ls", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "ls")
|
|
golden.Assert(t, res.Stdout(), GoldenFile("ls-out-default"))
|
|
|
|
res = c.RunDockerCmd("context", "ls", "--format", "pretty")
|
|
golden.Assert(t, res.Stdout(), GoldenFile("ls-out-default"))
|
|
|
|
res = c.RunDockerCmd("context", "ls", "--format", "json")
|
|
golden.Assert(t, res.Stdout(), GoldenFile("ls-out-json"))
|
|
|
|
res = c.RunDockerCmd("context", "ls", "--format", "{{ json . }}")
|
|
golden.Assert(t, res.Stdout(), GoldenFile("ls-out-legacy-json"))
|
|
})
|
|
|
|
t.Run("inspect", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "inspect", "default")
|
|
res.Assert(t, icmd.Expected{Out: `"Name": "default"`})
|
|
})
|
|
|
|
t.Run("inspect current", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "inspect")
|
|
res.Assert(t, icmd.Expected{Out: `"Name": "default"`})
|
|
})
|
|
}
|
|
|
|
func TestContextCreateDocker(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
res := c.RunDockerCmd("context", "create", "test-docker", "--from", "default")
|
|
res.Assert(t, icmd.Expected{Out: "test-docker"})
|
|
|
|
t.Run("ls", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "ls")
|
|
golden.Assert(t, res.Stdout(), GoldenFile("ls-out-test-docker"))
|
|
})
|
|
|
|
t.Run("ls quiet", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "ls", "-q")
|
|
golden.Assert(t, res.Stdout(), "ls-out-test-docker-quiet.golden")
|
|
})
|
|
|
|
t.Run("ls format", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "ls", "--format", "{{ json . }}")
|
|
res.Assert(t, icmd.Expected{Out: `"Name":"default"`})
|
|
})
|
|
}
|
|
|
|
func TestContextInspect(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
res := c.RunDockerCmd("context", "create", "test-docker", "--from", "default")
|
|
res.Assert(t, icmd.Expected{Out: "test-docker"})
|
|
|
|
t.Run("inspect current", func(t *testing.T) {
|
|
// Cannot be run in parallel because of "context use"
|
|
res := c.RunDockerCmd("context", "use", "test-docker")
|
|
res.Assert(t, icmd.Expected{Out: "test-docker"})
|
|
|
|
res = c.RunDockerCmd("context", "inspect")
|
|
res.Assert(t, icmd.Expected{Out: `"Name": "test-docker"`})
|
|
})
|
|
}
|
|
|
|
func TestContextHelpACI(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("help", func(t *testing.T) {
|
|
res := c.RunDockerCmd("context", "create", "aci", "--help")
|
|
// Can't use golden here as the help prints the config directory which changes
|
|
res.Assert(t, icmd.Expected{Out: "docker context create aci CONTEXT [flags]"})
|
|
res.Assert(t, icmd.Expected{Out: "--location"})
|
|
res.Assert(t, icmd.Expected{Out: "--subscription-id"})
|
|
res.Assert(t, icmd.Expected{Out: "--resource-group"})
|
|
})
|
|
|
|
t.Run("check exec", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("context", "create", "aci", "--subscription-id", "invalid-id")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "accepts 1 arg(s), received 0",
|
|
})
|
|
assert.Assert(t, !strings.Contains(res.Combined(), "unknown flag"))
|
|
})
|
|
}
|
|
|
|
func TestContextMetrics(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
s := NewMetricsServer(c.MetricsSocket())
|
|
s.Start()
|
|
defer s.Stop()
|
|
|
|
started := false
|
|
for i := 0; i < 30; i++ {
|
|
c.RunDockerCmd("help", "ps")
|
|
if len(s.GetUsage()) > 0 {
|
|
started = true
|
|
fmt.Printf(" [%s] Server up in %d ms\n", t.Name(), i*100)
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
assert.Assert(t, started, "Metrics mock server not available after 3 secs")
|
|
|
|
t.Run("send metrics on help commands", func(t *testing.T) {
|
|
s.ResetUsage()
|
|
|
|
c.RunDockerCmd("help", "run")
|
|
c.RunDockerCmd("--help")
|
|
c.RunDockerCmd("run", "--help")
|
|
|
|
usage := s.GetUsage()
|
|
assert.DeepEqual(t, []string{
|
|
`{"command":"help run","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"--help","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"--help run","context":"moby","source":"cli","status":"success"}`,
|
|
}, usage)
|
|
})
|
|
|
|
t.Run("metrics on default context", func(t *testing.T) {
|
|
s.ResetUsage()
|
|
|
|
c.RunDockerCmd("ps")
|
|
c.RunDockerCmd("version")
|
|
c.RunDockerOrExitError("version", "--xxx")
|
|
|
|
usage := s.GetUsage()
|
|
assert.DeepEqual(t, []string{
|
|
`{"command":"ps","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"version","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"version","context":"moby","source":"cli","status":"failure-cmd-syntax"}`,
|
|
}, usage)
|
|
})
|
|
|
|
t.Run("metrics on other context type", func(t *testing.T) {
|
|
s.ResetUsage()
|
|
|
|
c.RunDockerCmd("context", "create", "local", "test-local")
|
|
c.RunDockerCmd("ps")
|
|
c.RunDockerCmd("context", "use", "test-local")
|
|
c.RunDockerCmd("ps")
|
|
c.RunDockerOrExitError("stop", "unknown")
|
|
c.RunDockerCmd("context", "use", "default")
|
|
c.RunDockerCmd("--context", "test-local", "ps")
|
|
c.RunDockerCmd("context", "ls")
|
|
|
|
usage := s.GetUsage()
|
|
assert.DeepEqual(t, []string{
|
|
`{"command":"context create","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"ps","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"context use","context":"moby","source":"cli","status":"success"}`,
|
|
`{"command":"ps","context":"local","source":"cli","status":"success"}`,
|
|
`{"command":"stop","context":"local","source":"cli","status":"failure"}`,
|
|
`{"command":"context use","context":"local","source":"cli","status":"success"}`,
|
|
`{"command":"ps","context":"local","source":"cli","status":"success"}`,
|
|
`{"command":"context ls","context":"moby","source":"cli","status":"success"}`,
|
|
}, usage)
|
|
})
|
|
}
|
|
|
|
func TestContextDuplicateACI(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
c.RunDockerCmd("context", "create", "mycontext", "--from", "default")
|
|
res := c.RunDockerOrExitError("context", "create", "aci", "mycontext")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "context mycontext: already exists",
|
|
})
|
|
}
|
|
|
|
func TestContextRemove(t *testing.T) {
|
|
t.Run("remove current", func(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
c.RunDockerCmd("context", "create", "test-context-rm", "--from", "default")
|
|
res := c.RunDockerCmd("context", "use", "test-context-rm")
|
|
res.Assert(t, icmd.Expected{Out: "test-context-rm"})
|
|
res = c.RunDockerOrExitError("context", "rm", "test-context-rm")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "cannot delete current context",
|
|
})
|
|
})
|
|
|
|
t.Run("force remove current", func(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
c.RunDockerCmd("context", "create", "test-context-rmf")
|
|
c.RunDockerCmd("context", "use", "test-context-rmf")
|
|
res := c.RunDockerCmd("context", "rm", "-f", "test-context-rmf")
|
|
res.Assert(t, icmd.Expected{Out: "test-context-rmf"})
|
|
res = c.RunDockerCmd("context", "ls")
|
|
res.Assert(t, icmd.Expected{Out: "default *"})
|
|
})
|
|
}
|
|
|
|
func TestLoginCommandDelegation(t *testing.T) {
|
|
// These tests just check that the existing CLI is called in various cases.
|
|
// They do not test actual login functionality.
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("default context", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("login", "-u", "nouser", "-p", "wrongpasword")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "unauthorized: incorrect username or password",
|
|
})
|
|
})
|
|
|
|
t.Run("interactive", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("login", "someregistry.docker.io")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "Cannot perform an interactive login from a non TTY device",
|
|
})
|
|
})
|
|
|
|
t.Run("localhost registry interactive", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("login", "localhost:443")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "Cannot perform an interactive login from a non TTY device",
|
|
})
|
|
})
|
|
|
|
t.Run("localhost registry", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("login", "localhost", "-u", "user", "-p", "password")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "http://localhost/v2/",
|
|
})
|
|
})
|
|
|
|
t.Run("logout", func(t *testing.T) {
|
|
res := c.RunDockerCmd("logout", "someregistry.docker.io")
|
|
res.Assert(t, icmd.Expected{Out: "Removing login credentials for someregistry.docker.io"})
|
|
})
|
|
|
|
t.Run("logout", func(t *testing.T) {
|
|
res := c.RunDockerCmd("logout", "localhost:443")
|
|
res.Assert(t, icmd.Expected{Out: "Removing login credentials for localhost:443"})
|
|
})
|
|
|
|
t.Run("existing context", func(t *testing.T) {
|
|
c.RunDockerCmd("context", "create", "local", "local")
|
|
c.RunDockerCmd("context", "use", "local")
|
|
res := c.RunDockerOrExitError("login", "-u", "nouser", "-p", "wrongpasword")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "unauthorized: incorrect username or password",
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestMissingExistingCLI(t *testing.T) {
|
|
t.Parallel()
|
|
home, err := ioutil.TempDir("", "")
|
|
assert.NilError(t, err)
|
|
t.Cleanup(func() {
|
|
_ = os.RemoveAll(home)
|
|
})
|
|
|
|
bin, err := ioutil.TempDir("", "")
|
|
assert.NilError(t, err)
|
|
t.Cleanup(func() {
|
|
_ = os.RemoveAll(bin)
|
|
})
|
|
err = CopyFile(filepath.Join(binDir, DockerExecutableName), filepath.Join(bin, DockerExecutableName))
|
|
assert.NilError(t, err)
|
|
|
|
env := []string{"PATH=" + bin}
|
|
if runtime.GOOS == "windows" {
|
|
env = append(env, "USERPROFILE="+home)
|
|
|
|
} else {
|
|
env = append(env, "HOME="+home)
|
|
}
|
|
|
|
c := icmd.Cmd{
|
|
Env: env,
|
|
Command: []string{filepath.Join(bin, "docker")},
|
|
}
|
|
res := icmd.RunCmd(c)
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: `"com.docker.cli": executable file not found`,
|
|
})
|
|
}
|
|
|
|
func TestLegacy(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("help", func(t *testing.T) {
|
|
res := c.RunDockerCmd("--help")
|
|
res.Assert(t, icmd.Expected{Out: "swarm"})
|
|
})
|
|
|
|
t.Run("swarm", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("swarm", "join")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: `"docker swarm join" requires exactly 1 argument.`,
|
|
})
|
|
})
|
|
|
|
t.Run("local run", func(t *testing.T) {
|
|
cmd := c.NewDockerCmd("run", "--rm", "hello-world")
|
|
cmd.Timeout = 40 * time.Second
|
|
res := icmd.RunCmd(cmd)
|
|
res.Assert(t, icmd.Expected{Out: "Hello from Docker!"})
|
|
})
|
|
|
|
t.Run("error messages", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("foo")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "docker: 'foo' is not a docker command.",
|
|
})
|
|
})
|
|
|
|
t.Run("run without HOME defined", func(t *testing.T) {
|
|
cmd := c.NewDockerCmd("ps")
|
|
cmd.Env = []string{"PATH=" + c.PathEnvVar()}
|
|
res := icmd.RunCmd(cmd)
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 0,
|
|
Out: "CONTAINER ID",
|
|
})
|
|
assert.Equal(t, res.Stderr(), "")
|
|
})
|
|
|
|
t.Run("run without write access to context store", func(t *testing.T) {
|
|
cmd := c.NewDockerCmd("ps")
|
|
cmd.Env = []string{"PATH=" + c.PathEnvVar(), "HOME=/doesnotexist/"}
|
|
res := icmd.RunCmd(cmd)
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 0,
|
|
Out: "CONTAINER ID",
|
|
})
|
|
})
|
|
|
|
t.Run("host flag", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("-H", "tcp://nonexistent:123", "version")
|
|
assert.Assert(t, res.ExitCode == 1)
|
|
assert.Assert(t, strings.Contains(res.Stderr(), "dial tcp: lookup nonexistent"), res.Stderr())
|
|
})
|
|
|
|
t.Run("remote engine context", func(t *testing.T) {
|
|
c.RunDockerCmd("context", "create", "test-remote-engine", "--docker", "host=tcp://nonexistent:1234")
|
|
c.RunDockerCmd("context", "use", "test-remote-engine")
|
|
|
|
res := c.RunDockerOrExitError("version")
|
|
assert.Assert(t, res.ExitCode == 1)
|
|
assert.Assert(t, strings.Contains(res.Stderr(), "dial tcp: lookup nonexistent"), res.Stderr())
|
|
})
|
|
|
|
t.Run("existing contexts delegate", func(t *testing.T) {
|
|
c.RunDockerCmd("context", "create", "moby-ctx", "--from=default")
|
|
c.RunDockerCmd("context", "use", "moby-ctx")
|
|
res := c.RunDockerOrExitError("swarm", "join")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: `"docker swarm join" requires exactly 1 argument.`,
|
|
})
|
|
res = c.RunDockerCmd("context", "update", "moby-ctx", "--description", "updated context")
|
|
res.Assert(t, icmd.Expected{Out: "moby-ctx"})
|
|
})
|
|
|
|
t.Run("host flag overrides context", func(t *testing.T) {
|
|
c.RunDockerCmd("context", "create", "local", "test-local")
|
|
c.RunDockerCmd("context", "use", "test-local")
|
|
endpoint := "unix:///var/run/docker.sock"
|
|
if runtime.GOOS == "windows" {
|
|
endpoint = "npipe:////./pipe/docker_engine"
|
|
}
|
|
res := c.RunDockerCmd("-H", endpoint, "images")
|
|
// Local backend does not have images command
|
|
assert.Assert(t, strings.Contains(res.Stdout(), "IMAGE ID"), res.Stdout())
|
|
})
|
|
}
|
|
|
|
func TestLegacyLogin(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("host flag login", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("-H", "tcp://localhost:123", "login", "-u", "nouser", "-p", "wrongpasword")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "WARNING! Using --password via the CLI is insecure. Use --password-stdin.",
|
|
})
|
|
})
|
|
|
|
t.Run("log level flag login", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("--log-level", "debug", "login", "-u", "nouser", "-p", "wrongpasword")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: "WARNING! Using --password via the CLI is insecure",
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestUnsupportedCommand(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
c.RunDockerCmd("context", "create", "local", "test-local")
|
|
res := c.RunDockerOrExitError("--context", "test-local", "images")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Err: `Command "images" not available in current context (test-local), you can use the "default" context to run this command`,
|
|
})
|
|
}
|
|
|
|
func TestBackendMetadata(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("backend-metadata", func(t *testing.T) {
|
|
res := c.RunDockerCmd("backend-metadata")
|
|
res.Assert(t, icmd.Expected{Out: `{"Name":"Cloud integration","Version":"`})
|
|
})
|
|
}
|
|
|
|
func TestVersion(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
|
|
t.Run("azure version", func(t *testing.T) {
|
|
res := c.RunDockerCmd("version")
|
|
res.Assert(t, icmd.Expected{Out: "Cloud integration"})
|
|
})
|
|
|
|
t.Run("format", func(t *testing.T) {
|
|
res := c.RunDockerCmd("version", "-f", "{{ json . }}")
|
|
res.Assert(t, icmd.Expected{Out: `"Client":`})
|
|
res = c.RunDockerCmd("version", "--format", "{{ json . }}")
|
|
res.Assert(t, icmd.Expected{Out: `"Client":`})
|
|
})
|
|
|
|
t.Run("format legacy", func(t *testing.T) {
|
|
res := c.RunDockerCmd("version", "-f", "{{ json .Client }}")
|
|
res.Assert(t, icmd.Expected{Out: `"DefaultAPIVersion":`})
|
|
res = c.RunDockerCmd("version", "--format", "{{ json .Server }}")
|
|
res.Assert(t, icmd.Expected{Out: `"KernelVersion":`})
|
|
})
|
|
|
|
t.Run("format cloud integration", func(t *testing.T) {
|
|
res := c.RunDockerCmd("version", "-f", "pretty")
|
|
res.Assert(t, icmd.Expected{Out: `Cloud integration:`})
|
|
res = c.RunDockerCmd("version", "-f", "")
|
|
res.Assert(t, icmd.Expected{Out: `Cloud integration:`})
|
|
|
|
res = c.RunDockerCmd("version", "-f", "json")
|
|
res.Assert(t, icmd.Expected{Out: `"CloudIntegration":`})
|
|
res = c.RunDockerCmd("version", "-f", "{{ json . }}")
|
|
res.Assert(t, icmd.Expected{Out: `"CloudIntegration":`})
|
|
res = c.RunDockerCmd("version", "--format", "{{json .}}")
|
|
res.Assert(t, icmd.Expected{Out: `"CloudIntegration":`})
|
|
res = c.RunDockerCmd("version", "--format", "{{json . }}")
|
|
res.Assert(t, icmd.Expected{Out: `"CloudIntegration":`})
|
|
res = c.RunDockerCmd("version", "--format", "{{ json .}}")
|
|
res.Assert(t, icmd.Expected{Out: `"CloudIntegration":`})
|
|
res = c.RunDockerCmd("version", "--format", "{{ json . }}")
|
|
res.Assert(t, icmd.Expected{Out: `"CloudIntegration":`})
|
|
})
|
|
|
|
t.Run("delegate version flag", func(t *testing.T) {
|
|
c.RunDockerCmd("context", "create", "local", "test-local")
|
|
c.RunDockerCmd("context", "use", "test-local")
|
|
res := c.RunDockerCmd("-v")
|
|
res.Assert(t, icmd.Expected{Out: "Docker version"})
|
|
})
|
|
}
|
|
|
|
func TestFailOnEcsUsageAsPlugin(t *testing.T) {
|
|
c := NewParallelE2eCLI(t, binDir)
|
|
res := c.RunDockerCmd("context", "create", "local", "local")
|
|
res.Assert(t, icmd.Expected{})
|
|
|
|
t.Run("fail on ecs usage as plugin", func(t *testing.T) {
|
|
res := c.RunDockerOrExitError("--context", "local", "ecs", "compose", "up")
|
|
res.Assert(t, icmd.Expected{
|
|
ExitCode: 1,
|
|
Out: "",
|
|
Err: "The ECS integration is now part of the CLI. Use `docker compose` with an ECS context.",
|
|
})
|
|
})
|
|
}
|