diff --git a/integration-cli/cli/cli.go b/integration-cli/cli/cli.go index d8355217e3244..55ac0913fc7e1 100644 --- a/integration-cli/cli/cli.go +++ b/integration-cli/cli/cli.go @@ -229,3 +229,11 @@ func WithStdout(writer io.Writer) func(*icmd.Cmd) func() { return nil } } + +// WithStdin sets the standard input reader for the command +func WithStdin(stdin io.Reader) func(*icmd.Cmd) func() { + return func(cmd *icmd.Cmd) func() { + cmd.Stdin = stdin + return nil + } +} diff --git a/integration-cli/daemon/daemon.go b/integration-cli/daemon/daemon.go index bf8015b311d0c..aa1da1a690e13 100644 --- a/integration-cli/daemon/daemon.go +++ b/integration-cli/daemon/daemon.go @@ -14,18 +14,20 @@ import ( "strings" "time" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/events" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/stringid" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/docker/go-connections/sockets" "github.com/docker/go-connections/tlsconfig" "github.com/go-check/check" "github.com/pkg/errors" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" ) type testingT interface { @@ -570,20 +572,13 @@ func (d *Daemon) WaitRun(contID string) error { return WaitInspectWithArgs(d.dockerBinary, contID, "{{.State.Running}}", "true", 10*time.Second, args...) } -// GetBaseDeviceSize returns the base device size of the daemon -func (d *Daemon) GetBaseDeviceSize(c *check.C) int64 { - infoCmdOutput, _, err := testutil.RunCommandPipelineWithOutput( - exec.Command(d.dockerBinary, "-H", d.Sock(), "info"), - exec.Command("grep", "Base Device Size"), - ) - c.Assert(err, checker.IsNil) - basesizeSlice := strings.Split(infoCmdOutput, ":") - basesize := strings.Trim(basesizeSlice[1], " ") - basesize = strings.Trim(basesize, "\n")[:len(basesize)-3] - basesizeFloat, err := strconv.ParseFloat(strings.Trim(basesize, " "), 64) - c.Assert(err, checker.IsNil) - basesizeBytes := int64(basesizeFloat) * (1024 * 1024 * 1024) - return basesizeBytes +// Info returns the info struct for this daemon +func (d *Daemon) Info(t require.TestingT) types.Info { + apiclient, err := request.NewClientForHost(d.Sock()) + require.NoError(t, err) + info, err := apiclient.Info(context.Background()) + require.NoError(t, err) + return info } // Cmd executes a docker CLI command against this daemon. diff --git a/integration-cli/docker_cli_cp_test.go b/integration-cli/docker_cli_cp_test.go index f7ed459194555..743398ca21182 100644 --- a/integration-cli/docker_cli_cp_test.go +++ b/integration-cli/docker_cli_cp_test.go @@ -11,7 +11,6 @@ import ( "strings" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" ) @@ -548,7 +547,7 @@ func (s *DockerSuite) TestCpToStdout(c *check.C) { // failed to set up container c.Assert(strings.TrimSpace(out), checker.Equals, "0") - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "cp", containerID+":/test", "-"), exec.Command("tar", "-vtf", "-")) diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 3155a351c47c0..8bcf850453355 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -201,7 +201,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithInvalidBasesize(c *check.C) { testRequires(c, Devicemapper) s.d.Start(c) - oldBasesizeBytes := s.d.GetBaseDeviceSize(c) + oldBasesizeBytes := getBaseDeviceSize(c, s.d) var newBasesizeBytes int64 = 1073741824 //1GB in bytes if newBasesizeBytes < oldBasesizeBytes { @@ -221,7 +221,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithIncreasedBasesize(c *check.C) { testRequires(c, Devicemapper) s.d.Start(c) - oldBasesizeBytes := s.d.GetBaseDeviceSize(c) + oldBasesizeBytes := getBaseDeviceSize(c, s.d) var newBasesizeBytes int64 = 53687091200 //50GB in bytes @@ -232,13 +232,31 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithIncreasedBasesize(c *check.C) { err := s.d.RestartWithError("--storage-opt", fmt.Sprintf("dm.basesize=%d", newBasesizeBytes)) c.Assert(err, check.IsNil, check.Commentf("we should have been able to start the daemon with increased base device size: %v", err)) - basesizeAfterRestart := s.d.GetBaseDeviceSize(c) + basesizeAfterRestart := getBaseDeviceSize(c, s.d) newBasesize, err := convertBasesize(newBasesizeBytes) c.Assert(err, check.IsNil, check.Commentf("Error in converting base device size: %v", err)) c.Assert(newBasesize, check.Equals, basesizeAfterRestart, check.Commentf("Basesize passed is not equal to Basesize set")) s.d.Stop(c) } +func getBaseDeviceSize(c *check.C, d *daemon.Daemon) int64 { + info := d.Info(c) + for _, statusLine := range info.DriverStatus { + key, value := statusLine[0], statusLine[1] + if key == "Base Device Size" { + return parseDeviceSize(c, value) + } + } + c.Fatal("failed to parse Base Device Size from info") + return int64(0) +} + +func parseDeviceSize(c *check.C, raw string) int64 { + size, err := units.RAMInBytes(strings.TrimSpace(raw)) + c.Assert(err, check.IsNil) + return size +} + func convertBasesize(basesizeBytes int64) (int64, error) { basesize := units.HumanSize(float64(basesizeBytes)) basesize = strings.Trim(basesize, " ")[:len(basesize)-3] diff --git a/integration-cli/docker_cli_events_test.go b/integration-cli/docker_cli_events_test.go index 0bbc9868433a9..f3d839a3174b9 100644 --- a/integration-cli/docker_cli_events_test.go +++ b/integration-cli/docker_cli_events_test.go @@ -18,7 +18,6 @@ import ( "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" ) @@ -230,7 +229,7 @@ func (s *DockerSuite) TestEventsImageImport(c *check.C) { cleanedContainerID := strings.TrimSpace(out) since := daemonUnixTime(c) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "export", cleanedContainerID), exec.Command(dockerBinary, "import", "-"), ) diff --git a/integration-cli/docker_cli_import_test.go b/integration-cli/docker_cli_import_test.go index 711f39b87e3ca..ac7a180461c96 100644 --- a/integration-cli/docker_cli_import_test.go +++ b/integration-cli/docker_cli_import_test.go @@ -11,7 +11,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" ) @@ -21,7 +20,7 @@ func (s *DockerSuite) TestImportDisplay(c *check.C) { out, _ := dockerCmd(c, "run", "-d", "busybox", "true") cleanedContainerID := strings.TrimSpace(out) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "export", cleanedContainerID), exec.Command(dockerBinary, "import", "-"), ) diff --git a/integration-cli/docker_cli_save_load_test.go b/integration-cli/docker_cli_save_load_test.go index 1f4c6708ed8e0..846f84d3b4284 100644 --- a/integration-cli/docker_cli_save_load_test.go +++ b/integration-cli/docker_cli_save_load_test.go @@ -17,7 +17,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli/build" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" digest "github.com/opencontainers/go-digest" @@ -34,7 +33,7 @@ func (s *DockerSuite) TestSaveXzAndLoadRepoStdout(c *check.C) { dockerCmd(c, "inspect", repoName) - repoTarball, _, err := testutil.RunCommandPipelineWithOutput( + repoTarball, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", repoName), exec.Command("xz", "-c"), exec.Command("gzip", "-c")) @@ -63,7 +62,7 @@ func (s *DockerSuite) TestSaveXzGzAndLoadRepoStdout(c *check.C) { dockerCmd(c, "inspect", repoName) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", repoName), exec.Command("xz", "-c"), exec.Command("gzip", "-c")) @@ -90,7 +89,7 @@ func (s *DockerSuite) TestSaveSingleTag(c *check.C) { out, _ := dockerCmd(c, "images", "-q", "--no-trunc", repoName) cleanedImageID := strings.TrimSpace(out) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", fmt.Sprintf("%v:latest", repoName)), exec.Command("tar", "t"), exec.Command("grep", "-E", fmt.Sprintf("(^repositories$|%v)", cleanedImageID))) @@ -109,7 +108,7 @@ func (s *DockerSuite) TestSaveCheckTimes(c *check.C) { c.Assert(err, checker.IsNil, check.Commentf("failed to marshal from %q: err %v", repoName, err)) c.Assert(len(data), checker.Not(checker.Equals), 0, check.Commentf("failed to marshal the data from %q", repoName)) tarTvTimeFormat := "2006-01-02 15:04" - out, _, err = testutil.RunCommandPipelineWithOutput( + out, err = RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", repoName), exec.Command("tar", "tv"), exec.Command("grep", "-E", fmt.Sprintf("%s %s", data[0].Created.Format(tarTvTimeFormat), digest.Digest(data[0].ID).Hex()))) @@ -167,7 +166,7 @@ func (s *DockerSuite) TestSaveAndLoadRepoFlags(c *check.C) { before, _ := dockerCmd(c, "inspect", repoName) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", repoName), exec.Command(dockerBinary, "load")) c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err)) @@ -196,7 +195,7 @@ func (s *DockerSuite) TestSaveMultipleNames(c *check.C) { // Make two images dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v-two:latest", repoName)) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", fmt.Sprintf("%v-one", repoName), fmt.Sprintf("%v-two:latest", repoName)), exec.Command("tar", "xO", "repositories"), exec.Command("grep", "-q", "-E", "(-one|-two)"), @@ -228,7 +227,7 @@ func (s *DockerSuite) TestSaveRepoWithMultipleImages(c *check.C) { deleteImages(repoName) // create the archive - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", repoName, "busybox:latest"), exec.Command("tar", "t")) c.Assert(err, checker.IsNil, check.Commentf("failed to save multiple images: %s, %v", out, err)) @@ -272,7 +271,7 @@ func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) { RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`)) - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", name), exec.Command("tar", "-xf", "-", "-C", extractionDirectory), ) @@ -384,7 +383,7 @@ func (s *DockerSuite) TestSaveLoadNoTag(c *check.C) { id := inspectField(c, name, "Id") // Test to make sure that save w/o name just shows imageID during load - out, _, err := testutil.RunCommandPipelineWithOutput( + out, err := RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", id), exec.Command(dockerBinary, "load")) c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err)) @@ -395,7 +394,7 @@ func (s *DockerSuite) TestSaveLoadNoTag(c *check.C) { c.Assert(out, checker.Contains, id) // Test to make sure that save by name shows that name during load - out, _, err = testutil.RunCommandPipelineWithOutput( + out, err = RunCommandPipelineWithOutput( exec.Command(dockerBinary, "save", name), exec.Command(dockerBinary, "load")) c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err)) diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index 3e39f47bf2935..e5f3a794ae0a0 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -12,7 +12,6 @@ import ( "net/http" "net/http/httptest" "os" - "os/exec" "path/filepath" "strings" "time" @@ -23,7 +22,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/daemon" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/docker/docker/pkg/testutil/tempfile" "github.com/docker/libnetwork/driverapi" @@ -467,14 +465,17 @@ func (s *DockerSwarmSuite) TestSwarmIngressNetwork(c *check.C) { d := s.AddDaemon(c, true, true) // Ingress network can be removed - out, _, err := testutil.RunCommandPipelineWithOutput( - exec.Command("echo", "Y"), - exec.Command("docker", "-H", d.Sock(), "network", "rm", "ingress"), - ) - c.Assert(err, checker.IsNil, check.Commentf(out)) + removeNetwork := func(name string) *icmd.Result { + return cli.Docker( + cli.Args("-H", d.Sock(), "network", "rm", name), + cli.WithStdin(strings.NewReader("Y"))) + } + + result := removeNetwork("ingress") + result.Assert(c, icmd.Success) // And recreated - out, err = d.Cmd("network", "create", "-d", "overlay", "--ingress", "new-ingress") + out, err := d.Cmd("network", "create", "-d", "overlay", "--ingress", "new-ingress") c.Assert(err, checker.IsNil, check.Commentf(out)) // But only one is allowed @@ -485,21 +486,19 @@ func (s *DockerSwarmSuite) TestSwarmIngressNetwork(c *check.C) { // It cannot be removed if it is being used out, err = d.Cmd("service", "create", "--no-resolve-image", "--name", "srv1", "-p", "9000:8000", "busybox", "top") c.Assert(err, checker.IsNil, check.Commentf(out)) - out, _, err = testutil.RunCommandPipelineWithOutput( - exec.Command("echo", "Y"), - exec.Command("docker", "-H", d.Sock(), "network", "rm", "new-ingress"), - ) - c.Assert(err, checker.NotNil) - c.Assert(strings.TrimSpace(out), checker.Contains, "ingress network cannot be removed because service") + + result = removeNetwork("new-ingress") + result.Assert(c, icmd.Expected{ + ExitCode: 1, + Err: "ingress network cannot be removed because service", + }) // But it can be removed once no more services depend on it out, err = d.Cmd("service", "update", "--publish-rm", "9000:8000", "srv1") c.Assert(err, checker.IsNil, check.Commentf(out)) - out, _, err = testutil.RunCommandPipelineWithOutput( - exec.Command("echo", "Y"), - exec.Command("docker", "-H", d.Sock(), "network", "rm", "new-ingress"), - ) - c.Assert(err, checker.IsNil, check.Commentf(out)) + + result = removeNetwork("new-ingress") + result.Assert(c, icmd.Success) // A service which needs the ingress network cannot be created if no ingress is present out, err = d.Cmd("service", "create", "--no-resolve-image", "--name", "srv2", "-p", "500:500", "busybox", "top") @@ -520,15 +519,14 @@ func (s *DockerSwarmSuite) TestSwarmCreateServiceWithNoIngressNetwork(c *check.C d := s.AddDaemon(c, true, true) // Remove ingress network - out, _, err := testutil.RunCommandPipelineWithOutput( - exec.Command("echo", "Y"), - exec.Command("docker", "-H", d.Sock(), "network", "rm", "ingress"), - ) - c.Assert(err, checker.IsNil, check.Commentf(out)) + result := cli.Docker( + cli.Args("-H", d.Sock(), "network", "rm", "ingress"), + cli.WithStdin(strings.NewReader("Y"))) + result.Assert(c, icmd.Success) // Create a overlay network and launch a service on it // Make sure nothing panics because ingress network is missing - out, err = d.Cmd("network", "create", "-d", "overlay", "another-network") + out, err := d.Cmd("network", "create", "-d", "overlay", "another-network") c.Assert(err, checker.IsNil, check.Commentf(out)) out, err = d.Cmd("service", "create", "--no-resolve-image", "--name", "srv4", "--network", "another-network", "busybox", "top") c.Assert(err, checker.IsNil, check.Commentf(out)) diff --git a/integration-cli/docker_cli_userns_test.go b/integration-cli/docker_cli_userns_test.go index 8311401d0ec16..54cfdd179cd07 100644 --- a/integration-cli/docker_cli_userns_test.go +++ b/integration-cli/docker_cli_userns_test.go @@ -15,7 +15,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/system" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" ) @@ -62,15 +61,15 @@ func (s *DockerDaemonSuite) TestDaemonUserNamespaceRootSetting(c *check.C) { c.Assert(err, checker.IsNil, check.Commentf("Could not inspect running container: out: %q", pid)) // check the uid and gid maps for the PID to ensure root is remapped // (cmd = cat /proc//uid_map | grep -E '0\s+9999\s+1') - out, rc1, err := testutil.RunCommandPipelineWithOutput( + out, err = RunCommandPipelineWithOutput( exec.Command("cat", "/proc/"+strings.TrimSpace(pid)+"/uid_map"), exec.Command("grep", "-E", fmt.Sprintf("0[[:space:]]+%d[[:space:]]+", uid))) - c.Assert(rc1, checker.Equals, 0, check.Commentf("Didn't match uid_map: output: %s", out)) + c.Assert(err, check.IsNil) - out, rc2, err := testutil.RunCommandPipelineWithOutput( + out, err = RunCommandPipelineWithOutput( exec.Command("cat", "/proc/"+strings.TrimSpace(pid)+"/gid_map"), exec.Command("grep", "-E", fmt.Sprintf("0[[:space:]]+%d[[:space:]]+", gid))) - c.Assert(rc2, checker.Equals, 0, check.Commentf("Didn't match gid_map: output: %s", out)) + c.Assert(err, check.IsNil) // check that the touched file is owned by remapped uid:gid stat, err := system.Stat(filepath.Join(tmpDir, "testfile")) diff --git a/integration-cli/request/request.go b/integration-cli/request/request.go index 3af0e43e82c05..72632f3f7635a 100644 --- a/integration-cli/request/request.go +++ b/integration-cli/request/request.go @@ -165,7 +165,11 @@ func NewHTTPClient(host string) (*http.Client, error) { // NewClient returns a new Docker API client func NewClient() (dclient.APIClient, error) { - host := DaemonHost() + return NewClientForHost(DaemonHost()) +} + +// NewClientForHost returns a Docker API client for the host +func NewClientForHost(host string) (dclient.APIClient, error) { httpClient, err := NewHTTPClient(host) if err != nil { return nil, err diff --git a/integration-cli/utils_test.go b/integration-cli/utils_test.go index 2497b4a39cba7..9d9f83abdd148 100644 --- a/integration-cli/utils_test.go +++ b/integration-cli/utils_test.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/testutil/cmd" + "github.com/pkg/errors" ) func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) { @@ -64,3 +65,50 @@ func RandomTmpDirPath(s string, platform string) string { } return filepath.ToSlash(path) // Using / } + +// 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 +// if something bad happened. +// Deprecated: use icmd instead +func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, err error) { + if len(cmds) < 2 { + return "", errors.New("pipeline does not have multiple cmds") + } + + // connect stdin of each cmd to stdout pipe of previous cmd + for i, cmd := range cmds { + if i > 0 { + prevCmd := cmds[i-1] + cmd.Stdin, err = prevCmd.StdoutPipe() + + if err != nil { + return "", fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err) + } + } + } + + // start all cmds except the last + for _, cmd := range cmds[:len(cmds)-1] { + if err = cmd.Start(); err != nil { + return "", fmt.Errorf("starting %s failed with error: %v", cmd.Path, err) + } + } + + defer func() { + var pipeErrMsgs []string + // wait all cmds except the last to release their resources + for _, cmd := range cmds[:len(cmds)-1] { + if pipeErr := cmd.Wait(); pipeErr != nil { + pipeErrMsgs = append(pipeErrMsgs, fmt.Sprintf("command %s failed with error: %v", cmd.Path, pipeErr)) + } + } + if len(pipeErrMsgs) > 0 && err == nil { + err = fmt.Errorf("pipelineError from Wait: %v", strings.Join(pipeErrMsgs, ", ")) + } + }() + + // wait on last cmd + out, err := cmds[len(cmds)-1].CombinedOutput() + return string(out), err +} diff --git a/pkg/testutil/utils.go b/pkg/testutil/utils.go deleted file mode 100644 index f59ea54ab8fcc..0000000000000 --- a/pkg/testutil/utils.go +++ /dev/null @@ -1,62 +0,0 @@ -package testutil - -import ( - "errors" - "fmt" - "os/exec" - "strings" - - "github.com/docker/docker/pkg/system" -) - -func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) { - out, err := cmd.CombinedOutput() - exitCode = system.ProcessExitCode(err) - output = string(out) - 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 -// if something bad happened. -func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode int, err error) { - if len(cmds) < 2 { - return "", 0, errors.New("pipeline does not have multiple cmds") - } - - // connect stdin of each cmd to stdout pipe of previous cmd - for i, cmd := range cmds { - if i > 0 { - prevCmd := cmds[i-1] - cmd.Stdin, err = prevCmd.StdoutPipe() - - if err != nil { - return "", 0, fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err) - } - } - } - - // start all cmds except the last - for _, cmd := range cmds[:len(cmds)-1] { - if err = cmd.Start(); err != nil { - return "", 0, fmt.Errorf("starting %s failed with error: %v", cmd.Path, err) - } - } - - defer func() { - var pipeErrMsgs []string - // wait all cmds except the last to release their resources - for _, cmd := range cmds[:len(cmds)-1] { - if pipeErr := cmd.Wait(); pipeErr != nil { - pipeErrMsgs = append(pipeErrMsgs, fmt.Sprintf("command %s failed with error: %v", cmd.Path, pipeErr)) - } - } - if len(pipeErrMsgs) > 0 && err == nil { - err = fmt.Errorf("pipelineError from Wait: %v", strings.Join(pipeErrMsgs, ", ")) - } - }() - - // wait on last cmd - return runCommandWithOutput(cmds[len(cmds)-1]) -} diff --git a/pkg/testutil/utils_test.go b/pkg/testutil/utils_test.go deleted file mode 100644 index c475a6b9bef5f..0000000000000 --- a/pkg/testutil/utils_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package testutil - -import ( - "os" - "os/exec" - "runtime" - "testing" -) - -func TestRunCommandPipelineWithOutputWithNotEnoughCmds(t *testing.T) { - _, _, err := RunCommandPipelineWithOutput(exec.Command("ls")) - expectedError := "pipeline does not have multiple cmds" - if err == nil || err.Error() != expectedError { - t.Fatalf("Expected an error with %s, got err:%s", expectedError, err) - } -} - -func TestRunCommandPipelineWithOutputErrors(t *testing.T) { - p := "$PATH" - if runtime.GOOS == "windows" { - p = "%PATH%" - } - cmd1 := exec.Command("ls") - cmd1.Stdout = os.Stdout - cmd2 := exec.Command("anything really") - _, _, err := RunCommandPipelineWithOutput(cmd1, cmd2) - if err == nil || err.Error() != "cannot set stdout pipe for anything really: exec: Stdout already set" { - t.Fatalf("Expected an error, got %v", err) - } - - cmdWithError := exec.Command("doesnotexists") - cmdCat := exec.Command("cat") - _, _, err = RunCommandPipelineWithOutput(cmdWithError, cmdCat) - if err == nil || err.Error() != `starting doesnotexists failed with error: exec: "doesnotexists": executable file not found in `+p { - t.Fatalf("Expected an error, got %v", err) - } -} - -func TestRunCommandPipelineWithOutput(t *testing.T) { - //TODO: Should run on Solaris - if runtime.GOOS == "solaris" { - t.Skip() - } - cmds := []*exec.Cmd{ - // Print 2 characters - exec.Command("echo", "-n", "11"), - // Count the number or char from stdin (previous command) - exec.Command("wc", "-m"), - } - out, exitCode, err := RunCommandPipelineWithOutput(cmds...) - expectedOutput := "2\n" - if out != expectedOutput || exitCode != 0 || err != nil { - t.Fatalf("Expected %s for commands %v, got out:%s, exitCode:%d, err:%v", expectedOutput, cmds, out, exitCode, err) - } -}