Merge pull request #25426 from dnephin/better-int-testing-cmd

Remove duplicate RunCommand functions used for integration-cli
This commit is contained in:
Daniel Nephin 2016-08-24 11:34:24 -04:00 committed by GitHub
commit b29558ed5d
24 changed files with 627 additions and 1049 deletions

View file

@ -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) {

View file

@ -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",
})
}

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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)

View file

@ -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) {

View file

@ -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

View file

@ -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)

View file

@ -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) {

View file

@ -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" {

View file

@ -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) {

View file

@ -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])

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)
}

View 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
}

View 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",
})
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)