From 5d95524be6ba4006d4880207909ee4de5f32cbb2 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Tue, 19 Jan 2016 16:54:03 +0100 Subject: [PATCH] Write CLI integration tests with Go Signed-off-by: David Gageot --- circle.yml | 5 +- its/cli/create_rm_test.go | 79 ++++++ its/cli/driver_help_test.go | 26 ++ its/cli/help_test.go | 96 +++++++ its/cli/inspect_test.go | 16 ++ its/cli/ls_test.go | 178 ++++++++++++ its/cli/status_test.go | 16 ++ its/cli/url_test.go | 16 ++ its/tester.go | 345 ++++++++++++++++++++++++ its/thirdparty/commands_test.go | 34 +++ test/integration/3rdparty/commands.bats | 34 --- test/integration/cli/create-rm.bats | 116 -------- test/integration/cli/driver_help.bats | 15 -- test/integration/cli/help.bats | 130 --------- test/integration/cli/inspect.bats | 9 - test/integration/cli/ls.bats | 191 ------------- test/integration/cli/status.bats | 9 - test/integration/cli/url.bats | 9 - 18 files changed, 807 insertions(+), 517 deletions(-) create mode 100644 its/cli/create_rm_test.go create mode 100644 its/cli/driver_help_test.go create mode 100644 its/cli/help_test.go create mode 100644 its/cli/inspect_test.go create mode 100644 its/cli/ls_test.go create mode 100644 its/cli/status_test.go create mode 100644 its/cli/url_test.go create mode 100644 its/tester.go create mode 100644 its/thirdparty/commands_test.go delete mode 100644 test/integration/3rdparty/commands.bats delete mode 100644 test/integration/cli/create-rm.bats delete mode 100644 test/integration/cli/driver_help.bats delete mode 100644 test/integration/cli/help.bats delete mode 100644 test/integration/cli/inspect.bats delete mode 100644 test/integration/cli/ls.bats delete mode 100644 test/integration/cli/status.bats delete mode 100644 test/integration/cli/url.bats diff --git a/circle.yml b/circle.yml index 5ff94210..655f9bc2 100644 --- a/circle.yml +++ b/circle.yml @@ -30,9 +30,6 @@ test: - gvm use stable && GO15VENDOREXPERIMENT=1 go get github.com/docker/docker-machine-driver-ci-test override: - - DRIVER=none test/integration/run-bats.sh test/integration/cli: - pwd: $BASE_STABLE - timeout: 600 - - PATH=../../../../bin:$PATH DRIVER=ci-test test/integration/run-bats.sh test/integration/3rdparty: + - gvm use stable && PATH=../../../../bin:$PATH DRIVER=ci-test GO15VENDOREXPERIMENT=1 go test -v github.com/docker/machine/its/...: pwd: $BASE_STABLE timeout: 600 diff --git a/its/cli/create_rm_test.go b/its/cli/create_rm_test.go new file mode 100644 index 00000000..1a1ae2fb --- /dev/null +++ b/its/cli/create_rm_test.go @@ -0,0 +1,79 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestCreateRm(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.Run("non-existent driver fails", func() { + test.Machine("create -d bogus bogus").Should().Fail(`Driver "bogus" not found. Do you have the plugin binary accessible in your PATH?`) + }) + + test.Run("non-existent driver fails", func() { + test.Machine("create -d bogus bogus").Should().Fail(`Driver "bogus" not found. Do you have the plugin binary accessible in your PATH?`) + }) + + test.Run("create with no name fails", func() { + test.Machine("create -d none").Should().Fail(`Error: No machine name specified`) + }) + + test.Run("create with invalid name fails", func() { + test.Machine("create -d none --url none ∞").Should().Fail(`Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -`) + }) + + test.Run("create with invalid name fails", func() { + test.Machine("create -d none --url none -").Should().Fail(`Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -`) + }) + + test.Run("create with invalid name fails", func() { + test.Machine("create -d none --url none .").Should().Fail(`Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -`) + }) + + test.Run("create with invalid name fails", func() { + test.Machine("create -d none --url none ..").Should().Fail(`Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -`) + }) + + test.Run("create with weird but valid name succeeds", func() { + test.Machine("create -d none --url none a").Should().Succeed() + }) + + test.Run("fail with extra argument", func() { + test.Machine("create -d none --url none a extra").Should().Fail(`Invalid command line. Found extra arguments [extra]`) + }) + + test.Run("create with weird but valid name", func() { + test.Machine("create -d none --url none 0").Should().Succeed() + }) + + test.Run("rm with no name fails", func() { + test.Machine("rm -y").Should().Fail(`Error: Expected to get one or more machine names as arguments`) + }) + + test.Run("rm non existent machine fails", func() { + test.Machine("rm ∞ -y").Should().Fail(`Error removing host "∞": Host does not exist: "∞"`) + }) + + test.Run("rm existing machine", func() { + test.Machine("rm 0 -y").Should().Succeed() + }) + + test.Run("rm ask user confirmation when -y is not provided", func() { + test.Machine("create -d none --url none ba").Should().Succeed() + test.Cmd("echo y | machine rm ba").Should().Succeed() + }) + + test.Run("rm deny user confirmation when -y is not provided", func() { + test.Machine("create -d none --url none ab").Should().Succeed() + test.Cmd("echo n | machine rm ab").Should().Succeed() + }) + + test.Run("rm never prompt user confirmation when -f is provided", func() { + test.Machine("create -d none --url none c").Should().Succeed() + test.Machine("rm -f c").Should().Succeed("Successfully removed c") + }) +} diff --git a/its/cli/driver_help_test.go b/its/cli/driver_help_test.go new file mode 100644 index 00000000..ea69491a --- /dev/null +++ b/its/cli/driver_help_test.go @@ -0,0 +1,26 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestDriverHelp(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.SkipDriver("ci-test") + + test.Run("no --help flag or command specified", func() { + test.Machine("create -d $DRIVER").Should().Fail("Error: No machine name specified") + }) + + test.Run("-h flag specified", func() { + test.Machine("create -d $DRIVER -h").Should().Succeed(test.DriverName()) + }) + + test.Run("--help flag specified", func() { + test.Machine("create -d $DRIVER --help").Should().Succeed(test.DriverName()) + }) +} diff --git a/its/cli/help_test.go b/its/cli/help_test.go new file mode 100644 index 00000000..3a1d0582 --- /dev/null +++ b/its/cli/help_test.go @@ -0,0 +1,96 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestHelp(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.Run("cli: show info", func() { + test.Machine("").Should().Succeed("Usage:", "Create and manage machines running Docker") + }) + + test.Run("cli: show active help", func() { + test.Machine("active -h").Should().Succeed("machine active") + }) + + test.Run("cli: show config help", func() { + test.Machine("config -h").Should().Succeed("machine config") + }) + + test.Run("cli: show create help", func() { + test.Machine("create -h").Should().Succeed("machine create") + }) + + test.Run("cli: show env help", func() { + test.Machine("env -h").Should().Succeed("machine env") + }) + + test.Run("cli: show inspect help", func() { + test.Machine("inspect -h").Should().Succeed("machine inspect") + }) + + test.Run("cli: show ip help", func() { + test.Machine("ip -h").Should().Succeed("machine ip") + }) + + test.Run("cli: show kill help", func() { + test.Machine("kill -h").Should().Succeed("machine kill") + }) + + test.Run("cli: show ls help", func() { + test.Machine("ls -h").Should().Succeed("machine ls") + }) + + test.Run("cli: show regenerate-certs help", func() { + test.Machine("regenerate-certs -h").Should().Succeed("machine regenerate-certs") + }) + + test.Run("cli: show restart help", func() { + test.Machine("restart -h").Should().Succeed("machine restart") + }) + + test.Run("cli: show rm help", func() { + test.Machine("rm -h").Should().Succeed("machine rm") + }) + + test.Run("cli: show scp help", func() { + test.Machine("scp -h").Should().Succeed("machine scp") + }) + + test.Run("cli: show ssh help", func() { + test.Machine("ssh -h").Should().Succeed("machine ssh") + }) + + test.Run("cli: show start help", func() { + test.Machine("start -h").Should().Succeed("machine start") + }) + + test.Run("cli: show status help", func() { + test.Machine("status -h").Should().Succeed("machine status") + }) + + test.Run("cli: show stop help", func() { + test.Machine("stop -h").Should().Succeed("machine stop") + }) + + test.Run("cli: show upgrade help", func() { + test.Machine("upgrade -h").Should().Succeed("machine upgrade") + }) + + test.Run("cli: show url help", func() { + test.Machine("url -h").Should().Succeed("machine url") + }) + + test.Run("cli: show version", func() { + test.Machine("-v").Should().Succeed("version") + }) + + test.Run("cli: show help", func() { + test.Machine("--help").Should().Succeed("Usage:") + }) +} diff --git a/its/cli/inspect_test.go b/its/cli/inspect_test.go new file mode 100644 index 00000000..59bd291b --- /dev/null +++ b/its/cli/inspect_test.go @@ -0,0 +1,16 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestInspect(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.Run("inspect: show error in case of no args", func() { + test.Machine("inspect").Should().Fail(`Error: No machine name(s) specified and no "default" machine exists.`) + }) +} diff --git a/its/cli/ls_test.go b/its/cli/ls_test.go new file mode 100644 index 00000000..0cc785c9 --- /dev/null +++ b/its/cli/ls_test.go @@ -0,0 +1,178 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestLs(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.Run("setup", func() { + test.Machine("create -d none --url none --engine-label app=1 testmachine5").Should().Succeed() + test.Machine("create -d none --url none --engine-label foo=bar --engine-label app=1 testmachine4").Should().Succeed() + test.Machine("create -d none --url none testmachine3").Should().Succeed() + test.Machine("create -d none --url none testmachine2").Should().Succeed() + test.Machine("create -d none --url none testmachine").Should().Succeed() + }) + + test.Run("ls: filter on label", func() { + test.Machine("ls --filter label=foo=bar").Should().Succeed(). + ContainLines(2). + ContainLine(0, "NAME"). + ContainLine(1, "testmachine4") + }) + + test.Run("ls: mutiple filters on label", func() { + test.Machine("ls --filter label=foo=bar --filter label=app=1").Should().Succeed(). + ContainLines(3). + ContainLine(0, "NAME"). + ContainLine(1, "testmachine4"). + ContainLine(2, "testmachine5") + }) + + test.Run("ls: non-existing filter on label", func() { + test.Machine("ls --filter label=invalid=filter").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + }) + + test.Run("ls: filter on driver", func() { + test.Machine("ls --filter driver=none").Should().Succeed(). + ContainLines(6). + ContainLine(0, "NAME"). + ContainLine(1, "testmachine"). + ContainLine(2, "testmachine2"). + ContainLine(3, "testmachine3"). + ContainLine(4, "testmachine4"). + ContainLine(5, "testmachine5") + }) + + test.Run("ls: filter on driver", func() { + test.Machine("ls -q --filter driver=none").Should().Succeed(). + ContainLines(5). + EqualLine(0, "testmachine"). + EqualLine(1, "testmachine2"). + EqualLine(2, "testmachine3") + }) + + test.Run("ls: filter on state", func() { + test.Machine("ls --filter state=Running").Should().Succeed(). + ContainLines(6). + ContainLine(0, "NAME"). + ContainLine(1, "testmachine"). + ContainLine(2, "testmachine2"). + ContainLine(3, "testmachine3") + + test.Machine("ls -q --filter state=Running").Should().Succeed(). + ContainLines(5). + EqualLine(0, "testmachine"). + EqualLine(1, "testmachine2"). + EqualLine(2, "testmachine3") + + test.Machine("ls --filter state=None").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + + test.Machine("ls --filter state=Paused").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + + test.Machine("ls --filter state=Saved").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + + test.Machine("ls --filter state=Stopped").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + + test.Machine("ls --filter state=Stopping").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + + test.Machine("ls --filter state=Starting").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + + test.Machine("ls --filter state=Error").Should().Succeed(). + ContainLines(1). + ContainLine(0, "NAME") + }) + + test.Run("ls: filter on name", func() { + test.Machine("ls --filter name=testmachine2").Should().Succeed(). + ContainLines(2). + ContainLine(0, "NAME"). + ContainLine(1, "testmachine2") + + test.Machine("ls -q --filter name=testmachine3").Should().Succeed(). + ContainLines(1). + EqualLine(0, "testmachine3") + }) + + test.Run("ls: filter on name with regex", func() { + test.Machine("ls --filter name=^t.*e[3-5]").Should().Succeed(). + ContainLines(4). + ContainLine(0, "NAME"). + ContainLine(1, "testmachine3"). + ContainLine(2, "testmachine4"). + ContainLine(3, "testmachine5") + + test.Machine("ls -q --filter name=^t.*e[45]").Should().Succeed(). + ContainLines(2). + EqualLine(0, "testmachine4"). + EqualLine(1, "testmachine5") + }) + + test.Run("setup swarm", func() { + test.Machine("create -d none --url tcp://127.0.0.1:2375 --swarm --swarm-master --swarm-discovery token://deadbeef testswarm").Should().Succeed() + test.Machine("create -d none --url tcp://127.0.0.1:2375 --swarm --swarm-discovery token://deadbeef testswarm2").Should().Succeed() + test.Machine("create -d none --url tcp://127.0.0.1:2375 --swarm --swarm-discovery token://deadbeef testswarm3").Should().Succeed() + }) + + test.Run("ls: filter on swarm", func() { + test.Machine("ls --filter swarm=testswarm").Should().Succeed(). + ContainLines(4). + ContainLine(0, "NAME"). + ContainLine(1, "testswarm"). + ContainLine(2, "testswarm2"). + ContainLine(3, "testswarm3") + }) + + test.Run("ls: multi filter", func() { + test.Machine("ls -q --filter swarm=testswarm --filter name=^t.*e --filter driver=none --filter state=Running").Should().Succeed(). + ContainLines(3). + EqualLine(0, "testswarm"). + EqualLine(1, "testswarm2"). + EqualLine(2, "testswarm3") + }) + + test.Run("ls: format on driver", func() { + test.Machine("ls --format {{.DriverName}}").Should().Succeed(). + ContainLines(8). + EqualLine(0, "none"). + EqualLine(1, "none"). + EqualLine(2, "none"). + EqualLine(3, "none"). + EqualLine(4, "none"). + EqualLine(5, "none"). + EqualLine(6, "none"). + EqualLine(7, "none") + }) + + test.Run("ls: format on name and driver", func() { + test.Machine("ls --format 'table {{.Name}}: {{.DriverName}}'").Should().Succeed(). + ContainLines(9). + ContainLine(0, "NAME"). + EqualLine(1, "testmachine: none"). + EqualLine(2, "testmachine2: none"). + EqualLine(3, "testmachine3: none"). + EqualLine(4, "testmachine4: none"). + EqualLine(5, "testmachine5: none"). + EqualLine(6, "testswarm: none"). + EqualLine(7, "testswarm2: none"). + EqualLine(8, "testswarm3: none") + }) +} diff --git a/its/cli/status_test.go b/its/cli/status_test.go new file mode 100644 index 00000000..556fc3b4 --- /dev/null +++ b/its/cli/status_test.go @@ -0,0 +1,16 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestStatus(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.Run("status: show error in case of no args", func() { + test.Machine("status").Should().Fail(`Error: No machine name(s) specified and no "default" machine exists.`) + }) +} diff --git a/its/cli/url_test.go b/its/cli/url_test.go new file mode 100644 index 00000000..b8d40044 --- /dev/null +++ b/its/cli/url_test.go @@ -0,0 +1,16 @@ +package cli + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestUrl(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.Run("url: show error in case of no args", func() { + test.Machine("url").Should().Fail(`Error: No machine name(s) specified and no "default" machine exists.`) + }) +} diff --git a/its/tester.go b/its/tester.go new file mode 100644 index 00000000..22c936c9 --- /dev/null +++ b/its/tester.go @@ -0,0 +1,345 @@ +package its + +import ( + "os/exec" + "regexp" + "strings" + "testing" + + "io/ioutil" + + "os" + + "fmt" + + "path/filepath" + "runtime" +) + +var ( + regexpCommandLine = regexp.MustCompile("('[^']*')|(\\S+)") +) + +type IntegrationTest interface { + RequireDriver(driverName string) + + SkipDriver(driverName string) + + SkipDrivers(driverNames ...string) + + ForceDriver(driverName string) + + Run(description string, action func()) + + Cmd(commandLine string) IntegrationTest + + Machine(commandLine string) IntegrationTest + + DriverName() string + + Should() Assertions + + TearDown() +} + +type Assertions interface { + Succeed(messages ...string) Assertions + + Fail(errorMessages ...string) Assertions + + ContainLines(count int) Assertions + + ContainLine(index int, text string) Assertions + + EqualLine(index int, text string) Assertions +} + +func NewTest(t *testing.T) IntegrationTest { + storagePath, _ := ioutil.TempDir("", "docker") + + return &dockerMachineTest{ + t: t, + storagePath: storagePath, + } +} + +type dockerMachineTest struct { + t *testing.T + storagePath string + dockerMachineBinary string + description string + skip bool + rawOutput string + lines []string + err error + fatal bool + failed bool +} + +func (dmt *dockerMachineTest) RequireDriver(driverName string) { + dmt.skipIf(dmt.DriverName() != driverName) +} + +func (dmt *dockerMachineTest) SkipDriver(driverName string) { + dmt.skipIf(dmt.DriverName() == driverName) +} + +func (dmt *dockerMachineTest) SkipDrivers(driverNames ...string) { + for _, driverName := range driverNames { + dmt.skipIf(dmt.DriverName() == driverName) + } +} + +func (dmt *dockerMachineTest) ForceDriver(driverName string) { + os.Setenv("DRIVER", driverName) +} + +func (dmt *dockerMachineTest) skipIf(condition bool) { + if condition { + dmt.skip = true + } +} + +func (dmt *dockerMachineTest) Run(description string, action func()) { + dmt.description = description + dmt.rawOutput = "" + dmt.lines = nil + dmt.err = nil + dmt.failed = false + + if dmt.skip { + fmt.Printf("%s %s\n", yellow("[SKIP]"), description) + } else { + fmt.Printf("%s %s", yellow("[..]"), description) + action() + + if dmt.fatal || dmt.failed { + fmt.Printf("\r%s %s\n", red("[KO]"), description) + } else { + fmt.Printf("\r%s %s\n", green("[OK]"), description) + } + } +} + +func red(message string) string { + if runtime.GOOS == "windows" { + return message + } + return "\033[1;31m" + message + "\033[0m" +} + +func green(message string) string { + if runtime.GOOS == "windows" { + return message + } + return "\033[1;32m" + message + "\033[0m" +} + +func yellow(message string) string { + if runtime.GOOS == "windows" { + return message + } + return "\033[1;33m" + message + "\033[0m" +} + +func (dmt *dockerMachineTest) DriverName() string { + driver := os.Getenv("DRIVER") + if driver != "" { + return driver + } + + return "none" +} + +func (dmt *dockerMachineTest) Should() Assertions { + return dmt +} + +func (dmt *dockerMachineTest) testedBinary() string { + if dmt.dockerMachineBinary != "" { + return dmt.dockerMachineBinary + } + + var binary string + if runtime.GOOS == "windows" { + binary = "docker-machine.exe" + } else { + binary = "docker-machine" + } + + _, file, _, _ := runtime.Caller(0) + dir := filepath.Dir(file) + + for dir != "/" { + path := filepath.Join(dir, "bin", binary) + + _, err := os.Stat(path) + if err == nil { + dmt.dockerMachineBinary = path + return path + } + + dir = filepath.Dir(dir) + } + + if !dmt.fatal { + dmt.fatal = true + dmt.t.Errorf("Binary not found: %s", binary) + } + + return "" +} + +func (dmt *dockerMachineTest) Cmd(commandLine string) IntegrationTest { + if dmt.fatal { + return dmt + } + + commandLine = dmt.replaceDriver(commandLine) + commandLine = dmt.replaceMachinePath(commandLine) + + return dmt.cmd("bash", "-c", commandLine) +} + +func (dmt *dockerMachineTest) Machine(commandLine string) IntegrationTest { + if dmt.fatal { + return dmt + } + + commandLine = dmt.replaceDriver(commandLine) + + return dmt.cmd(dmt.testedBinary(), parseFields(commandLine)...) +} + +func (dmt *dockerMachineTest) cmd(command string, args ...string) IntegrationTest { + cmd := exec.Command(command, args...) + cmd.Env = append(os.Environ(), "MACHINE_STORAGE_PATH="+dmt.storagePath) + + combinedOutput, err := cmd.CombinedOutput() + + dmt.rawOutput = string(combinedOutput) + dmt.lines = strings.Split(strings.TrimSpace(dmt.rawOutput), "\n") + dmt.err = err + + return dmt +} + +func (dmt *dockerMachineTest) replaceMachinePath(commandLine string) string { + return strings.Replace(commandLine, "machine", dmt.testedBinary(), -1) +} + +func (dmt *dockerMachineTest) replaceDriver(commandLine string) string { + return strings.Replace(commandLine, "$DRIVER", dmt.DriverName(), -1) +} + +func parseFields(commandLine string) []string { + fields := regexpCommandLine.FindAllString(commandLine, -1) + + for i := range fields { + if len(fields[i]) > 2 && strings.HasPrefix(fields[i], "'") && strings.HasSuffix(fields[i], "'") { + fields[i] = fields[i][1 : len(fields[i])-1] + } + } + + return fields +} + +func (dmt *dockerMachineTest) TearDown() { + machines := filepath.Join(dmt.storagePath, "machines") + + dirs, _ := ioutil.ReadDir(machines) + for _, dir := range dirs { + dmt.Cmd("machine rm -f " + dir.Name()) + } + + os.RemoveAll(dmt.storagePath) +} + +func (dmt *dockerMachineTest) ContainLines(count int) Assertions { + if dmt.fatal { + return dmt + } + + if count != len(dmt.lines) { + return dmt.failExpected("%d lines but got %d", count, len(dmt.lines)) + } + + return dmt +} + +func (dmt *dockerMachineTest) ContainLine(index int, text string) Assertions { + if dmt.fatal { + return dmt + } + + if index >= len(dmt.lines) { + return dmt.failExpected("at least %d lines\nGot %d", index+1, len(dmt.lines)) + } + + if !strings.Contains(dmt.lines[index], text) { + return dmt.failExpected("line %d to contain '%s'\nGot '%s'", index, text, dmt.lines[index]) + } + + return dmt +} + +func (dmt *dockerMachineTest) EqualLine(index int, text string) Assertions { + if dmt.fatal { + return dmt + } + + if index >= len(dmt.lines) { + return dmt.failExpected("at least %d lines\nGot %d", index+1, len(dmt.lines)) + } + + if text != dmt.lines[index] { + return dmt.failExpected("line %d to be '%s'\nGot '%s'", index, text, dmt.lines[index]) + } + + return dmt +} + +func (dmt *dockerMachineTest) Succeed(messages ...string) Assertions { + if dmt.fatal { + return dmt + } + + if dmt.err != nil { + return dmt.failExpected("to succeed\nFailed with %s\n%s", dmt.err, dmt.rawOutput) + } + + for _, message := range messages { + if !strings.Contains(dmt.rawOutput, message) { + return dmt.failExpected("output to contain '%s'\nGot '%s'", message, dmt.rawOutput) + } + } + + return dmt +} + +func (dmt *dockerMachineTest) Fail(errorMessages ...string) Assertions { + if dmt.fatal { + return dmt + } + + if dmt.err == nil { + return dmt.failExpected("to fail\nGot success\n%s", dmt.rawOutput) + } + + for _, message := range errorMessages { + if !strings.Contains(dmt.rawOutput, message) { + return dmt.failExpected("output to contain '%s'\nGot '%s'", message, dmt.rawOutput) + } + } + + return dmt +} + +func (dmt *dockerMachineTest) failExpected(message string, args ...interface{}) Assertions { + allArgs := append([]interface{}{dmt.description}, args...) + + dmt.failed = true + dmt.t.Errorf("%s\nExpected "+message, allArgs...) + + return dmt +} diff --git a/its/thirdparty/commands_test.go b/its/thirdparty/commands_test.go new file mode 100644 index 00000000..945ece76 --- /dev/null +++ b/its/thirdparty/commands_test.go @@ -0,0 +1,34 @@ +package thirdparty + +import ( + "testing" + + "github.com/docker/machine/its" +) + +func TestThirdPartyCompatibility(t *testing.T) { + test := its.NewTest(t) + defer test.TearDown() + + test.RequireDriver("ci-test") + + test.Run("create", func() { + test.Machine("create -d $DRIVER --url url default").Should().Succeed() + }) + + test.Run("ls", func() { + test.Machine("ls -q").Should().Succeed().ContainLines(1).EqualLine(0, "default") + }) + + test.Run("url", func() { + test.Machine("url default").Should().Succeed("url") + }) + + test.Run("status", func() { + test.Machine("status default").Should().Succeed("Running") + }) + + test.Run("rm", func() { + test.Machine("rm -y default").Should().Succeed() + }) +} diff --git a/test/integration/3rdparty/commands.bats b/test/integration/3rdparty/commands.bats deleted file mode 100644 index 117adb1a..00000000 --- a/test/integration/3rdparty/commands.bats +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -only_if_env DRIVER ci-test - -@test "create" { - run machine create -d $DRIVER --url none default - [ "$status" -eq 0 ] -} - -@test "ls" { - run machine ls -q - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - [[ ${lines[0]} = "default" ]] -} - -@test "url" { - run machine url default - [ "$status" -eq 0 ] - [[ ${output} == *"none"* ]] -} - -@test "status" { - run machine status default - [ "$status" -eq 0 ] - [[ ${output} == *"Running"* ]] -} - -@test "rm" { - run machine rm -y default - [ "$status" -eq 0 ] -} diff --git a/test/integration/cli/create-rm.bats b/test/integration/cli/create-rm.bats deleted file mode 100644 index ecac1403..00000000 --- a/test/integration/cli/create-rm.bats +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -@test "bogus: non-existent driver fails 'machine create -d bogus bogus'" { - run machine create -d bogus bogus - [ "$status" -eq 1 ] - [[ ${lines[0]} == "Driver \"bogus\" not found. Do you have the plugin binary accessible in your PATH?" ]] -} - -@test "none: create with no name fails 'machine create -d none'" { - run machine create -d none - last=$((${#lines[@]} - 1)) - [ "$status" -eq 1 ] - [[ ${lines[$last]} == "Error: No machine name specified" ]] -} - -@test "none: create with invalid name fails 'machine create -d none --url none ∞'" { - run machine create -d none --url none ∞ - last=$((${#lines[@]} - 1)) - [ "$status" -eq 1 ] - [[ ${lines[$last]} == "Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -" ]] -} - -@test "none: create with invalid name fails 'machine create -d none --url none -'" { - run machine create -d none --url none - - [ "$status" -eq 1 ] - [[ ${lines[0]} == "Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -" ]] -} - -@test "none: create with invalid name fails 'machine create -d none --url none .'" { - run machine create -d none --url none . - [ "$status" -eq 1 ] - [[ ${lines[0]} == "Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -" ]] -} - -@test "none: create with invalid name fails 'machine create -d none --url none ..'" { - run machine create -d none --url none .. - [ "$status" -eq 1 ] - [[ ${lines[0]} == "Error creating machine: Invalid hostname specified. Allowed hostname chars are: 0-9a-zA-Z . -" ]] -} - -@test "none: create with weird but valid name succeeds 'machine create -d none --url none a'" { - run machine create -d none --url none a - [ "$status" -eq 0 ] -} - -@test "none: name is case insensitive 'machine create -d none --url none A'" { - skip - run machine create -d none --url none A - [ "$status" -eq 1 ] - [[ ${lines[0]} == "Error creating machine: Machine A already exists" ]] -} - -@test "none: fail with extra argument 'machine create -d none --url none a extra'" { - run machine create -d none --url none a extra - [ "$status" -eq 1 ] - [[ ${lines[0]} == "Invalid command line. Found extra arguments [extra]" ]] -} - -@test "none: create with weird but valid name succeeds 'machine create -d none --url none 0'" { - run machine create -d none --url none 0 - [ "$status" -eq 0 ] -} - -@test "none: rm with no name fails 'machine rm'" { - run machine rm -y - last=$(expr ${#lines[@]} - 1) - [ "$status" -eq 1 ] - [[ ${lines[$last]} == "Error: Expected to get one or more machine names as arguments" ]] -} - -@test "none: rm non existent machine fails 'machine rm ∞'" { - run machine rm ∞ -y - [ "$status" -eq 1 ] - [[ ${lines[1]} == "Error removing host \"∞\": Host does not exist: \"∞\"" ]] -} - -@test "none: rm is successful 'machine rm 0'" { - run machine rm 0 -y - [ "$status" -eq 0 ] -} - -@test "none: rm ask user confirmation when -y is not provided 'echo y | machine rm ba'" { - run machine create -d none --url none ba - [ "$status" -eq 0 ] - run bash -c "echo y | machine rm ba" - [ "$status" -eq 0 ] -} - -@test "none: rm deny user confirmation when -y is not provided 'echo n | machine rm ab'" { - run machine create -d none --url none ab - [ "$status" -eq 0 ] - run bash -c "echo n | machine rm ab" - [ "$status" -eq 0 ] -} - -@test "none: rm never prompt user confirmation with -f is provided 'echo n | machine rm -f ab'" { - run machine create -d none --url none c - [ "$status" -eq 0 ] - run bash -c "machine rm -f c" - [ "$status" -eq 0 ] - [[ ${lines[1]} == "Successfully removed c" ]] -} - -# Should be replaced by the test below -@test "none: rm is successful 'machine rm a'" { - run machine rm a -y - [ "$status" -eq 0 ] -} - -@test "none: rm is case insensitive 'machine rm A'" { - skip - run machine rm A -y - [ "$status" -eq 0 ] -} diff --git a/test/integration/cli/driver_help.bats b/test/integration/cli/driver_help.bats deleted file mode 100644 index 526a2133..00000000 --- a/test/integration/cli/driver_help.bats +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -@test "no --help flag or command specified" { - [[ $(machine create -d ${DRIVER} 2>&1 | grep $DRIVER | wc -l) -gt 0 ]] -} - -@test "-h flag specified" { - [[ $(machine create -d ${DRIVER} 2>&1 -h | grep $DRIVER | wc -l) -gt 0 ]] -} - -@test "--help flag specified" { - [[ $(machine create -d ${DRIVER} --help 2>&1 | grep $DRIVER | wc -l) -gt 0 ]] -} diff --git a/test/integration/cli/help.bats b/test/integration/cli/help.bats deleted file mode 100644 index 58376e7d..00000000 --- a/test/integration/cli/help.bats +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -@test "cli: show info" { - run machine - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "Usage:" ]] - [[ ${lines[1]} =~ "Create and manage machines running Docker" ]] -} - -@test "cli: show active help" { - run machine active -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine active" ]] -} - -@test "cli: show config help" { - run machine config -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine config" ]] -} - -@test "cli: show create help" { - run machine create -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine create" ]] -} - -@test "cli: show env help" { - run machine env -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine env" ]] -} - -@test "cli: show inspect help" { - run machine inspect -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine inspect" ]] -} - -@test "cli: show ip help" { - run machine ip -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine ip" ]] -} - -@test "cli: show kill help" { - run machine kill -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine kill" ]] -} - -@test "cli: show ls help" { - run machine ls -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine ls" ]] -} - -@test "cli: show regenerate-certs help" { - run machine regenerate-certs -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine regenerate-certs" ]] -} - -@test "cli: show restart help" { - run machine restart -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine restart" ]] -} - -@test "cli: show rm help" { - run machine rm -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine rm" ]] -} - -@test "cli: show scp help" { - run machine scp -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine scp" ]] -} - -@test "cli: show ssh help" { - run machine ssh -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine ssh" ]] -} - -@test "cli: show start help" { - run machine start -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine start" ]] -} - -@test "cli: show status help" { - run machine status -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine status" ]] -} - -@test "cli: show stop help" { - run machine stop -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine stop" ]] -} - -@test "cli: show upgrade help" { - run machine upgrade -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine upgrade" ]] -} - -@test "cli: show url help" { - run machine url -h - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "machine url" ]] -} - -@test "flag: show version" { - run machine -v - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "version" ]] -} - -@test "flag: show help" { - run machine --help - [ "$status" -eq 0 ] - [[ ${lines[0]} =~ "Usage:" ]] -} diff --git a/test/integration/cli/inspect.bats b/test/integration/cli/inspect.bats deleted file mode 100644 index d1674442..00000000 --- a/test/integration/cli/inspect.bats +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -@test "inspect: show error in case of no args" { - run machine inspect - [ "$status" -eq 1 ] - [[ ${output} == *"Error: No machine name(s) specified and no \"default\" machine exists."* ]] -} diff --git a/test/integration/cli/ls.bats b/test/integration/cli/ls.bats deleted file mode 100644 index 482deb26..00000000 --- a/test/integration/cli/ls.bats +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -setup () { - machine create -d none --url none --engine-label app=1 testmachine5 - machine create -d none --url none --engine-label foo=bar --engine-label app=1 testmachine4 - machine create -d none --url none testmachine3 - machine create -d none --url none testmachine2 - machine create -d none --url none testmachine -} - -teardown () { - machine rm -y $(machine ls -q) - echo_to_log -} - -bootstrap_swarm () { - machine create -d none --url tcp://127.0.0.1:2375 --swarm --swarm-master --swarm-discovery token://deadbeef testswarm - machine create -d none --url tcp://127.0.0.1:2375 --swarm --swarm-discovery token://deadbeef testswarm2 - machine create -d none --url tcp://127.0.0.1:2375 --swarm --swarm-discovery token://deadbeef testswarm3 -} - -@test "ls: filter on label 'machine ls --filter label=foo=bar'" { - run machine ls --filter label=foo=bar - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 2 ]] - [[ ${lines[1]} =~ "testmachine4" ]] -} - -@test "ls: mutiple filters on label 'machine ls --filter label=foo=bar --filter label=app=1'" { - run machine ls --filter label=foo=bar --filter label=app=1 - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 3 ]] - [[ ${lines[1]} =~ "testmachine4" ]] - [[ ${lines[2]} =~ "testmachine5" ]] -} - -@test "ls: non-existing filter on label 'machine ls --filter label=invalid=filter'" { - run machine ls --filter label=invalid=filter - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] -} - -@test "ls: filter on driver 'machine ls --filter driver=none'" { - run machine ls --filter driver=none - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 6 ]] - [[ ${lines[1]} =~ "testmachine" ]] - [[ ${lines[2]} =~ "testmachine2" ]] - [[ ${lines[3]} =~ "testmachine3" ]] - [[ ${lines[4]} =~ "testmachine4" ]] - [[ ${lines[5]} =~ "testmachine5" ]] -} - -@test "ls: filter on driver 'machine ls -q --filter driver=none'" { - run machine ls -q --filter driver=none - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 5 ]] - [[ ${lines[0]} == "testmachine" ]] - [[ ${lines[1]} == "testmachine2" ]] - [[ ${lines[2]} == "testmachine3" ]] -} - -@test "ls: filter on state 'machine ls --filter state=\"Running\"'" { - # Default state for 'none' driver is "Running" - run machine ls --filter state="Running" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 6 ]] - [[ ${lines[1]} =~ "testmachine" ]] - [[ ${lines[2]} =~ "testmachine2" ]] - [[ ${lines[3]} =~ "testmachine3" ]] - - # TODO: have machines in that state - run machine ls --filter state="None" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - run machine ls --filter state="Paused" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - run machine ls --filter state="Saved" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - run machine ls --filter state="Stopped" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - run machine ls --filter state="Stopping" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - run machine ls --filter state="Starting" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - run machine ls --filter state="Error" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] -} - -@test "ls: filter on state 'machine ls -q --filter state=\"Running\"'" { - run machine ls -q --filter state="Running" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 5 ]] - [[ ${lines[0]} == "testmachine" ]] - [[ ${lines[1]} == "testmachine2" ]] - [[ ${lines[2]} == "testmachine3" ]] -} - -@test "ls: filter on name 'machine ls --filter name=\"testmachine2\"'" { - run machine ls --filter name="testmachine2" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 2 ]] - [[ ${lines[1]} =~ "testmachine2" ]] -} - -@test "ls: filter on name 'machine ls -q --filter name=\"testmachine2\"'" { - run machine ls -q --filter name="testmachine2" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 1 ]] - [[ ${lines[0]} == "testmachine2" ]] -} - -@test "ls: filter on name with regex 'machine ls --filter name=\"^t.*e\"'" { - run machine ls --filter name="^t.*e" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 6 ]] - [[ ${lines[1]} =~ "testmachine" ]] - [[ ${lines[2]} =~ "testmachine2" ]] - [[ ${lines[3]} =~ "testmachine3" ]] -} - -@test "ls: filter on name with regex 'machine ls -q --filter name=\"^t.*e\"'" { - run machine ls -q --filter name="^t.*e" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 5 ]] - [[ ${lines[0]} == "testmachine" ]] - [[ ${lines[1]} == "testmachine2" ]] - [[ ${lines[2]} == "testmachine3" ]] -} - -@test "ls: filter on swarm 'machine ls --filter swarm=testswarm" { - bootstrap_swarm - run machine ls --filter swarm=testswarm - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 4 ]] - [[ ${lines[1]} =~ "testswarm" ]] - [[ ${lines[2]} =~ "testswarm2" ]] - [[ ${lines[3]} =~ "testswarm3" ]] -} - -@test "ls: filter on swarm 'machine ls -q --filter swarm=testswarm" { - bootstrap_swarm - run machine ls -q --filter swarm=testswarm - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 3 ]] - [[ ${lines[0]} == "testswarm" ]] - [[ ${lines[1]} == "testswarm2" ]] - [[ ${lines[2]} == "testswarm3" ]] -} - -@test "ls: multi filter 'machine ls -q --filter swarm=testswarm --filter name=\"^t.*e\" --filter driver=none --filter state=\"Running\"'" { - bootstrap_swarm - run machine ls -q --filter swarm=testswarm --filter name="^t.*e" --filter driver=none --filter state="Running" - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 3 ]] - [[ ${lines[0]} == "testswarm" ]] - [[ ${lines[1]} == "testswarm2" ]] - [[ ${lines[2]} == "testswarm3" ]] -} - -@test "ls: format on driver 'machine ls --format '{{ .DriverName }}'" { - run machine ls --format '{{ .DriverName }}' - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 5 ]] - [[ ${lines[0]} =~ "none" ]] - [[ ${lines[1]} =~ "none" ]] - [[ ${lines[2]} =~ "none" ]] - [[ ${lines[3]} =~ "none" ]] - [[ ${lines[4]} =~ "none" ]] -} - - -@test "ls: format on name and driver 'machine ls --format 'table {{ .Name}}: {{ .DriverName }}'" { - run machine ls --format 'table {{ .Name}}: {{ .DriverName }}' - [ "$status" -eq 0 ] - [[ ${#lines[@]} == 6 ]] - [[ ${lines[1]} =~ "testmachine: none" ]] - [[ ${lines[2]} =~ "testmachine2: none" ]] - [[ ${lines[3]} =~ "testmachine3: none" ]] - [[ ${lines[4]} =~ "testmachine4: none" ]] - [[ ${lines[5]} =~ "testmachine5: none" ]] -} - diff --git a/test/integration/cli/status.bats b/test/integration/cli/status.bats deleted file mode 100644 index b3e8387e..00000000 --- a/test/integration/cli/status.bats +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -@test "status: show error in case of no args" { - run machine status - [ "$status" -eq 1 ] - [[ ${output} == *"Error: No machine name(s) specified and no \"default\" machine exists."* ]] -} diff --git a/test/integration/cli/url.bats b/test/integration/cli/url.bats deleted file mode 100644 index 671fd731..00000000 --- a/test/integration/cli/url.bats +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bats - -load ${BASE_TEST_DIR}/helpers.bash - -@test "url: show error in case of no args" { - run machine url - [ "$status" -eq 1 ] - [[ ${output} == *"Error: No machine name(s) specified and no \"default\" machine exists."* ]] -}