Merge pull request #25426 from dnephin/better-int-testing-cmd
Remove duplicate RunCommand functions used for integration-cli
This commit is contained in:
commit
b29558ed5d
24 changed files with 627 additions and 1049 deletions
|
@ -5,13 +5,13 @@ import (
|
|||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
|
@ -89,15 +89,12 @@ func (s *DockerSuite) TestApiDockerApiVersion(c *check.C) {
|
|||
defer server.Close()
|
||||
|
||||
// Test using the env var first
|
||||
cmd := exec.Command(dockerBinary, "-H="+server.URL[7:], "version")
|
||||
cmd.Env = appendBaseEnv(false, "DOCKER_API_VERSION=xxx")
|
||||
out, _, _ := runCommandWithOutput(cmd)
|
||||
|
||||
c.Assert(svrVersion, check.Equals, "/vxxx/version")
|
||||
|
||||
if !strings.Contains(out, "API version: xxx") {
|
||||
c.Fatalf("Out didn't have 'xxx' for the API version, had:\n%s", out)
|
||||
}
|
||||
result := icmd.RunCmd(icmd.Cmd{
|
||||
Command: binaryWithArgs("-H="+server.URL[7:], "version"),
|
||||
Env: appendBaseEnv(false, "DOCKER_API_VERSION=xxx"),
|
||||
})
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{Out: "API version: xxx", ExitCode: 1})
|
||||
c.Assert(svrVersion, check.Equals, "/vxxx/version", check.Commentf("%s", result.Compare(icmd.Success)))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestApiErrorJSON(c *check.C) {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
|
@ -161,7 +161,11 @@ func (s *DockerSuite) TestAttachPausedContainer(c *check.C) {
|
|||
defer unpauseAllContainers()
|
||||
dockerCmd(c, "run", "-d", "--name=test", "busybox", "top")
|
||||
dockerCmd(c, "pause", "test")
|
||||
out, _, err := dockerCmdWithError("attach", "test")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "You cannot attach to a paused container, unpause it first")
|
||||
|
||||
result := dockerCmdWithResult("attach", "test")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
Error: "exit status 1",
|
||||
ExitCode: 1,
|
||||
Err: "You cannot attach to a paused container, unpause it first",
|
||||
})
|
||||
}
|
||||
|
|
|
@ -56,7 +56,6 @@ func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
|
||||
|
||||
name := "detachtest"
|
||||
|
||||
cpty, tty, err := pty.Open()
|
||||
|
@ -80,7 +79,11 @@ func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
|
|||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
c.Assert(err, check.IsNil)
|
||||
if err != nil {
|
||||
buff := make([]byte, 200)
|
||||
tty.Read(buff)
|
||||
c.Fatalf("%s: %s", err, buff)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
c.Fatal("timeout while detaching")
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/docker/docker/builder/dockerfile/command"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
@ -240,7 +241,7 @@ func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) {
|
|||
|
||||
envResult := []string{}
|
||||
|
||||
if err = unmarshalJSON([]byte(res), &envResult); err != nil {
|
||||
if err = json.Unmarshal([]byte(res), &envResult); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -297,7 +298,7 @@ func (s *DockerSuite) TestBuildHandleEscapes(c *check.C) {
|
|||
|
||||
res := inspectFieldJSON(c, name, "Config.Volumes")
|
||||
|
||||
if err = unmarshalJSON([]byte(res), &result); err != nil {
|
||||
if err = json.Unmarshal([]byte(res), &result); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -320,7 +321,7 @@ func (s *DockerSuite) TestBuildHandleEscapes(c *check.C) {
|
|||
|
||||
res = inspectFieldJSON(c, name, "Config.Volumes")
|
||||
|
||||
if err = unmarshalJSON([]byte(res), &result); err != nil {
|
||||
if err = json.Unmarshal([]byte(res), &result); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -347,7 +348,7 @@ func (s *DockerSuite) TestBuildHandleEscapes(c *check.C) {
|
|||
|
||||
res = inspectFieldJSON(c, name, "Config.Volumes")
|
||||
|
||||
if err = unmarshalJSON([]byte(res), &result); err != nil {
|
||||
if err = json.Unmarshal([]byte(res), &result); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1705,7 @@ func (s *DockerSuite) TestBuildWithVolumes(c *check.C) {
|
|||
}
|
||||
res := inspectFieldJSON(c, name, "Config.Volumes")
|
||||
|
||||
err = unmarshalJSON([]byte(res), &result)
|
||||
err = json.Unmarshal([]byte(res), &result)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
@ -1833,9 +1834,9 @@ func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
|
|||
ADD wc2 c:/wc2
|
||||
WORKDIR c:/
|
||||
RUN sh -c "[ $(cat c:/wc1) = 'hellowc1' ]"
|
||||
RUN sh -c "[ $(cat c:/wc2) = 'worldwc2' ]"
|
||||
RUN sh -c "[ $(cat c:/wc2) = 'worldwc2' ]"
|
||||
|
||||
# Trailing slash on COPY/ADD, Windows-style path.
|
||||
# Trailing slash on COPY/ADD, Windows-style path.
|
||||
WORKDIR /wd1
|
||||
COPY wd1 c:/wd1/
|
||||
WORKDIR /wd2
|
||||
|
@ -5063,13 +5064,11 @@ func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) {
|
|||
filepath.Join(ctx, "dockerfile1"),
|
||||
filepath.Join(ctx, "dockerfile2"),
|
||||
} {
|
||||
out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")
|
||||
if err == nil {
|
||||
c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out)
|
||||
}
|
||||
if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") {
|
||||
c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out)
|
||||
}
|
||||
result := dockerCmdWithResult("build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
Err: "must be within the build context",
|
||||
ExitCode: 1,
|
||||
})
|
||||
deleteImages(name)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/go-check/check"
|
||||
|
@ -193,7 +194,7 @@ func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) {
|
|||
}
|
||||
|
||||
// Get the exit status of `docker build`, check it exited because killed.
|
||||
if err := buildCmd.Wait(); err != nil && !isKilled(err) {
|
||||
if err := buildCmd.Wait(); err != nil && !integration.IsKilled(err) {
|
||||
c.Fatalf("wait failed during build run: %T %s", err, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
|
@ -908,9 +909,8 @@ func (s *DockerDaemonSuite) TestDaemonDefaultNetworkInvalidClusterConfig(c *chec
|
|||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Start daemon with docker0 bridge
|
||||
ifconfigCmd := exec.Command("ifconfig", defaultNetworkBridge)
|
||||
_, err = runCommand(ifconfigCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
result := icmd.RunCommand("ifconfig", defaultNetworkBridge)
|
||||
c.Assert(result, icmd.Matches, icmd.Success)
|
||||
|
||||
err = d.Restart(fmt.Sprintf("--cluster-store=%s", discoveryBackend))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
@ -2235,7 +2235,6 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *che
|
|||
|
||||
pid, err := s.d.Cmd("inspect", "-f", "{{.State.Pid}}", cid)
|
||||
t.Assert(err, check.IsNil)
|
||||
pid = strings.TrimSpace(pid)
|
||||
|
||||
// pause the container
|
||||
if _, err := s.d.Cmd("pause", cid); err != nil {
|
||||
|
@ -2248,19 +2247,18 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *che
|
|||
}
|
||||
|
||||
// resume the container
|
||||
runCmd := exec.Command(ctrBinary, "--address", "unix:///var/run/docker/libcontainerd/docker-containerd.sock", "containers", "resume", cid)
|
||||
if out, ec, err := runCommandWithOutput(runCmd); err != nil {
|
||||
t.Fatalf("Failed to run ctr, ExitCode: %d, err: '%v' output: '%s' cid: '%s'\n", ec, err, out, cid)
|
||||
}
|
||||
result := icmd.RunCommand(
|
||||
ctrBinary,
|
||||
"--address", "unix:///var/run/docker/libcontainerd/docker-containerd.sock",
|
||||
"containers", "resume", cid)
|
||||
t.Assert(result, icmd.Matches, icmd.Success)
|
||||
|
||||
// Give time to containerd to process the command if we don't
|
||||
// the resume event might be received after we do the inspect
|
||||
pidCmd := exec.Command("kill", "-0", pid)
|
||||
_, ec, _ := runCommandWithOutput(pidCmd)
|
||||
for ec == 0 {
|
||||
time.Sleep(1 * time.Second)
|
||||
_, ec, _ = runCommandWithOutput(pidCmd)
|
||||
}
|
||||
waitAndAssert(t, defaultReconciliationTimeout, func(*check.C) (interface{}, check.CommentInterface) {
|
||||
result := icmd.RunCommand("kill", "-0", strings.TrimSpace(pid))
|
||||
return result.ExitCode, nil
|
||||
}, checker.Equals, 0)
|
||||
|
||||
// restart the daemon
|
||||
if err := s.d.Start("--live-restore"); err != nil {
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/daemon/events/testutils"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
|
@ -57,11 +58,14 @@ func (s *DockerSuite) TestEventsUntag(c *check.C) {
|
|||
dockerCmd(c, "tag", image, "utest:tag2")
|
||||
dockerCmd(c, "rmi", "utest:tag1")
|
||||
dockerCmd(c, "rmi", "utest:tag2")
|
||||
eventsCmd := exec.Command(dockerBinary, "events", "--since=1")
|
||||
out, exitCode, _, err := runCommandWithOutputForDuration(eventsCmd, time.Duration(time.Millisecond*2500))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(exitCode, checker.Equals, 0, check.Commentf("Failed to get events"))
|
||||
events := strings.Split(out, "\n")
|
||||
|
||||
result := icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "events", "--since=1"},
|
||||
Timeout: time.Millisecond * 2500,
|
||||
})
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
|
||||
|
||||
events := strings.Split(result.Stdout(), "\n")
|
||||
nEvents := len(events)
|
||||
// The last element after the split above will be an empty string, so we
|
||||
// get the two elements before the last, which are the untags we're
|
||||
|
@ -275,8 +279,8 @@ func (s *DockerSuite) TestEventsImageLoad(c *check.C) {
|
|||
c.Assert(noImageID, checker.Equals, "", check.Commentf("Should not have any image"))
|
||||
dockerCmd(c, "load", "-i", "saveimg.tar")
|
||||
|
||||
cmd := exec.Command("rm", "-rf", "saveimg.tar")
|
||||
runCommand(cmd)
|
||||
result := icmd.RunCommand("rm", "-rf", "saveimg.tar")
|
||||
c.Assert(result, icmd.Matches, icmd.Success)
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-q", "--no-trunc", myImageName)
|
||||
imageID := strings.TrimSpace(out)
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
|
@ -122,10 +123,8 @@ func (s *DockerSuite) TestExecEnv(c *check.C) {
|
|||
func (s *DockerSuite) TestExecExitStatus(c *check.C) {
|
||||
runSleepingContainer(c, "-d", "--name", "top")
|
||||
|
||||
// Test normal (non-detached) case first
|
||||
cmd := exec.Command(dockerBinary, "exec", "top", "sh", "-c", "exit 23")
|
||||
ec, _ := runCommand(cmd)
|
||||
c.Assert(ec, checker.Equals, 23)
|
||||
result := icmd.RunCommand(dockerBinary, "exec", "top", "sh", "-c", "exit 23")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{ExitCode: 23, Error: "exit status 23"})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
|
||||
|
|
|
@ -227,7 +227,7 @@ func (s *DockerSuite) TestInspectBindMountPoint(c *check.C) {
|
|||
vol := inspectFieldJSON(c, "test", "Mounts")
|
||||
|
||||
var mp []types.MountPoint
|
||||
err := unmarshalJSON([]byte(vol), &mp)
|
||||
err := json.Unmarshal([]byte(vol), &mp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// check that there is only one mountpoint
|
||||
|
@ -253,7 +253,7 @@ func (s *DockerSuite) TestInspectNamedMountPoint(c *check.C) {
|
|||
vol := inspectFieldJSON(c, "test", "Mounts")
|
||||
|
||||
var mp []types.MountPoint
|
||||
err := unmarshalJSON([]byte(vol), &mp)
|
||||
err := json.Unmarshal([]byte(vol), &mp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// check that there is only one mountpoint
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
@ -97,7 +98,7 @@ func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) {
|
|||
dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top")
|
||||
links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links")
|
||||
|
||||
err := unmarshalJSON([]byte(links), &result)
|
||||
err := json.Unmarshal([]byte(links), &result)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
output := convertSliceOfStringsToMap(result)
|
||||
|
@ -116,7 +117,7 @@ func (s *DockerSuite) TestLinksInspectLinksStopped(c *check.C) {
|
|||
dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
|
||||
links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links")
|
||||
|
||||
err := unmarshalJSON([]byte(links), &result)
|
||||
err := json.Unmarshal([]byte(links), &result)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
output := convertSliceOfStringsToMap(result)
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/engine-api/types"
|
||||
|
@ -477,27 +478,33 @@ func (s *DockerSuite) TestDockerNetworkInspectWithID(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) {
|
||||
out, _ := dockerCmd(c, "network", "inspect", "host", "none")
|
||||
result := dockerCmdWithResult("network", "inspect", "host", "none")
|
||||
c.Assert(result, icmd.Matches, icmd.Success)
|
||||
|
||||
networkResources := []types.NetworkResource{}
|
||||
err := json.Unmarshal([]byte(out), &networkResources)
|
||||
err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(networkResources, checker.HasLen, 2)
|
||||
|
||||
// Should print an error, return an exitCode 1 *but* should print the host network
|
||||
out, exitCode, err := dockerCmdWithError("network", "inspect", "host", "nonexistent")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(exitCode, checker.Equals, 1)
|
||||
c.Assert(out, checker.Contains, "Error: No such network: nonexistent")
|
||||
result = dockerCmdWithResult("network", "inspect", "host", "nonexistent")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "Error: No such network: nonexistent",
|
||||
Out: "host",
|
||||
})
|
||||
|
||||
networkResources = []types.NetworkResource{}
|
||||
inspectOut := strings.SplitN(out, "\nError: No such network: nonexistent\n", 2)[0]
|
||||
err = json.Unmarshal([]byte(inspectOut), &networkResources)
|
||||
err = json.Unmarshal([]byte(result.Stdout()), &networkResources)
|
||||
c.Assert(networkResources, checker.HasLen, 1)
|
||||
|
||||
// Should print an error and return an exitCode, nothing else
|
||||
out, exitCode, err = dockerCmdWithError("network", "inspect", "nonexistent")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(exitCode, checker.Equals, 1)
|
||||
c.Assert(out, checker.Contains, "Error: No such network: nonexistent")
|
||||
result = dockerCmdWithResult("network", "inspect", "nonexistent")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "Error: No such network: nonexistent",
|
||||
Out: "[]",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
@ -204,8 +205,11 @@ func (s *DockerSuite) TestPsListContainersFilterStatus(c *check.C) {
|
|||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, secondID)
|
||||
|
||||
out, _, _ = dockerCmdWithTimeout(time.Second*60, "ps", "-a", "-q", "--filter=status=rubbish")
|
||||
c.Assert(out, checker.Contains, "Unrecognised filter value for status", check.Commentf("Expected error response due to invalid status filter output: %q", out))
|
||||
result := dockerCmdWithTimeout(time.Second*60, "ps", "-a", "-q", "--filter=status=rubbish")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "Unrecognised filter value for status",
|
||||
})
|
||||
|
||||
// Windows doesn't support pausing of containers
|
||||
if daemonPlatform != "windows" {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
@ -61,9 +62,11 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
|
|||
name := inspectField(c, newName, "Name")
|
||||
c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container %s", name))
|
||||
|
||||
name, err := inspectFieldWithError("first_name", "Name")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(name))
|
||||
c.Assert(err.Error(), checker.Contains, "No such container, image or task: first_name")
|
||||
result := dockerCmdWithResult("inspect", "-f={{.Name}}", "first_name")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "No such container, image or task: first_name",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRenameInvalidName(c *check.C) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -20,6 +21,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
|
@ -1855,32 +1857,18 @@ func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) {
|
|||
// Test run -i --restart xxx doesn't hang
|
||||
func (s *DockerSuite) TestRunInteractiveWithRestartPolicy(c *check.C) {
|
||||
name := "test-inter-restart"
|
||||
runCmd := exec.Command(dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh")
|
||||
|
||||
stdin, err := runCmd.StdinPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = runCmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(waitRun(name), check.IsNil)
|
||||
|
||||
_, err = stdin.Write([]byte("exit 11\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
finish := make(chan error)
|
||||
go func() {
|
||||
finish <- runCmd.Wait()
|
||||
close(finish)
|
||||
result := icmd.StartCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh"},
|
||||
Stdin: bytes.NewBufferString("exit 11"),
|
||||
})
|
||||
c.Assert(result.Error, checker.IsNil)
|
||||
defer func() {
|
||||
dockerCmdWithResult("stop", name).Assert(c, icmd.Success)
|
||||
}()
|
||||
delay := 10 * time.Second
|
||||
select {
|
||||
case <-finish:
|
||||
case <-time.After(delay):
|
||||
c.Fatal("run -i --restart hangs")
|
||||
}
|
||||
|
||||
c.Assert(waitRun(name), check.IsNil)
|
||||
dockerCmd(c, "stop", name)
|
||||
result = icmd.WaitOnCmd(10*time.Second, result)
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{ExitCode: 11})
|
||||
}
|
||||
|
||||
// Test for #2267
|
||||
|
@ -2397,7 +2385,7 @@ func (s *DockerSuite) TestRunAllowPortRangeThroughExpose(c *check.C) {
|
|||
id := strings.TrimSpace(out)
|
||||
portstr := inspectFieldJSON(c, id, "NetworkSettings.Ports")
|
||||
var ports nat.PortMap
|
||||
if err := unmarshalJSON([]byte(portstr), &ports); err != nil {
|
||||
if err := json.Unmarshal([]byte(portstr), &ports); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
for port, binding := range ports {
|
||||
|
@ -2827,7 +2815,7 @@ func (s *DockerSuite) TestRunAllowPortRangeThroughPublish(c *check.C) {
|
|||
portstr := inspectFieldJSON(c, id, "NetworkSettings.Ports")
|
||||
|
||||
var ports nat.PortMap
|
||||
err := unmarshalJSON([]byte(portstr), &ports)
|
||||
err := json.Unmarshal([]byte(portstr), &ports)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to unmarshal: %v", portstr))
|
||||
for port, binding := range ports {
|
||||
portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0])
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
|
@ -55,14 +56,18 @@ func (s *DockerSuite) TestVolumeCliInspectMulti(c *check.C) {
|
|||
dockerCmd(c, "volume", "create", "--name", "test2")
|
||||
dockerCmd(c, "volume", "create", "--name", "not-shown")
|
||||
|
||||
out, _, err := dockerCmdWithError("volume", "inspect", "--format='{{ .Name }}'", "test1", "test2", "doesntexist", "not-shown")
|
||||
c.Assert(err, checker.NotNil)
|
||||
result := dockerCmdWithResult("volume", "inspect", "--format={{ .Name }}", "test1", "test2", "doesntexist", "not-shown")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "No such volume: doesntexist",
|
||||
})
|
||||
|
||||
out := result.Stdout()
|
||||
outArr := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(outArr), check.Equals, 3, check.Commentf("\n%s", out))
|
||||
c.Assert(len(outArr), check.Equals, 2, check.Commentf("\n%s", out))
|
||||
|
||||
c.Assert(out, checker.Contains, "test1")
|
||||
c.Assert(out, checker.Contains, "test2")
|
||||
c.Assert(out, checker.Contains, "Error: No such volume: doesntexist")
|
||||
c.Assert(out, checker.Not(checker.Contains), "not-shown")
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
@ -401,10 +402,11 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
|
|||
c.Assert(waitRun("second"), check.IsNil)
|
||||
|
||||
// access outside of the network should fail
|
||||
_, _, err := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
|
||||
c.Assert(err, check.NotNil)
|
||||
result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
|
||||
|
||||
// intra-network communications should succeed
|
||||
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
|
@ -440,10 +442,10 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
|
|||
c.Assert(waitRun("second"), check.IsNil)
|
||||
|
||||
// access outside of the network should fail
|
||||
_, _, err := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
|
||||
c.Assert(err, check.NotNil)
|
||||
result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
|
||||
// intra-network communications should succeed
|
||||
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
|
@ -481,10 +483,10 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
|
|||
c.Assert(waitRun("second"), check.IsNil)
|
||||
|
||||
// access outside of the network should fail
|
||||
_, _, err := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
|
||||
c.Assert(err, check.NotNil)
|
||||
result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
|
||||
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
|
||||
// intra-network communications should succeed
|
||||
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/httputils"
|
||||
"github.com/docker/docker/pkg/integration"
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
"github.com/docker/engine-api/types"
|
||||
|
@ -228,16 +228,9 @@ func readBody(b io.ReadCloser) ([]byte, error) {
|
|||
return ioutil.ReadAll(b)
|
||||
}
|
||||
|
||||
func deleteContainer(container string) error {
|
||||
container = strings.TrimSpace(strings.Replace(container, "\n", " ", -1))
|
||||
rmArgs := strings.Split(fmt.Sprintf("rm -fv %v", container), " ")
|
||||
exitCode, err := runCommand(exec.Command(dockerBinary, rmArgs...))
|
||||
// set error manually if not set
|
||||
if exitCode != 0 && err == nil {
|
||||
err = fmt.Errorf("failed to remove container: `docker rm` exit is non-zero")
|
||||
}
|
||||
|
||||
return err
|
||||
func deleteContainer(container ...string) error {
|
||||
result := icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, container...)...)
|
||||
return result.Compare(icmd.Success)
|
||||
}
|
||||
|
||||
func getAllContainers() (string, error) {
|
||||
|
@ -256,13 +249,15 @@ func deleteAllContainers() error {
|
|||
fmt.Println(containers)
|
||||
return err
|
||||
}
|
||||
|
||||
if containers != "" {
|
||||
if err = deleteContainer(containers); err != nil {
|
||||
return err
|
||||
}
|
||||
if containers == "" {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
err = deleteContainer(strings.Split(strings.TrimSpace(containers), "\n")...)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func deleteAllNetworks() error {
|
||||
|
@ -398,13 +393,7 @@ func getSliceOfPausedContainers() ([]string, error) {
|
|||
}
|
||||
|
||||
func unpauseContainer(container string) error {
|
||||
unpauseCmd := exec.Command(dockerBinary, "unpause", container)
|
||||
exitCode, err := runCommand(unpauseCmd)
|
||||
if exitCode != 0 && err == nil {
|
||||
err = fmt.Errorf("failed to unpause container")
|
||||
}
|
||||
|
||||
return err
|
||||
return icmd.RunCommand(dockerBinary, "unpause", container).Error
|
||||
}
|
||||
|
||||
func unpauseAllContainers() error {
|
||||
|
@ -428,24 +417,12 @@ func unpauseAllContainers() error {
|
|||
}
|
||||
|
||||
func deleteImages(images ...string) error {
|
||||
args := []string{"rmi", "-f"}
|
||||
args = append(args, images...)
|
||||
rmiCmd := exec.Command(dockerBinary, args...)
|
||||
exitCode, err := runCommand(rmiCmd)
|
||||
// set error manually if not set
|
||||
if exitCode != 0 && err == nil {
|
||||
err = fmt.Errorf("failed to remove image: `docker rmi` exit is non-zero")
|
||||
}
|
||||
return err
|
||||
args := []string{dockerBinary, "rmi", "-f"}
|
||||
return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error
|
||||
}
|
||||
|
||||
func imageExists(image string) error {
|
||||
inspectCmd := exec.Command(dockerBinary, "inspect", image)
|
||||
exitCode, err := runCommand(inspectCmd)
|
||||
if exitCode != 0 && err == nil {
|
||||
err = fmt.Errorf("couldn't find image %q", image)
|
||||
}
|
||||
return err
|
||||
return icmd.RunCommand(dockerBinary, "inspect", image).Error
|
||||
}
|
||||
|
||||
func pullImageIfNotExist(image string) error {
|
||||
|
@ -464,33 +441,49 @@ func dockerCmdWithError(args ...string) (string, int, error) {
|
|||
if err := validateArgs(args...); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
out, code, err := integration.DockerCmdWithError(dockerBinary, args...)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%v: %s", err, out)
|
||||
result := icmd.RunCommand(dockerBinary, args...)
|
||||
if result.Error != nil {
|
||||
return result.Combined(), result.ExitCode, result.Compare(icmd.Success)
|
||||
}
|
||||
return out, code, err
|
||||
return result.Combined(), result.ExitCode, result.Error
|
||||
}
|
||||
|
||||
func dockerCmdWithStdoutStderr(c *check.C, args ...string) (string, string, int) {
|
||||
if err := validateArgs(args...); err != nil {
|
||||
c.Fatalf(err.Error())
|
||||
}
|
||||
return integration.DockerCmdWithStdoutStderr(dockerBinary, c, args...)
|
||||
|
||||
result := icmd.RunCommand(dockerBinary, args...)
|
||||
// TODO: why is c ever nil?
|
||||
if c != nil {
|
||||
c.Assert(result, icmd.Matches, icmd.Success)
|
||||
}
|
||||
return result.Stdout(), result.Stderr(), result.ExitCode
|
||||
}
|
||||
|
||||
func dockerCmd(c *check.C, args ...string) (string, int) {
|
||||
if err := validateArgs(args...); err != nil {
|
||||
c.Fatalf(err.Error())
|
||||
}
|
||||
return integration.DockerCmd(dockerBinary, c, args...)
|
||||
result := icmd.RunCommand(dockerBinary, args...)
|
||||
c.Assert(result, icmd.Matches, icmd.Success)
|
||||
return result.Combined(), result.ExitCode
|
||||
}
|
||||
|
||||
func dockerCmdWithResult(args ...string) *icmd.Result {
|
||||
return icmd.RunCommand(dockerBinary, args...)
|
||||
}
|
||||
|
||||
func binaryWithArgs(args ...string) []string {
|
||||
return append([]string{dockerBinary}, args...)
|
||||
}
|
||||
|
||||
// execute a docker command with a timeout
|
||||
func dockerCmdWithTimeout(timeout time.Duration, args ...string) (string, int, error) {
|
||||
func dockerCmdWithTimeout(timeout time.Duration, args ...string) *icmd.Result {
|
||||
if err := validateArgs(args...); err != nil {
|
||||
return "", 0, err
|
||||
return &icmd.Result{Error: err}
|
||||
}
|
||||
return integration.DockerCmdWithTimeout(dockerBinary, timeout, args...)
|
||||
return icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Timeout: timeout})
|
||||
}
|
||||
|
||||
// execute a docker command in a directory
|
||||
|
@ -498,15 +491,20 @@ func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error
|
|||
if err := validateArgs(args...); err != nil {
|
||||
c.Fatalf(err.Error())
|
||||
}
|
||||
return integration.DockerCmdInDir(dockerBinary, path, args...)
|
||||
result := icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Dir: path})
|
||||
return result.Combined(), result.ExitCode, result.Error
|
||||
}
|
||||
|
||||
// execute a docker command in a directory with a timeout
|
||||
func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...string) (string, int, error) {
|
||||
func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...string) *icmd.Result {
|
||||
if err := validateArgs(args...); err != nil {
|
||||
return "", 0, err
|
||||
return &icmd.Result{Error: err}
|
||||
}
|
||||
return integration.DockerCmdInDirWithTimeout(dockerBinary, timeout, path, args...)
|
||||
return icmd.RunCmd(icmd.Cmd{
|
||||
Command: binaryWithArgs(args...),
|
||||
Timeout: timeout,
|
||||
Dir: path,
|
||||
})
|
||||
}
|
||||
|
||||
// validateArgs is a checker to ensure tests are not running commands which are
|
||||
|
@ -867,7 +865,7 @@ var errMountNotFound = errors.New("mount point not found")
|
|||
|
||||
func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
|
||||
var mp []types.MountPoint
|
||||
if err := unmarshalJSON([]byte(j), &mp); err != nil {
|
||||
if err := json.Unmarshal([]byte(j), &mp); err != nil {
|
||||
return types.MountPoint{}, err
|
||||
}
|
||||
|
||||
|
@ -1355,17 +1353,12 @@ func buildImageCmdArgs(args []string, name, dockerfile string, useCache bool) *e
|
|||
}
|
||||
|
||||
func waitForContainer(contID string, args ...string) error {
|
||||
args = append([]string{"run", "--name", contID}, args...)
|
||||
cmd := exec.Command(dockerBinary, args...)
|
||||
if _, err := runCommand(cmd); err != nil {
|
||||
return err
|
||||
args = append([]string{dockerBinary, "run", "--name", contID}, args...)
|
||||
result := icmd.RunCmd(icmd.Cmd{Command: args})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if err := waitRun(contID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return waitRun(contID)
|
||||
}
|
||||
|
||||
// waitRun will wait for the specified container to be running, maximum 5 seconds.
|
||||
|
@ -1391,22 +1384,22 @@ func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg
|
|||
|
||||
args := append(arg, "inspect", "-f", expr, name)
|
||||
for {
|
||||
cmd := exec.Command(dockerBinary, args...)
|
||||
out, _, err := runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
if !strings.Contains(out, "No such") {
|
||||
return fmt.Errorf("error executing docker inspect: %v\n%s", err, out)
|
||||
result := icmd.RunCommand(dockerBinary, args...)
|
||||
if result.Error != nil {
|
||||
if !strings.Contains(result.Stderr(), "No such") {
|
||||
return fmt.Errorf("error executing docker inspect: %v\n%s",
|
||||
result.Stderr(), result.Stdout())
|
||||
}
|
||||
select {
|
||||
case <-after:
|
||||
return err
|
||||
return result.Error
|
||||
default:
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out = strings.TrimSpace(out)
|
||||
out := strings.TrimSpace(result.Stdout())
|
||||
if out == expected {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/integration"
|
||||
"github.com/docker/docker/pkg/integration/cmd"
|
||||
)
|
||||
|
||||
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
||||
|
@ -16,46 +17,39 @@ func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
|||
return "", "/"
|
||||
}
|
||||
|
||||
func getExitCode(err error) (int, error) {
|
||||
return integration.GetExitCode(err)
|
||||
// TODO: update code to call cmd.RunCmd directly, and remove this function
|
||||
func runCommandWithOutput(execCmd *exec.Cmd) (string, int, error) {
|
||||
result := cmd.RunCmd(transformCmd(execCmd))
|
||||
return result.Combined(), result.ExitCode, result.Error
|
||||
}
|
||||
|
||||
func processExitCode(err error) (exitCode int) {
|
||||
return integration.ProcessExitCode(err)
|
||||
// TODO: update code to call cmd.RunCmd directly, and remove this function
|
||||
func runCommandWithStdoutStderr(execCmd *exec.Cmd) (string, string, int, error) {
|
||||
result := cmd.RunCmd(transformCmd(execCmd))
|
||||
return result.Stdout(), result.Stderr(), result.ExitCode, result.Error
|
||||
}
|
||||
|
||||
func isKilled(err error) bool {
|
||||
return integration.IsKilled(err)
|
||||
// TODO: update code to call cmd.RunCmd directly, and remove this function
|
||||
func runCommand(execCmd *exec.Cmd) (exitCode int, err error) {
|
||||
result := cmd.RunCmd(transformCmd(execCmd))
|
||||
return result.ExitCode, result.Error
|
||||
}
|
||||
|
||||
func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
|
||||
return integration.RunCommandWithOutput(cmd)
|
||||
}
|
||||
|
||||
func runCommandWithStdoutStderr(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
|
||||
return integration.RunCommandWithStdoutStderr(cmd)
|
||||
}
|
||||
|
||||
func runCommandWithOutputForDuration(cmd *exec.Cmd, duration time.Duration) (output string, exitCode int, timedOut bool, err error) {
|
||||
return integration.RunCommandWithOutputForDuration(cmd, duration)
|
||||
}
|
||||
|
||||
func runCommandWithOutputAndTimeout(cmd *exec.Cmd, timeout time.Duration) (output string, exitCode int, err error) {
|
||||
return integration.RunCommandWithOutputAndTimeout(cmd, timeout)
|
||||
}
|
||||
|
||||
func runCommand(cmd *exec.Cmd) (exitCode int, err error) {
|
||||
return integration.RunCommand(cmd)
|
||||
// Temporary shim for migrating commands to the new function
|
||||
func transformCmd(execCmd *exec.Cmd) cmd.Cmd {
|
||||
return cmd.Cmd{
|
||||
Command: execCmd.Args,
|
||||
Env: execCmd.Env,
|
||||
Dir: execCmd.Dir,
|
||||
Stdin: execCmd.Stdin,
|
||||
Stdout: execCmd.Stdout,
|
||||
}
|
||||
}
|
||||
|
||||
func runCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode int, err error) {
|
||||
return integration.RunCommandPipelineWithOutput(cmds...)
|
||||
}
|
||||
|
||||
func unmarshalJSON(data []byte, result interface{}) error {
|
||||
return integration.UnmarshalJSON(data, result)
|
||||
}
|
||||
|
||||
func convertSliceOfStringsToMap(input []string) map[string]struct{} {
|
||||
return integration.ConvertSliceOfStringsToMap(input)
|
||||
}
|
||||
|
|
302
pkg/integration/cmd/command.go
Normal file
302
pkg/integration/cmd/command.go
Normal file
|
@ -0,0 +1,302 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
type testingT interface {
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
const (
|
||||
// None is a token to inform Result.Assert that the output should be empty
|
||||
None string = "<NOTHING>"
|
||||
)
|
||||
|
||||
// GetExitCode returns the ExitStatus of the specified error if its type is
|
||||
// exec.ExitError, returns 0 and an error otherwise.
|
||||
func GetExitCode(err error) (int, error) {
|
||||
exitCode := 0
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
return procExit.ExitStatus(), nil
|
||||
}
|
||||
}
|
||||
return exitCode, fmt.Errorf("failed to get exit code")
|
||||
}
|
||||
|
||||
// ProcessExitCode process the specified error and returns the exit status code
|
||||
// if the error was of type exec.ExitError, returns nothing otherwise.
|
||||
func ProcessExitCode(err error) (exitCode int) {
|
||||
if err != nil {
|
||||
var exiterr error
|
||||
if exitCode, exiterr = GetExitCode(err); exiterr != nil {
|
||||
// TODO: Fix this so we check the error's text.
|
||||
// we've failed to retrieve exit code, so we set it to 127
|
||||
exitCode = 127
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Result stores the result of running a command
|
||||
type Result struct {
|
||||
Cmd *exec.Cmd
|
||||
ExitCode int
|
||||
Error error
|
||||
// Timeout is true if the command was killed because it ran for too long
|
||||
Timeout bool
|
||||
outBuffer *bytes.Buffer
|
||||
errBuffer *bytes.Buffer
|
||||
}
|
||||
|
||||
// Assert compares the Result against the Expected struct, and fails the test if
|
||||
// any of the expcetations are not met.
|
||||
func (r *Result) Assert(t testingT, exp Expected) {
|
||||
err := r.Compare(exp)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
t.Fatalf("at %s:%d\n%s", filepath.Base(file), line, err.Error())
|
||||
}
|
||||
|
||||
// Compare returns an formatted error with the command, stdout, stderr, exit
|
||||
// code, and any failed expectations
|
||||
func (r *Result) Compare(exp Expected) error {
|
||||
errors := []string{}
|
||||
add := func(format string, args ...interface{}) {
|
||||
errors = append(errors, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
if exp.ExitCode != r.ExitCode {
|
||||
add("ExitCode was %d expected %d", r.ExitCode, exp.ExitCode)
|
||||
}
|
||||
if exp.Timeout != r.Timeout {
|
||||
if exp.Timeout {
|
||||
add("Expected command to timeout")
|
||||
} else {
|
||||
add("Expected command to finish, but it hit the timeout")
|
||||
}
|
||||
}
|
||||
if !matchOutput(exp.Out, r.Stdout()) {
|
||||
add("Expected stdout to contain %q", exp.Out)
|
||||
}
|
||||
if !matchOutput(exp.Err, r.Stderr()) {
|
||||
add("Expected stderr to contain %q", exp.Err)
|
||||
}
|
||||
switch {
|
||||
// If a non-zero exit code is expected there is going to be an error.
|
||||
// Don't require an error message as well as an exit code because the
|
||||
// error message is going to be "exit status <code> which is not useful
|
||||
case exp.Error == "" && exp.ExitCode != 0:
|
||||
case exp.Error == "" && r.Error != nil:
|
||||
add("Expected no error")
|
||||
case exp.Error != "" && r.Error == nil:
|
||||
add("Expected error to contain %q, but there was no error", exp.Error)
|
||||
case exp.Error != "" && !strings.Contains(r.Error.Error(), exp.Error):
|
||||
add("Expected error to contain %q", exp.Error)
|
||||
}
|
||||
|
||||
if len(errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%s\nFailures:\n%s\n", r, strings.Join(errors, "\n"))
|
||||
}
|
||||
|
||||
func matchOutput(expected string, actual string) bool {
|
||||
switch expected {
|
||||
case None:
|
||||
return actual == ""
|
||||
default:
|
||||
return strings.Contains(actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Result) String() string {
|
||||
var timeout string
|
||||
if r.Timeout {
|
||||
timeout = " (timeout)"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`
|
||||
Command: %s
|
||||
ExitCode: %d%s, Error: %s
|
||||
Stdout: %v
|
||||
Stderr: %v
|
||||
`,
|
||||
strings.Join(r.Cmd.Args, " "),
|
||||
r.ExitCode,
|
||||
timeout,
|
||||
r.Error,
|
||||
r.Stdout(),
|
||||
r.Stderr())
|
||||
}
|
||||
|
||||
// Expected is the expected output from a Command. This struct is compared to a
|
||||
// Result struct by Result.Assert().
|
||||
type Expected struct {
|
||||
ExitCode int
|
||||
Timeout bool
|
||||
Error string
|
||||
Out string
|
||||
Err string
|
||||
}
|
||||
|
||||
// Success is the default expected result
|
||||
var Success = Expected{}
|
||||
|
||||
// Stdout returns the stdout of the process as a string
|
||||
func (r *Result) Stdout() string {
|
||||
return r.outBuffer.String()
|
||||
}
|
||||
|
||||
// Stderr returns the stderr of the process as a string
|
||||
func (r *Result) Stderr() string {
|
||||
return r.errBuffer.String()
|
||||
}
|
||||
|
||||
// Combined returns the stdout and stderr combined into a single string
|
||||
func (r *Result) Combined() string {
|
||||
return r.outBuffer.String() + r.errBuffer.String()
|
||||
}
|
||||
|
||||
// SetExitError sets Error and ExitCode based on Error
|
||||
func (r *Result) SetExitError(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
r.Error = err
|
||||
r.ExitCode = ProcessExitCode(err)
|
||||
}
|
||||
|
||||
type matches struct{}
|
||||
|
||||
// Info returns the CheckerInfo
|
||||
func (m *matches) Info() *check.CheckerInfo {
|
||||
return &check.CheckerInfo{
|
||||
Name: "CommandMatches",
|
||||
Params: []string{"result", "expected"},
|
||||
}
|
||||
}
|
||||
|
||||
// Check compares a result against the expected
|
||||
func (m *matches) Check(params []interface{}, names []string) (bool, string) {
|
||||
result, ok := params[0].(*Result)
|
||||
if !ok {
|
||||
return false, fmt.Sprintf("result must be a *Result, not %T", params[0])
|
||||
}
|
||||
expected, ok := params[1].(Expected)
|
||||
if !ok {
|
||||
return false, fmt.Sprintf("expected must be an Expected, not %T", params[1])
|
||||
}
|
||||
|
||||
err := result.Compare(expected)
|
||||
if err == nil {
|
||||
return true, ""
|
||||
}
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
// Matches is a gocheck.Checker for comparing a Result against an Expected
|
||||
var Matches = &matches{}
|
||||
|
||||
// Cmd contains the arguments and options for a process to run as part of a test
|
||||
// suite.
|
||||
type Cmd struct {
|
||||
Command []string
|
||||
Timeout time.Duration
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Dir string
|
||||
Env []string
|
||||
}
|
||||
|
||||
// RunCmd runs a command and returns a Result
|
||||
func RunCmd(cmd Cmd) *Result {
|
||||
result := StartCmd(cmd)
|
||||
if result.Error != nil {
|
||||
return result
|
||||
}
|
||||
return WaitOnCmd(cmd.Timeout, result)
|
||||
}
|
||||
|
||||
// RunCommand parses a command line and runs it, returning a result
|
||||
func RunCommand(command string, args ...string) *Result {
|
||||
return RunCmd(Cmd{Command: append([]string{command}, args...)})
|
||||
}
|
||||
|
||||
// StartCmd starts a command, but doesn't wait for it to finish
|
||||
func StartCmd(cmd Cmd) *Result {
|
||||
result := buildCmd(cmd)
|
||||
if result.Error != nil {
|
||||
return result
|
||||
}
|
||||
result.SetExitError(result.Cmd.Start())
|
||||
return result
|
||||
}
|
||||
|
||||
func buildCmd(cmd Cmd) *Result {
|
||||
var execCmd *exec.Cmd
|
||||
switch len(cmd.Command) {
|
||||
case 1:
|
||||
execCmd = exec.Command(cmd.Command[0])
|
||||
default:
|
||||
execCmd = exec.Command(cmd.Command[0], cmd.Command[1:]...)
|
||||
}
|
||||
outBuffer := new(bytes.Buffer)
|
||||
errBuffer := new(bytes.Buffer)
|
||||
|
||||
execCmd.Stdin = cmd.Stdin
|
||||
execCmd.Dir = cmd.Dir
|
||||
execCmd.Env = cmd.Env
|
||||
if cmd.Stdout != nil {
|
||||
execCmd.Stdout = io.MultiWriter(outBuffer, cmd.Stdout)
|
||||
} else {
|
||||
execCmd.Stdout = outBuffer
|
||||
}
|
||||
execCmd.Stderr = errBuffer
|
||||
return &Result{
|
||||
Cmd: execCmd,
|
||||
outBuffer: outBuffer,
|
||||
errBuffer: errBuffer,
|
||||
}
|
||||
}
|
||||
|
||||
// WaitOnCmd waits for a command to complete. If timeout is non-nil then
|
||||
// only wait until the timeout.
|
||||
func WaitOnCmd(timeout time.Duration, result *Result) *Result {
|
||||
if timeout == time.Duration(0) {
|
||||
result.SetExitError(result.Cmd.Wait())
|
||||
return result
|
||||
}
|
||||
|
||||
done := make(chan error, 1)
|
||||
// Wait for command to exit in a goroutine
|
||||
go func() {
|
||||
done <- result.Cmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
killErr := result.Cmd.Process.Kill()
|
||||
if killErr != nil {
|
||||
fmt.Printf("failed to kill (pid=%d): %v\n", result.Cmd.Process.Pid, killErr)
|
||||
}
|
||||
result.Timeout = true
|
||||
case err := <-done:
|
||||
result.SetExitError(err)
|
||||
}
|
||||
return result
|
||||
}
|
104
pkg/integration/cmd/command_test.go
Normal file
104
pkg/integration/cmd/command_test.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/testutil/assert"
|
||||
)
|
||||
|
||||
func TestRunCommand(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
result := RunCommand("ls")
|
||||
result.Assert(t, Expected{})
|
||||
|
||||
result = RunCommand("doesnotexists")
|
||||
expectedError := `exec: "doesnotexists": executable file not found`
|
||||
result.Assert(t, Expected{ExitCode: 127, Error: expectedError})
|
||||
|
||||
result = RunCommand("ls", "-z")
|
||||
result.Assert(t, Expected{
|
||||
ExitCode: 2,
|
||||
Error: "exit status 2",
|
||||
Err: "invalid option",
|
||||
})
|
||||
assert.Contains(t, result.Combined(), "invalid option")
|
||||
}
|
||||
|
||||
func TestRunCommandWithCombined(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
result := RunCommand("ls", "-a")
|
||||
result.Assert(t, Expected{})
|
||||
|
||||
assert.Contains(t, result.Combined(), "..")
|
||||
assert.Contains(t, result.Stdout(), "..")
|
||||
}
|
||||
|
||||
func TestRunCommandWithTimeoutFinished(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
result := RunCmd(Cmd{
|
||||
Command: []string{"ls", "-a"},
|
||||
Timeout: 50 * time.Millisecond,
|
||||
})
|
||||
result.Assert(t, Expected{Out: ".."})
|
||||
}
|
||||
|
||||
func TestRunCommandWithTimeoutKilled(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
command := []string{"sh", "-c", "while true ; do echo 1 ; sleep .1 ; done"}
|
||||
result := RunCmd(Cmd{Command: command, Timeout: 500 * time.Millisecond})
|
||||
result.Assert(t, Expected{Timeout: true})
|
||||
|
||||
ones := strings.Split(result.Stdout(), "\n")
|
||||
assert.Equal(t, len(ones), 6)
|
||||
}
|
||||
|
||||
func TestRunCommandWithErrors(t *testing.T) {
|
||||
result := RunCommand("/foobar")
|
||||
result.Assert(t, Expected{Error: "foobar", ExitCode: 127})
|
||||
}
|
||||
|
||||
func TestRunCommandWithStdoutStderr(t *testing.T) {
|
||||
result := RunCommand("echo", "hello", "world")
|
||||
result.Assert(t, Expected{Out: "hello world\n", Err: None})
|
||||
}
|
||||
|
||||
func TestRunCommandWithStdoutStderrError(t *testing.T) {
|
||||
result := RunCommand("doesnotexists")
|
||||
|
||||
expected := `exec: "doesnotexists": executable file not found`
|
||||
result.Assert(t, Expected{Out: None, Err: None, ExitCode: 127, Error: expected})
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
expected = "ls: unknown option"
|
||||
default:
|
||||
expected = "ls: invalid option"
|
||||
}
|
||||
|
||||
result = RunCommand("ls", "-z")
|
||||
result.Assert(t, Expected{
|
||||
Out: None,
|
||||
Err: expected,
|
||||
ExitCode: 2,
|
||||
Error: "exit status 2",
|
||||
})
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// We use the elongated quote mechanism for quoting error returns as
|
||||
// the use of strconv.Quote or %q in fmt.Errorf will escape characters. This
|
||||
// has a big downside on Windows where the args include paths, so instead
|
||||
// of something like c:\directory\file.txt, the output would be
|
||||
// c:\\directory\\file.txt. This is highly misleading.
|
||||
const quote = `"`
|
||||
|
||||
var execCommand = exec.Command
|
||||
|
||||
// DockerCmdWithError executes a docker command that is supposed to fail and returns
|
||||
// the output, the exit code and the error.
|
||||
func DockerCmdWithError(dockerBinary string, args ...string) (string, int, error) {
|
||||
return RunCommandWithOutput(execCommand(dockerBinary, args...))
|
||||
}
|
||||
|
||||
// DockerCmdWithStdoutStderr executes a docker command and returns the content of the
|
||||
// stdout, stderr and the exit code. If a check.C is passed, it will fail and stop tests
|
||||
// if the error is not nil.
|
||||
func DockerCmdWithStdoutStderr(dockerBinary string, c *check.C, args ...string) (string, string, int) {
|
||||
stdout, stderr, status, err := RunCommandWithStdoutStderr(execCommand(dockerBinary, args...))
|
||||
if c != nil {
|
||||
c.Assert(err, check.IsNil, check.Commentf(quote+"%v"+quote+" failed with errors: %s, %v", strings.Join(args, " "), stderr, err))
|
||||
}
|
||||
return stdout, stderr, status
|
||||
}
|
||||
|
||||
// DockerCmd executes a docker command and returns the output and the exit code. If the
|
||||
// command returns an error, it will fail and stop the tests.
|
||||
func DockerCmd(dockerBinary string, c *check.C, args ...string) (string, int) {
|
||||
out, status, err := RunCommandWithOutput(execCommand(dockerBinary, args...))
|
||||
c.Assert(err, check.IsNil, check.Commentf(quote+"%v"+quote+" failed with errors: %s, %v", strings.Join(args, " "), out, err))
|
||||
return out, status
|
||||
}
|
||||
|
||||
// DockerCmdWithTimeout executes a docker command with a timeout, and returns the output,
|
||||
// the exit code and the error (if any).
|
||||
func DockerCmdWithTimeout(dockerBinary string, timeout time.Duration, args ...string) (string, int, error) {
|
||||
out, status, err := RunCommandWithOutputAndTimeout(execCommand(dockerBinary, args...), timeout)
|
||||
if err != nil {
|
||||
return out, status, fmt.Errorf(quote+"%v"+quote+" failed with errors: %v : %q", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return out, status, err
|
||||
}
|
||||
|
||||
// DockerCmdInDir executes a docker command in a directory and returns the output, the
|
||||
// exit code and the error (if any).
|
||||
func DockerCmdInDir(dockerBinary string, path string, args ...string) (string, int, error) {
|
||||
dockerCommand := execCommand(dockerBinary, args...)
|
||||
dockerCommand.Dir = path
|
||||
out, status, err := RunCommandWithOutput(dockerCommand)
|
||||
if err != nil {
|
||||
return out, status, fmt.Errorf(quote+"%v"+quote+" failed with errors: %v : %q", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return out, status, err
|
||||
}
|
||||
|
||||
// DockerCmdInDirWithTimeout executes a docker command in a directory with a timeout and
|
||||
// returns the output, the exit code and the error (if any).
|
||||
func DockerCmdInDirWithTimeout(dockerBinary string, timeout time.Duration, path string, args ...string) (string, int, error) {
|
||||
dockerCommand := execCommand(dockerBinary, args...)
|
||||
dockerCommand.Dir = path
|
||||
out, status, err := RunCommandWithOutputAndTimeout(dockerCommand, timeout)
|
||||
if err != nil {
|
||||
return out, status, fmt.Errorf(quote+"%v"+quote+" failed with errors: %v : %q", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return out, status, err
|
||||
}
|
|
@ -1,405 +0,0 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
const dockerBinary = "docker"
|
||||
|
||||
// Setup go-check for this test
|
||||
func Test(t *testing.T) {
|
||||
check.TestingT(t)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerCmdSuite{})
|
||||
}
|
||||
|
||||
type DockerCmdSuite struct{}
|
||||
|
||||
// Fake the exec.Command to use our mock.
|
||||
func (s *DockerCmdSuite) SetUpTest(c *check.C) {
|
||||
execCommand = fakeExecCommand
|
||||
}
|
||||
|
||||
// And bring it back to normal after the test.
|
||||
func (s *DockerCmdSuite) TearDownTest(c *check.C) {
|
||||
execCommand = exec.Command
|
||||
}
|
||||
|
||||
// DockerCmdWithError tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithError(c *check.C) {
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
"Command doesnotexists not found.",
|
||||
1,
|
||||
fmt.Errorf("exit status 1"),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
"an error has occurred",
|
||||
1,
|
||||
fmt.Errorf("exit status 1"),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "exitCode", "127"},
|
||||
"an error has occurred with exitCode 127",
|
||||
127,
|
||||
fmt.Errorf("exit status 127"),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
out, exitCode, error := DockerCmdWithError(cmd.binary, cmd.args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DockerCmdWithStdoutStderr tests
|
||||
|
||||
type dockerCmdWithStdoutStderrErrorSuite struct{}
|
||||
|
||||
func (s *dockerCmdWithStdoutStderrErrorSuite) Test(c *check.C) {
|
||||
// Should fail, the test too
|
||||
DockerCmdWithStdoutStderr(dockerBinary, c, "an", "error")
|
||||
}
|
||||
|
||||
type dockerCmdWithStdoutStderrSuccessSuite struct{}
|
||||
|
||||
func (s *dockerCmdWithStdoutStderrSuccessSuite) Test(c *check.C) {
|
||||
stdout, stderr, exitCode := DockerCmdWithStdoutStderr(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello")
|
||||
c.Assert(stdout, check.Equals, "hello")
|
||||
c.Assert(stderr, check.Equals, "")
|
||||
c.Assert(exitCode, check.Equals, 0)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrError(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdWithStdoutStderrErrorSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 0)
|
||||
c.Check(result.Failed, check.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrSuccess(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdWithStdoutStderrSuccessSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 1)
|
||||
c.Check(result.Failed, check.Equals, 0)
|
||||
}
|
||||
|
||||
// DockerCmd tests
|
||||
|
||||
type dockerCmdErrorSuite struct{}
|
||||
|
||||
func (s *dockerCmdErrorSuite) Test(c *check.C) {
|
||||
// Should fail, the test too
|
||||
DockerCmd(dockerBinary, c, "an", "error")
|
||||
}
|
||||
|
||||
type dockerCmdSuccessSuite struct{}
|
||||
|
||||
func (s *dockerCmdSuccessSuite) Test(c *check.C) {
|
||||
stdout, exitCode := DockerCmd(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello")
|
||||
c.Assert(stdout, check.Equals, "hello")
|
||||
c.Assert(exitCode, check.Equals, 0)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdError(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdErrorSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 0)
|
||||
c.Check(result.Failed, check.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdSuccess(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdSuccessSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 1)
|
||||
c.Check(result.Failed, check.Equals, 0)
|
||||
}
|
||||
|
||||
// DockerCmdWithTimeout tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithTimeout(c *check.C) {
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
timeout time.Duration
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
200 * time.Millisecond,
|
||||
`Command doesnotexists not found.`,
|
||||
1,
|
||||
fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
200 * time.Millisecond,
|
||||
`an error has occurred`,
|
||||
1,
|
||||
fmt.Errorf(`"an error" failed with errors: exit status 1 : "an error has occurred"`),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"a", "command", "that", "times", "out"},
|
||||
5 * time.Millisecond,
|
||||
"",
|
||||
0,
|
||||
fmt.Errorf(`"a command that times out" failed with errors: command timed out : ""`),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
200 * time.Millisecond,
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
out, exitCode, error := DockerCmdWithTimeout(cmd.binary, cmd.timeout, cmd.args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DockerCmdInDir tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdInDir(c *check.C) {
|
||||
tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
`Command doesnotexists not found.`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
`an error has occurred`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
// We prepend the arguments with dir:thefolder.. the fake command will check
|
||||
// that the current workdir is the same as the one we are passing.
|
||||
args := append([]string{"dir:" + tempFolder}, cmd.args...)
|
||||
out, exitCode, error := DockerCmdInDir(cmd.binary, tempFolder, args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DockerCmdInDirWithTimeout tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdInDirWithTimeout(c *check.C) {
|
||||
tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
timeout time.Duration
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
200 * time.Millisecond,
|
||||
`Command doesnotexists not found.`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
200 * time.Millisecond,
|
||||
`an error has occurred`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"a", "command", "that", "times", "out"},
|
||||
5 * time.Millisecond,
|
||||
"",
|
||||
0,
|
||||
fmt.Errorf(`"dir:%s a command that times out" failed with errors: command timed out : ""`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
200 * time.Millisecond,
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
// We prepend the arguments with dir:thefolder.. the fake command will check
|
||||
// that the current workdir is the same as the one we are passing.
|
||||
args := append([]string{"dir:" + tempFolder}, cmd.args...)
|
||||
out, exitCode, error := DockerCmdInDirWithTimeout(cmd.binary, cmd.timeout, tempFolder, args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers :)
|
||||
|
||||
// Type implementing the io.Writer interface for analyzing output.
|
||||
type String struct {
|
||||
value string
|
||||
}
|
||||
|
||||
// The only function required by the io.Writer interface. Will append
|
||||
// written data to the String.value string.
|
||||
func (s *String) Write(p []byte) (n int, err error) {
|
||||
s.value += string(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Helper function that mock the exec.Command call (and call the test binary)
|
||||
func fakeExecCommand(command string, args ...string) *exec.Cmd {
|
||||
cs := []string{"-test.run=TestHelperProcess", "--", command}
|
||||
cs = append(cs, args...)
|
||||
cmd := exec.Command(os.Args[0], cs...)
|
||||
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func TestHelperProcess(t *testing.T) {
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
||||
return
|
||||
}
|
||||
args := os.Args
|
||||
|
||||
// Previous arguments are tests stuff, that looks like :
|
||||
// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --
|
||||
cmd, args := args[3], args[4:]
|
||||
// Handle the case where args[0] is dir:...
|
||||
if len(args) > 0 && strings.HasPrefix(args[0], "dir:") {
|
||||
expectedCwd := args[0][4:]
|
||||
if len(args) > 1 {
|
||||
args = args[1:]
|
||||
}
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get workingdir: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// This checks that the given path is the same as the currend working dire
|
||||
if expectedCwd != cwd {
|
||||
fmt.Fprintf(os.Stderr, "Current workdir should be %q, but is %q", expectedCwd, cwd)
|
||||
}
|
||||
}
|
||||
switch cmd {
|
||||
case dockerBinary:
|
||||
argsStr := strings.Join(args, " ")
|
||||
switch argsStr {
|
||||
case "an exitCode 127":
|
||||
fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127")
|
||||
os.Exit(127)
|
||||
case "an error":
|
||||
fmt.Fprintf(os.Stderr, "an error has occurred")
|
||||
os.Exit(1)
|
||||
case "a command that times out":
|
||||
time.Sleep(10 * time.Second)
|
||||
fmt.Fprintf(os.Stdout, "too long, should be killed")
|
||||
// A random exit code (that should never happened in tests)
|
||||
os.Exit(7)
|
||||
case "run -ti ubuntu echo hello":
|
||||
fmt.Fprintf(os.Stdout, "hello")
|
||||
default:
|
||||
fmt.Fprintf(os.Stdout, "no arguments")
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Command %s not found.", cmd)
|
||||
os.Exit(1)
|
||||
}
|
||||
// some code here to check arguments perhaps?
|
||||
os.Exit(0)
|
||||
}
|
|
@ -2,8 +2,6 @@ package integration
|
|||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -15,35 +13,10 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
icmd "github.com/docker/docker/pkg/integration/cmd"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
)
|
||||
|
||||
// GetExitCode returns the ExitStatus of the specified error if its type is
|
||||
// exec.ExitError, returns 0 and an error otherwise.
|
||||
func GetExitCode(err error) (int, error) {
|
||||
exitCode := 0
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
return procExit.ExitStatus(), nil
|
||||
}
|
||||
}
|
||||
return exitCode, fmt.Errorf("failed to get exit code")
|
||||
}
|
||||
|
||||
// ProcessExitCode process the specified error and returns the exit status code
|
||||
// if the error was of type exec.ExitError, returns nothing otherwise.
|
||||
func ProcessExitCode(err error) (exitCode int) {
|
||||
if err != nil {
|
||||
var exiterr error
|
||||
if exitCode, exiterr = GetExitCode(err); exiterr != nil {
|
||||
// TODO: Fix this so we check the error's text.
|
||||
// we've failed to retrieve exit code, so we set it to 127
|
||||
exitCode = 127
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// IsKilled process the specified error and returns whether the process was killed or not.
|
||||
func IsKilled(err error) bool {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
|
@ -59,110 +32,14 @@ func IsKilled(err error) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// RunCommandWithOutput runs the specified command and returns the combined output (stdout/stderr)
|
||||
// with the exitCode different from 0 and the error if something bad happened
|
||||
func RunCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
|
||||
func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
|
||||
exitCode = 0
|
||||
out, err := cmd.CombinedOutput()
|
||||
exitCode = ProcessExitCode(err)
|
||||
exitCode = icmd.ProcessExitCode(err)
|
||||
output = string(out)
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommandWithStdoutStderr runs the specified command and returns stdout and stderr separately
|
||||
// with the exitCode different from 0 and the error if something bad happened
|
||||
func RunCommandWithStdoutStderr(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
|
||||
var (
|
||||
stderrBuffer, stdoutBuffer bytes.Buffer
|
||||
)
|
||||
exitCode = 0
|
||||
cmd.Stderr = &stderrBuffer
|
||||
cmd.Stdout = &stdoutBuffer
|
||||
err = cmd.Run()
|
||||
exitCode = ProcessExitCode(err)
|
||||
|
||||
stdout = stdoutBuffer.String()
|
||||
stderr = stderrBuffer.String()
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommandWithOutputForDuration runs the specified command "timeboxed" by the specified duration.
|
||||
// If the process is still running when the timebox is finished, the process will be killed and .
|
||||
// It will returns the output with the exitCode different from 0 and the error if something bad happened
|
||||
// and a boolean whether it has been killed or not.
|
||||
func RunCommandWithOutputForDuration(cmd *exec.Cmd, duration time.Duration) (output string, exitCode int, timedOut bool, err error) {
|
||||
var outputBuffer bytes.Buffer
|
||||
if cmd.Stdout != nil {
|
||||
err = errors.New("cmd.Stdout already set")
|
||||
return
|
||||
}
|
||||
cmd.Stdout = &outputBuffer
|
||||
|
||||
if cmd.Stderr != nil {
|
||||
err = errors.New("cmd.Stderr already set")
|
||||
return
|
||||
}
|
||||
cmd.Stderr = &outputBuffer
|
||||
|
||||
// Start the command in the main thread..
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Fail to start command %v : %v", cmd, err)
|
||||
}
|
||||
|
||||
type exitInfo struct {
|
||||
exitErr error
|
||||
exitCode int
|
||||
}
|
||||
|
||||
done := make(chan exitInfo, 1)
|
||||
|
||||
go func() {
|
||||
// And wait for it to exit in the goroutine :)
|
||||
info := exitInfo{}
|
||||
info.exitErr = cmd.Wait()
|
||||
info.exitCode = ProcessExitCode(info.exitErr)
|
||||
done <- info
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(duration):
|
||||
killErr := cmd.Process.Kill()
|
||||
if killErr != nil {
|
||||
fmt.Printf("failed to kill (pid=%d): %v\n", cmd.Process.Pid, killErr)
|
||||
}
|
||||
timedOut = true
|
||||
case info := <-done:
|
||||
err = info.exitErr
|
||||
exitCode = info.exitCode
|
||||
}
|
||||
output = outputBuffer.String()
|
||||
return
|
||||
}
|
||||
|
||||
var errCmdTimeout = fmt.Errorf("command timed out")
|
||||
|
||||
// RunCommandWithOutputAndTimeout runs the specified command "timeboxed" by the specified duration.
|
||||
// It returns the output with the exitCode different from 0 and the error if something bad happened or
|
||||
// if the process timed out (and has been killed).
|
||||
func RunCommandWithOutputAndTimeout(cmd *exec.Cmd, timeout time.Duration) (output string, exitCode int, err error) {
|
||||
var timedOut bool
|
||||
output, exitCode, timedOut, err = RunCommandWithOutputForDuration(cmd, timeout)
|
||||
if timedOut {
|
||||
err = errCmdTimeout
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommand runs the specified command and returns the exitCode different from 0
|
||||
// and the error if something bad happened.
|
||||
func RunCommand(cmd *exec.Cmd) (exitCode int, err error) {
|
||||
exitCode = 0
|
||||
err = cmd.Run()
|
||||
exitCode = ProcessExitCode(err)
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommandPipelineWithOutput runs the array of commands with the output
|
||||
// of each pipelined with the following (like cmd1 | cmd2 | cmd3 would do).
|
||||
// It returns the final output, the exitCode different from 0 and the error
|
||||
|
@ -206,16 +83,7 @@ func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode in
|
|||
}
|
||||
|
||||
// wait on last cmd
|
||||
return RunCommandWithOutput(cmds[len(cmds)-1])
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserialize a JSON in the given interface.
|
||||
func UnmarshalJSON(data []byte, result interface{}) error {
|
||||
if err := json.Unmarshal(data, result); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return runCommandWithOutput(cmds[len(cmds)-1])
|
||||
}
|
||||
|
||||
// ConvertSliceOfStringsToMap converts a slices of string in a map
|
||||
|
@ -351,11 +219,9 @@ func RunAtDifferentDate(date time.Time, block func()) {
|
|||
const timeLayout = "010203042006"
|
||||
// Ensure we bring time back to now
|
||||
now := time.Now().Format(timeLayout)
|
||||
dateReset := exec.Command("date", now)
|
||||
defer RunCommand(dateReset)
|
||||
defer icmd.RunCommand("date", now)
|
||||
|
||||
dateChange := exec.Command("date", date.Format(timeLayout))
|
||||
RunCommand(dateChange)
|
||||
icmd.RunCommand("date", date.Format(timeLayout))
|
||||
block()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -54,203 +53,6 @@ func TestIsKilledTrueWithKilledProcess(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutput(t *testing.T) {
|
||||
var (
|
||||
echoHelloWorldCmd *exec.Cmd
|
||||
expected string
|
||||
)
|
||||
if runtime.GOOS != "windows" {
|
||||
echoHelloWorldCmd = exec.Command("echo", "hello", "world")
|
||||
expected = "hello world\n"
|
||||
} else {
|
||||
echoHelloWorldCmd = exec.Command("cmd", "/s", "/c", "echo", "hello", "world")
|
||||
expected = "hello world\r\n"
|
||||
}
|
||||
|
||||
out, exitCode, err := RunCommandWithOutput(echoHelloWorldCmd)
|
||||
if out != expected || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expected, out, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputError(t *testing.T) {
|
||||
var (
|
||||
p string
|
||||
wrongCmd *exec.Cmd
|
||||
expected string
|
||||
expectedExitCode int
|
||||
)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
p = "$PATH"
|
||||
wrongCmd = exec.Command("ls", "-z")
|
||||
expected = `ls: invalid option -- 'z'
|
||||
Try 'ls --help' for more information.
|
||||
`
|
||||
expectedExitCode = 2
|
||||
} else {
|
||||
p = "%PATH%"
|
||||
wrongCmd = exec.Command("cmd", "/s", "/c", "dir", "/Z")
|
||||
expected = "Invalid switch - " + strconv.Quote("Z") + ".\r\n"
|
||||
expectedExitCode = 1
|
||||
}
|
||||
cmd := exec.Command("doesnotexists")
|
||||
out, exitCode, err := RunCommandWithOutput(cmd)
|
||||
expectedError := `exec: "doesnotexists": executable file not found in ` + p
|
||||
if out != "" || exitCode != 127 || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expectedError, out, err, exitCode)
|
||||
}
|
||||
|
||||
out, exitCode, err = RunCommandWithOutput(wrongCmd)
|
||||
|
||||
if out != expected || exitCode != expectedExitCode || err == nil || !strings.Contains(err.Error(), "exit status "+strconv.Itoa(expectedExitCode)) {
|
||||
t.Fatalf("Expected command to output %s, got out:xxx%sxxx, err:%v with exitCode %v", expected, out, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithStdoutStderr(t *testing.T) {
|
||||
echoHelloWorldCmd := exec.Command("echo", "hello", "world")
|
||||
stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(echoHelloWorldCmd)
|
||||
expected := "hello world\n"
|
||||
if stdout != expected || stderr != "" || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected command to output %s, got stdout:%s, stderr:%s, err:%v with exitCode %v", expected, stdout, stderr, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithStdoutStderrError(t *testing.T) {
|
||||
p := "$PATH"
|
||||
if runtime.GOOS == "windows" {
|
||||
p = "%PATH%"
|
||||
}
|
||||
cmd := exec.Command("doesnotexists")
|
||||
stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(cmd)
|
||||
expectedError := `exec: "doesnotexists": executable file not found in ` + p
|
||||
if stdout != "" || stderr != "" || exitCode != 127 || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", "", stdout, stderr, err, exitCode)
|
||||
}
|
||||
|
||||
wrongLsCmd := exec.Command("ls", "-z")
|
||||
expected := `ls: invalid option -- 'z'
|
||||
Try 'ls --help' for more information.
|
||||
`
|
||||
|
||||
stdout, stderr, exitCode, err = RunCommandWithStdoutStderr(wrongLsCmd)
|
||||
if stdout != "" && stderr != expected || exitCode != 2 || err == nil || err.Error() != "exit status 2" {
|
||||
t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", expectedError, stdout, stderr, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputForDurationFinished(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
cmd := exec.Command("ls")
|
||||
out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 50*time.Millisecond)
|
||||
if out == "" || exitCode != 0 || timedOut || err != nil {
|
||||
t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], timedOut:[%v], err:[%v]", out, exitCode, timedOut, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputForDurationKilled(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done")
|
||||
out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 500*time.Millisecond)
|
||||
ones := strings.Split(out, "\n")
|
||||
if len(ones) != 6 || exitCode != 0 || !timedOut || err != nil {
|
||||
t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out, but did not : out:[%s], exitCode:%d, timedOut:%v, err:%v", out, exitCode, timedOut, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputForDurationErrors(t *testing.T) {
|
||||
cmd := exec.Command("ls")
|
||||
cmd.Stdout = os.Stdout
|
||||
if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err)
|
||||
}
|
||||
cmd = exec.Command("ls")
|
||||
cmd.Stderr = os.Stderr
|
||||
if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputAndTimeoutFinished(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
cmd := exec.Command("ls")
|
||||
out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 50*time.Millisecond)
|
||||
if out == "" || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], err:[%v]", out, exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputAndTimeoutKilled(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done")
|
||||
out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 500*time.Millisecond)
|
||||
ones := strings.Split(out, "\n")
|
||||
if len(ones) != 6 || exitCode != 0 || err == nil || err.Error() != "command timed out" {
|
||||
t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out with an error 'command timed out', but did not : out:[%s], exitCode:%d, err:%v", out, exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputAndTimeoutErrors(t *testing.T) {
|
||||
cmd := exec.Command("ls")
|
||||
cmd.Stdout = os.Stdout
|
||||
if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err)
|
||||
}
|
||||
cmd = exec.Command("ls")
|
||||
cmd.Stderr = os.Stderr
|
||||
if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommand(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
p := "$PATH"
|
||||
if runtime.GOOS == "windows" {
|
||||
p = "%PATH%"
|
||||
}
|
||||
lsCmd := exec.Command("ls")
|
||||
exitCode, err := RunCommand(lsCmd)
|
||||
if exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
|
||||
}
|
||||
|
||||
var expectedError string
|
||||
|
||||
exitCode, err = RunCommand(exec.Command("doesnotexists"))
|
||||
expectedError = `exec: "doesnotexists": executable file not found in ` + p
|
||||
if exitCode != 127 || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
|
||||
}
|
||||
wrongLsCmd := exec.Command("ls", "-z")
|
||||
expected := 2
|
||||
expectedError = `exit status 2`
|
||||
exitCode, err = RunCommand(wrongLsCmd)
|
||||
if exitCode != expected || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandPipelineWithOutputWithNotEnoughCmds(t *testing.T) {
|
||||
_, _, err := RunCommandPipelineWithOutput(exec.Command("ls"))
|
||||
expectedError := "pipeline does not have multiple cmds"
|
||||
|
@ -294,21 +96,6 @@ func TestRunCommandPipelineWithOutput(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Simple simple test as it is just a passthrough for json.Unmarshal
|
||||
func TestUnmarshalJSON(t *testing.T) {
|
||||
emptyResult := struct{}{}
|
||||
if err := UnmarshalJSON([]byte(""), &emptyResult); err == nil {
|
||||
t.Fatalf("Expected an error, got nothing")
|
||||
}
|
||||
result := struct{ Name string }{}
|
||||
if err := UnmarshalJSON([]byte(`{"name": "name"}`), &result); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Name != "name" {
|
||||
t.Fatalf("Expected result.name to be 'name', was '%s'", result.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertSliceOfStringsToMap(t *testing.T) {
|
||||
input := []string{"a", "b"}
|
||||
actual := ConvertSliceOfStringsToMap(input)
|
||||
|
|
Loading…
Reference in a new issue