diff --git a/builder/remotecontext/remote_test.go b/builder/remotecontext/remote_test.go index c698726e8b..fae0a30240 100644 --- a/builder/remotecontext/remote_test.go +++ b/builder/remotecontext/remote_test.go @@ -253,7 +253,7 @@ func TestGetWithStatusError(t *testing.T) { if testcase.expectedErr == "" { require.NoError(t, err) - body, err := testutil.ReadBody(response.Body) + body, err := readBody(response.Body) require.NoError(t, err) assert.Contains(t, string(body), testcase.expectedBody) } else { @@ -261,3 +261,8 @@ func TestGetWithStatusError(t *testing.T) { } } } + +func readBody(b io.ReadCloser) ([]byte, error) { + defer b.Close() + return ioutil.ReadAll(b) +} diff --git a/integration-cli/cli/cli.go b/integration-cli/cli/cli.go index d8355217e3..55ac0913fc 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 8b086c9425..aa1da1a690 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 { @@ -545,7 +547,7 @@ func (d *Daemon) queryRootDir() (string, error) { } var b []byte var i Info - b, err = testutil.ReadBody(body) + b, err = request.ReadBody(body) if err == nil && resp.StatusCode == http.StatusOK { // read the docker root dir if err = json.Unmarshal(b, &i); err == nil { @@ -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. @@ -620,7 +615,7 @@ func (d *Daemon) SockRequest(method, endpoint string, data interface{}) (int, [] if err != nil { return -1, nil, err } - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) return res.StatusCode, b, err } diff --git a/integration-cli/docker_api_attach_test.go b/integration-cli/docker_api_attach_test.go index 11f7340c1f..20829335a1 100644 --- a/integration-cli/docker_api_attach_test.go +++ b/integration-cli/docker_api_attach_test.go @@ -15,7 +15,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/docker/docker/pkg/stdcopy" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" "golang.org/x/net/websocket" ) @@ -80,7 +79,7 @@ func (s *DockerSuite) TestPostContainersAttachContainerNotFound(c *check.C) { resp, err := client.Do(req) // connection will shutdown, err should be "persistent connection closed" c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound) - content, err := testutil.ReadBody(resp.Body) + content, err := request.ReadBody(resp.Body) c.Assert(err, checker.IsNil) expected := "No such container: doesnotexist\r\n" c.Assert(string(content), checker.Equals, expected) diff --git a/integration-cli/docker_api_build_test.go b/integration-cli/docker_api_build_test.go index fb62917823..fa6fc3556a 100644 --- a/integration-cli/docker_api_build_test.go +++ b/integration-cli/docker_api_build_test.go @@ -17,7 +17,6 @@ import ( "github.com/docker/docker/integration-cli/cli/build/fakegit" "github.com/docker/docker/integration-cli/cli/build/fakestorage" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/filesync" @@ -47,7 +46,7 @@ RUN find /tmp/` c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusOK) - buf, err := testutil.ReadBody(body) + buf, err := request.ReadBody(body) c.Assert(err, checker.IsNil) // Make sure Dockerfile exists. @@ -135,7 +134,7 @@ RUN echo 'right' c.Assert(res.StatusCode, checker.Equals, http.StatusOK) defer body.Close() - content, err := testutil.ReadBody(body) + content, err := request.ReadBody(body) c.Assert(err, checker.IsNil) // Build used the wrong dockerfile. @@ -153,7 +152,7 @@ RUN echo from dockerfile`, c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusOK) - buf, err := testutil.ReadBody(body) + buf, err := request.ReadBody(body) c.Assert(err, checker.IsNil) out := string(buf) @@ -174,7 +173,7 @@ RUN echo from Dockerfile`, c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusOK) - buf, err := testutil.ReadBody(body) + buf, err := request.ReadBody(body) c.Assert(err, checker.IsNil) out := string(buf) @@ -196,7 +195,7 @@ RUN echo from dockerfile`, c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusOK) - buf, err := testutil.ReadBody(body) + buf, err := request.ReadBody(body) c.Assert(err, checker.IsNil) out := string(buf) @@ -243,7 +242,7 @@ func (s *DockerSuite) TestBuildAPIUnnormalizedTarPaths(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusOK) - out, err := testutil.ReadBody(body) + out, err := request.ReadBody(body) c.Assert(err, checker.IsNil) lines := strings.Split(string(out), "\n") c.Assert(len(lines), checker.GreaterThan, 1) @@ -280,7 +279,7 @@ func (s *DockerSuite) TestBuildOnBuildWithCopy(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusOK) - out, err := testutil.ReadBody(body) + out, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(string(out), checker.Contains, "Successfully built") } @@ -299,7 +298,7 @@ func (s *DockerSuite) TestBuildOnBuildCache(c *check.C) { require.NoError(c, err) assert.Equal(c, http.StatusOK, res.StatusCode) - out, err := testutil.ReadBody(body) + out, err := request.ReadBody(body) require.NoError(c, err) assert.Contains(c, string(out), "Successfully built") return out @@ -361,7 +360,7 @@ func (s *DockerRegistrySuite) TestBuildCopyFromForcePull(c *check.C) { require.NoError(c, err) assert.Equal(c, http.StatusOK, res.StatusCode) - out, err := testutil.ReadBody(body) + out, err := request.ReadBody(body) require.NoError(c, err) assert.Contains(c, string(out), "Successfully built") } @@ -405,7 +404,7 @@ func (s *DockerSuite) TestBuildAddRemoteNoDecompress(c *check.C) { require.NoError(c, err) assert.Equal(c, http.StatusOK, res.StatusCode) - out, err := testutil.ReadBody(body) + out, err := request.ReadBody(body) require.NoError(c, err) assert.Contains(c, string(out), "Successfully built") } @@ -461,7 +460,7 @@ func (s *DockerSuite) TestBuildWithSession(c *check.C) { require.NoError(c, err) assert.Equal(c, http.StatusOK, res.StatusCode) - outBytes, err := testutil.ReadBody(body) + outBytes, err := request.ReadBody(body) require.NoError(c, err) assert.Contains(c, string(outBytes), "Successfully built") assert.Equal(c, strings.Count(string(outBytes), "Using cache"), 4) @@ -499,7 +498,7 @@ func testBuildWithSession(c *check.C, dir, dockerfile string) (outStr string) { return err } assert.Equal(c, res.StatusCode, http.StatusOK) - out, err := testutil.ReadBody(body) + out, err := request.ReadBody(body) require.NoError(c, err) assert.Contains(c, string(out), "Successfully built") sess.Close() diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index 72b4807a55..cd3992a6f9 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -27,7 +27,6 @@ import ( "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/stringid" - "github.com/docker/docker/pkg/testutil" "github.com/docker/docker/volume" "github.com/go-check/check" ) @@ -215,7 +214,7 @@ func (s *DockerSuite) TestGetContainerStatsRmRunning(c *check.C) { out := runSleepingContainer(c) id := strings.TrimSpace(out) - buf := &testutil.ChannelBuffer{C: make(chan []byte, 1)} + buf := &ChannelBuffer{C: make(chan []byte, 1)} defer buf.Close() _, body, err := request.Get("/containers/"+id+"/stats?stream=1", request.JSON) @@ -243,6 +242,34 @@ func (s *DockerSuite) TestGetContainerStatsRmRunning(c *check.C) { c.Assert(<-chErr, checker.IsNil) } +// ChannelBuffer holds a chan of byte array that can be populate in a goroutine. +type ChannelBuffer struct { + C chan []byte +} + +// Write implements Writer. +func (c *ChannelBuffer) Write(b []byte) (int, error) { + c.C <- b + return len(b), nil +} + +// Close closes the go channel. +func (c *ChannelBuffer) Close() error { + close(c.C) + return nil +} + +// ReadTimeout reads the content of the channel in the specified byte array with +// the specified duration as timeout. +func (c *ChannelBuffer) ReadTimeout(p []byte, n time.Duration) (int, error) { + select { + case b := <-c.C: + return copy(p[0:], b), nil + case <-time.After(n): + return -1, fmt.Errorf("timeout reading from channel") + } +} + // regression test for gh13421 // previous test was just checking one stat entry so it didn't fail (stats with // stream false always return one stat) @@ -707,7 +734,7 @@ func (s *DockerSuite) TestContainerAPIInvalidPortSyntax(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(string(b[:]), checker.Contains, "invalid port") } @@ -727,7 +754,7 @@ func (s *DockerSuite) TestContainerAPIRestartPolicyInvalidPolicyName(c *check.C) c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(string(b[:]), checker.Contains, "invalid restart policy") } @@ -747,7 +774,7 @@ func (s *DockerSuite) TestContainerAPIRestartPolicyRetryMismatch(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(string(b[:]), checker.Contains, "maximum retry count cannot be used with restart policy") } @@ -767,7 +794,7 @@ func (s *DockerSuite) TestContainerAPIRestartPolicyNegativeRetryCount(c *check.C c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(string(b[:]), checker.Contains, "maximum retry count cannot be negative") } @@ -818,7 +845,7 @@ func (s *DockerSuite) TestContainerAPIPostCreateNull(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusCreated) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) type createResp struct { ID string @@ -847,7 +874,7 @@ func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) { res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON) c.Assert(err, checker.IsNil) - b, err2 := testutil.ReadBody(body) + b, err2 := request.ReadBody(body) c.Assert(err2, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) diff --git a/integration-cli/docker_api_exec_test.go b/integration-cli/docker_api_exec_test.go index 8118aa94a7..1d7a773d9b 100644 --- a/integration-cli/docker_api_exec_test.go +++ b/integration-cli/docker_api_exec_test.go @@ -12,7 +12,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" ) @@ -42,7 +41,7 @@ func (s *DockerSuite) TestExecAPICreateNoValidContentType(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) comment := check.Commentf("Expected message when creating exec command with invalid Content-Type specified") @@ -109,7 +108,7 @@ func (s *DockerSuite) TestExecAPIStartBackwardsCompatible(c *check.C) { resp, body, err := request.Post(fmt.Sprintf("/v1.20/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.ContentType("text/plain")) c.Assert(err, checker.IsNil) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) comment := check.Commentf("response body: %s", b) c.Assert(err, checker.IsNil, comment) c.Assert(resp.StatusCode, checker.Equals, http.StatusOK, comment) @@ -144,7 +143,7 @@ func (s *DockerSuite) TestExecAPIStartWithDetach(c *check.C) { _, body, err := request.Post(fmt.Sprintf("/exec/%s/start", createResp.ID), request.RawString(`{"Detach": true}`), request.JSON) c.Assert(err, checker.IsNil) - b, err = testutil.ReadBody(body) + b, err = request.ReadBody(body) comment := check.Commentf("response body: %s", b) c.Assert(err, checker.IsNil, comment) @@ -207,7 +206,7 @@ func startExec(c *check.C, id string, code int) { resp, body, err := request.Post(fmt.Sprintf("/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.JSON) c.Assert(err, checker.IsNil) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) comment := check.Commentf("response body: %s", b) c.Assert(err, checker.IsNil, comment) c.Assert(resp.StatusCode, checker.Equals, code, comment) diff --git a/integration-cli/docker_api_info_test.go b/integration-cli/docker_api_info_test.go index 9cb873d608..8bc437bf79 100644 --- a/integration-cli/docker_api_info_test.go +++ b/integration-cli/docker_api_info_test.go @@ -1,13 +1,12 @@ package main import ( + "encoding/json" "net/http" - "encoding/json" "github.com/docker/docker/api/types" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" ) @@ -52,7 +51,7 @@ func (s *DockerSuite) TestInfoAPIRuncCommit(c *check.C) { c.Assert(res.StatusCode, checker.Equals, http.StatusOK) c.Assert(err, checker.IsNil) - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) var i types.Info diff --git a/integration-cli/docker_api_session_test.go b/integration-cli/docker_api_session_test.go index e1ad880ea7..f1c44892d3 100644 --- a/integration-cli/docker_api_session_test.go +++ b/integration-cli/docker_api_session_test.go @@ -5,7 +5,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" ) @@ -29,7 +28,7 @@ func (s *DockerSuite) TestSessionCreateWithBadUpgrade(c *check.C) { res, body, err := request.Post("/session") c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - buf, err := testutil.ReadBody(body) + buf, err := request.ReadBody(body) c.Assert(err, checker.IsNil) out := string(buf) @@ -41,7 +40,7 @@ func (s *DockerSuite) TestSessionCreateWithBadUpgrade(c *check.C) { }) c.Assert(err, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - buf, err = testutil.ReadBody(body) + buf, err = request.ReadBody(body) c.Assert(err, checker.IsNil) out = string(buf) diff --git a/integration-cli/docker_api_test.go b/integration-cli/docker_api_test.go index 24a12d2783..af189b9d07 100644 --- a/integration-cli/docker_api_test.go +++ b/integration-cli/docker_api_test.go @@ -11,7 +11,6 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" ) @@ -62,7 +61,7 @@ func (s *DockerSuite) TestAPIErrorJSON(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(httpResp.StatusCode, checker.Equals, http.StatusBadRequest) c.Assert(httpResp.Header.Get("Content-Type"), checker.Equals, "application/json") - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(getErrorMessage(c, b), checker.Equals, "Config cannot be empty in order to create a container") } @@ -75,7 +74,7 @@ func (s *DockerSuite) TestAPIErrorPlainText(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(httpResp.StatusCode, checker.Equals, http.StatusBadRequest) c.Assert(httpResp.Header.Get("Content-Type"), checker.Contains, "text/plain") - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(strings.TrimSpace(string(b)), checker.Equals, "Config cannot be empty in order to create a container") } @@ -86,7 +85,7 @@ func (s *DockerSuite) TestAPIErrorNotFoundJSON(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(httpResp.StatusCode, checker.Equals, http.StatusNotFound) c.Assert(httpResp.Header.Get("Content-Type"), checker.Equals, "application/json") - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(getErrorMessage(c, b), checker.Equals, "page not found") } @@ -96,7 +95,7 @@ func (s *DockerSuite) TestAPIErrorNotFoundPlainText(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(httpResp.StatusCode, checker.Equals, http.StatusNotFound) c.Assert(httpResp.Header.Get("Content-Type"), checker.Contains, "text/plain") - b, err := testutil.ReadBody(body) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) c.Assert(strings.TrimSpace(string(b)), checker.Equals, "page not found") } diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 5a3d3efc65..5f94b35daa 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -25,10 +25,9 @@ import ( "github.com/docker/docker/integration-cli/cli/build/fakestorage" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/stringutils" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" - "github.com/opencontainers/go-digest" + digest "github.com/opencontainers/go-digest" ) func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) { @@ -1526,7 +1525,7 @@ func (s *DockerSuite) TestBuildContextCleanup(c *check.C) { if err != nil { c.Fatalf("failed to list contents of tmp dir: %s", err) } - if err = testutil.CompareDirectoryEntries(entries, entriesFinal); err != nil { + if err = compareDirectoryEntries(entries, entriesFinal); err != nil { c.Fatalf("context should have been deleted, but wasn't") } @@ -1550,12 +1549,31 @@ func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) { if err != nil { c.Fatalf("failed to list contents of tmp dir: %s", err) } - if err = testutil.CompareDirectoryEntries(entries, entriesFinal); err != nil { + if err = compareDirectoryEntries(entries, entriesFinal); err != nil { c.Fatalf("context should have been deleted, but wasn't") } } +// compareDirectoryEntries compares two sets of FileInfo (usually taken from a directory) +// and returns an error if different. +func compareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error { + var ( + e1Entries = make(map[string]struct{}) + e2Entries = make(map[string]struct{}) + ) + for _, e := range e1 { + e1Entries[e.Name()] = struct{}{} + } + for _, e := range e2 { + e2Entries[e.Name()] = struct{}{} + } + if !reflect.DeepEqual(e1Entries, e2Entries) { + return fmt.Errorf("entries differ") + } + return nil +} + func (s *DockerSuite) TestBuildCmd(c *check.C) { name := "testbuildcmd" expected := "[/bin/echo Hello World]" @@ -4052,7 +4070,7 @@ func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) { if err != nil { c.Fatalf("failed to read '/proc/self/cgroup - %v", err) } - selfCgroupPaths := testutil.ParseCgroupPaths(string(data)) + selfCgroupPaths := ParseCgroupPaths(string(data)) _, found := selfCgroupPaths["memory"] if !found { c.Fatalf("unable to find self memory cgroup path. CgroupsPath: %v", selfCgroupPaths) diff --git a/integration-cli/docker_cli_build_unix_test.go b/integration-cli/docker_cli_build_unix_test.go index 11c6823255..7083fccb17 100644 --- a/integration-cli/docker_cli_build_unix_test.go +++ b/integration-cli/docker_cli_build_unix_test.go @@ -12,15 +12,15 @@ import ( "path/filepath" "regexp" "strings" + "syscall" "time" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" "github.com/docker/docker/integration-cli/cli/build/fakecontext" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" - "github.com/docker/go-units" + units "github.com/docker/go-units" "github.com/go-check/check" ) @@ -191,7 +191,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 && !testutil.IsKilled(err) { + if err := buildCmd.Wait(); err != nil && !isKilled(err) { c.Fatalf("wait failed during build run: %T %s", err, err) } @@ -202,3 +202,17 @@ func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) { // ignore, done } } + +func isKilled(err error) bool { + if exitErr, ok := err.(*exec.ExitError); ok { + status, ok := exitErr.Sys().(syscall.WaitStatus) + if !ok { + return false + } + // status.ExitStatus() is required on Windows because it does not + // implement Signal() nor Signaled(). Just check it had a bad exit + // status could mean it was killed (and in tests we do kill) + return (status.Signaled() && status.Signal() == os.Kill) || status.ExitStatus() != 0 + } + return false +} diff --git a/integration-cli/docker_cli_cp_test.go b/integration-cli/docker_cli_cp_test.go index f7ed459194..743398ca21 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 55b45a9724..8bcf850453 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -34,7 +34,6 @@ import ( "github.com/docker/docker/opts" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/stringid" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" units "github.com/docker/go-units" "github.com/docker/libnetwork/iptables" @@ -202,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 { @@ -222,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 @@ -233,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] @@ -1883,7 +1900,7 @@ func (s *DockerDaemonSuite) TestDaemonCgroupParent(c *check.C) { out, err := s.d.Cmd("run", "--name", name, "busybox", "cat", "/proc/self/cgroup") c.Assert(err, checker.IsNil) - cgroupPaths := testutil.ParseCgroupPaths(string(out)) + cgroupPaths := ParseCgroupPaths(string(out)) c.Assert(len(cgroupPaths), checker.Not(checker.Equals), 0, check.Commentf("unexpected output - %q", string(out))) out, err = s.d.Cmd("inspect", "-f", "{{.Id}}", name) c.Assert(err, checker.IsNil) diff --git a/integration-cli/docker_cli_events_test.go b/integration-cli/docker_cli_events_test.go index 0bbc986843..f3d839a317 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 711f39b87e..ac7a180461 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_links_test.go b/integration-cli/docker_cli_links_test.go index 7c9ce739ce..0b4f30cfe9 100644 --- a/integration-cli/docker_cli_links_test.go +++ b/integration-cli/docker_cli_links_test.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" "regexp" + "sort" "strings" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/pkg/testutil" "github.com/docker/docker/runconfig" "github.com/go-check/check" ) @@ -90,40 +90,41 @@ func (s *DockerSuite) TestLinksPingLinkedContainersAfterRename(c *check.C) { func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) { testRequires(c, DaemonIsLinux) - var ( - expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}} - result []string - ) dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top") dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top") links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links") + var result []string err := json.Unmarshal([]byte(links), &result) c.Assert(err, checker.IsNil) - output := testutil.ConvertSliceOfStringsToMap(result) - - c.Assert(output, checker.DeepEquals, expected) + var expected = []string{ + "/container1:/testinspectlink/alias1", + "/container2:/testinspectlink/alias2", + } + sort.Strings(result) + c.Assert(result, checker.DeepEquals, expected) } func (s *DockerSuite) TestLinksInspectLinksStopped(c *check.C) { testRequires(c, DaemonIsLinux) - var ( - expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}} - result []string - ) + dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top") dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top") dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true") links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links") + var result []string err := json.Unmarshal([]byte(links), &result) c.Assert(err, checker.IsNil) - output := testutil.ConvertSliceOfStringsToMap(result) - - c.Assert(output, checker.DeepEquals, expected) + var expected = []string{ + "/container1:/testinspectlink/alias1", + "/container2:/testinspectlink/alias2", + } + sort.Strings(result) + c.Assert(result, checker.DeepEquals, expected) } func (s *DockerSuite) TestLinksNotStartedParentNotFail(c *check.C) { diff --git a/integration-cli/docker_cli_logs_test.go b/integration-cli/docker_cli_logs_test.go index a8b8f90548..8304d6eedb 100644 --- a/integration-cli/docker_cli_logs_test.go +++ b/integration-cli/docker_cli_logs_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/jsonlog" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" ) @@ -232,11 +231,11 @@ func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) { c.Assert(logCmd.Start(), checker.IsNil) // First read slowly - bytes1, err := testutil.ConsumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead) + bytes1, err := ConsumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead) c.Assert(err, checker.IsNil) // After the container has finished we can continue reading fast - bytes2, err := testutil.ConsumeWithSpeed(stdout, 32*1024, 0, nil) + bytes2, err := ConsumeWithSpeed(stdout, 32*1024, 0, nil) c.Assert(err, checker.IsNil) actual := bytes1 + bytes2 @@ -244,6 +243,29 @@ func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) { c.Assert(actual, checker.Equals, expected) } +// ConsumeWithSpeed reads chunkSize bytes from reader before sleeping +// for interval duration. Returns total read bytes. Send true to the +// stop channel to return before reading to EOF on the reader. +func ConsumeWithSpeed(reader io.Reader, chunkSize int, interval time.Duration, stop chan bool) (n int, err error) { + buffer := make([]byte, chunkSize) + for { + var readBytes int + readBytes, err = reader.Read(buffer) + n += readBytes + if err != nil { + if err == io.EOF { + err = nil + } + return + } + select { + case <-stop: + return + case <-time.After(interval): + } + } +} + func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) { out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 2; done") id := strings.TrimSpace(out) diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index d080086f78..8d18b7357a 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -28,7 +28,6 @@ import ( "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringutils" - "github.com/docker/docker/pkg/testutil" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/docker/docker/runconfig" "github.com/docker/go-connections/nat" @@ -495,7 +494,7 @@ func (s *DockerSuite) TestRunVolumesFromInReadWriteMode(c *check.C) { func (s *DockerSuite) TestVolumesFromGetsProperMode(c *check.C) { testRequires(c, SameHostDaemon) prefix, slash := getPrefixAndSlashFromDaemonPlatform() - hostpath := testutil.RandomTmpDirPath("test", testEnv.DaemonPlatform()) + hostpath := RandomTmpDirPath("test", testEnv.DaemonPlatform()) if err := os.MkdirAll(hostpath, 0755); err != nil { c.Fatalf("Failed to create %s: %q", hostpath, err) } @@ -518,8 +517,8 @@ func (s *DockerSuite) TestVolumesFromGetsProperMode(c *check.C) { // Test for GH#10618 func (s *DockerSuite) TestRunNoDupVolumes(c *check.C) { - path1 := testutil.RandomTmpDirPath("test1", testEnv.DaemonPlatform()) - path2 := testutil.RandomTmpDirPath("test2", testEnv.DaemonPlatform()) + path1 := RandomTmpDirPath("test1", testEnv.DaemonPlatform()) + path2 := RandomTmpDirPath("test2", testEnv.DaemonPlatform()) someplace := ":/someplace" if testEnv.DaemonPlatform() == "windows" { @@ -2183,7 +2182,7 @@ func (s *DockerSuite) TestVolumesNoCopyData(c *check.C) { c.Fatalf("Data was copied on volumes-from but shouldn't be:\n%q", out) } - tmpDir := testutil.RandomTmpDirPath("docker_test_bind_mount_copy_data", testEnv.DaemonPlatform()) + tmpDir := RandomTmpDirPath("docker_test_bind_mount_copy_data", testEnv.DaemonPlatform()) if out, _, err := dockerCmdWithError("run", "-v", tmpDir+":/foo", "dataimage", "ls", "-lh", "/foo/bar"); err == nil || !strings.Contains(out, "No such file or directory") { c.Fatalf("Data was copied on bind mount but shouldn't be:\n%q", out) } @@ -2247,7 +2246,7 @@ func (s *DockerSuite) TestRunSlowStdoutConsumer(c *check.C) { if err := cont.Start(); err != nil { c.Fatal(err) } - n, err := testutil.ConsumeWithSpeed(stdout, 10000, 5*time.Millisecond, nil) + n, err := ConsumeWithSpeed(stdout, 10000, 5*time.Millisecond, nil) if err != nil { c.Fatal(err) } @@ -3337,7 +3336,7 @@ func testRunContainerWithCgroupParent(c *check.C, cgroupParent, name string) { if err != nil { c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) } - cgroupPaths := testutil.ParseCgroupPaths(string(out)) + cgroupPaths := ParseCgroupPaths(string(out)) if len(cgroupPaths) == 0 { c.Fatalf("unexpected output - %q", string(out)) } @@ -3377,7 +3376,7 @@ func testRunInvalidCgroupParent(c *check.C, cgroupParent, cleanCgroupParent, nam c.Fatalf("SECURITY: --cgroup-parent with ../../ relative paths cause files to be created in the host (this is bad) !!") } - cgroupPaths := testutil.ParseCgroupPaths(string(out)) + cgroupPaths := ParseCgroupPaths(string(out)) if len(cgroupPaths) == 0 { c.Fatalf("unexpected output - %q", string(out)) } diff --git a/integration-cli/docker_cli_save_load_test.go b/integration-cli/docker_cli_save_load_test.go index 3b14576f73..846f84d3b4 100644 --- a/integration-cli/docker_cli_save_load_test.go +++ b/integration-cli/docker_cli_save_load_test.go @@ -1,8 +1,10 @@ package main import ( + "archive/tar" "encoding/json" "fmt" + "io" "io/ioutil" "os" "os/exec" @@ -15,10 +17,9 @@ 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" - "github.com/opencontainers/go-digest" + digest "github.com/opencontainers/go-digest" ) // save a repo using gz compression and try to load it using stdout @@ -32,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")) @@ -61,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")) @@ -88,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))) @@ -107,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()))) @@ -165,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)) @@ -194,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)"), @@ -226,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)) @@ -270,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), ) @@ -289,7 +290,7 @@ func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) { c.Assert(err, checker.IsNil, check.Commentf("failed to open %s: %s", layerPath, err)) defer f.Close() - entries, err := testutil.ListTar(f) + entries, err := listTar(f) for _, e := range entries { if !strings.Contains(e, "dev/") { entriesSansDev = append(entriesSansDev, e) @@ -308,6 +309,23 @@ func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) { } +func listTar(f io.Reader) ([]string, error) { + tr := tar.NewReader(f) + var entries []string + + for { + th, err := tr.Next() + if err == io.EOF { + // end of tar archive + return entries, nil + } + if err != nil { + return entries, err + } + entries = append(entries, th.Name) + } +} + // Test loading a weird image where one of the layers is of zero size. // The layer.tar file is actually zero bytes, no padding or anything else. // See issue: 18170 @@ -365,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)) @@ -376,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 3e39f47bf2..e5f3a794ae 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 8311401d0e..54cfdd179c 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/docker_deprecated_api_v124_test.go b/integration-cli/docker_deprecated_api_v124_test.go index db2ce10e48..482425bf12 100644 --- a/integration-cli/docker_deprecated_api_v124_test.go +++ b/integration-cli/docker_deprecated_api_v124_test.go @@ -9,7 +9,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/testutil" "github.com/go-check/check" ) @@ -45,7 +44,7 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumeBinds(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(status, checker.Equals, http.StatusCreated) - bindPath := testutil.RandomTmpDirPath("test", testEnv.DaemonPlatform()) + bindPath := RandomTmpDirPath("test", testEnv.DaemonPlatform()) config = map[string]interface{}{ "Binds": []string{bindPath + ":" + path}, } @@ -72,8 +71,8 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartDupVolumeBinds(c *check.C) c.Assert(err, checker.IsNil) c.Assert(status, checker.Equals, http.StatusCreated) - bindPath1 := testutil.RandomTmpDirPath("test1", testEnv.DaemonPlatform()) - bindPath2 := testutil.RandomTmpDirPath("test2", testEnv.DaemonPlatform()) + bindPath1 := RandomTmpDirPath("test1", testEnv.DaemonPlatform()) + bindPath2 := RandomTmpDirPath("test2", testEnv.DaemonPlatform()) config = map[string]interface{}{ "Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"}, @@ -151,7 +150,7 @@ func (s *DockerSuite) TestDeprecatedStartWithTooLowMemoryLimit(c *check.C) { res, body, err := request.Post(formatV123StartAPIURL("/containers/"+containerID+"/start"), request.RawString(config), request.JSON) c.Assert(err, checker.IsNil) - b, err2 := testutil.ReadBody(body) + b, err2 := request.ReadBody(body) c.Assert(err2, checker.IsNil) c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) c.Assert(string(b), checker.Contains, "Minimum memory limit allowed is 4MB") diff --git a/integration-cli/request/request.go b/integration-cli/request/request.go index 6f2bf650d4..72632f3f76 100644 --- a/integration-cli/request/request.go +++ b/integration-cli/request/request.go @@ -21,7 +21,6 @@ import ( dclient "github.com/docker/docker/client" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/pkg/testutil" "github.com/docker/go-connections/sockets" "github.com/docker/go-connections/tlsconfig" "github.com/pkg/errors" @@ -166,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 @@ -214,10 +217,16 @@ func SockRequest(method, endpoint string, data interface{}, daemon string, modif if err != nil { return -1, nil, err } - b, err := testutil.ReadBody(body) + b, err := ReadBody(body) return res.StatusCode, b, err } +// ReadBody read the specified ReadCloser content and returns it +func ReadBody(b io.ReadCloser) ([]byte, error) { + defer b.Close() + return ioutil.ReadAll(b) +} + // SockRequestRaw create a request against the specified host (with method, endpoint and other request modifier) and // returns the http response, the output as a io.ReadCloser // Deprecated: use request.Do (or Get, Delete, Post) instead diff --git a/integration-cli/utils_test.go b/integration-cli/utils_test.go index 2725ddf4f7..9d9f83abdd 100644 --- a/integration-cli/utils_test.go +++ b/integration-cli/utils_test.go @@ -1,9 +1,15 @@ package main import ( + "fmt" + "os" "os/exec" + "path/filepath" + "strings" + "github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/testutil/cmd" + "github.com/pkg/errors" ) func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) { @@ -30,3 +36,79 @@ func transformCmd(execCmd *exec.Cmd) cmd.Cmd { Stdout: execCmd.Stdout, } } + +// ParseCgroupPaths parses 'procCgroupData', which is output of '/proc//cgroup', and returns +// a map which cgroup name as key and path as value. +func ParseCgroupPaths(procCgroupData string) map[string]string { + cgroupPaths := map[string]string{} + for _, line := range strings.Split(procCgroupData, "\n") { + parts := strings.Split(line, ":") + if len(parts) != 3 { + continue + } + cgroupPaths[parts[1]] = parts[2] + } + return cgroupPaths +} + +// RandomTmpDirPath provides a temporary path with rand string appended. +// does not create or checks if it exists. +func RandomTmpDirPath(s string, platform string) string { + // TODO: why doesn't this use os.TempDir() ? + tmp := "/tmp" + if platform == "windows" { + tmp = os.Getenv("TEMP") + } + path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, stringutils.GenerateRandomAlphaOnlyString(10))) + if platform == "windows" { + return filepath.FromSlash(path) // Using \ + } + 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/helpers.go b/pkg/testutil/helpers.go index c291148712..adc76418e8 100644 --- a/pkg/testutil/helpers.go +++ b/pkg/testutil/helpers.go @@ -1,9 +1,6 @@ package testutil import ( - "strings" - "unicode" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -14,20 +11,3 @@ func ErrorContains(t require.TestingT, err error, expectedError string) { require.Error(t, err) assert.Contains(t, err.Error(), expectedError) } - -// EqualNormalizedString compare the actual value to the expected value after applying the specified -// transform function. It fails the test if these two transformed string are not equal. -// For example `EqualNormalizedString(t, RemoveSpace, "foo\n", "foo")` wouldn't fail the test as -// spaces (and thus '\n') are removed before comparing the string. -func EqualNormalizedString(t require.TestingT, transformFun func(rune) rune, actual, expected string) { - require.Equal(t, strings.Map(transformFun, expected), strings.Map(transformFun, actual)) -} - -// RemoveSpace returns -1 if the specified runes is considered as a space (unicode) -// and the rune itself otherwise. -func RemoveSpace(r rune) rune { - if unicode.IsSpace(r) { - return -1 - } - return r -} diff --git a/pkg/testutil/utils.go b/pkg/testutil/utils.go deleted file mode 100644 index 0522dde2b1..0000000000 --- a/pkg/testutil/utils.go +++ /dev/null @@ -1,218 +0,0 @@ -package testutil - -import ( - "archive/tar" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "reflect" - "strings" - "syscall" - "time" - - "github.com/docker/docker/pkg/stringutils" - "github.com/docker/docker/pkg/system" -) - -// 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 { - status, ok := exitErr.Sys().(syscall.WaitStatus) - if !ok { - return false - } - // status.ExitStatus() is required on Windows because it does not - // implement Signal() nor Signaled(). Just check it had a bad exit - // status could mean it was killed (and in tests we do kill) - return (status.Signaled() && status.Signal() == os.Kill) || status.ExitStatus() != 0 - } - return false -} - -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]) -} - -// ConvertSliceOfStringsToMap converts a slices of string in a map -// with the strings as key and an empty string as values. -func ConvertSliceOfStringsToMap(input []string) map[string]struct{} { - output := make(map[string]struct{}) - for _, v := range input { - output[v] = struct{}{} - } - return output -} - -// CompareDirectoryEntries compares two sets of FileInfo (usually taken from a directory) -// and returns an error if different. -func CompareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error { - var ( - e1Entries = make(map[string]struct{}) - e2Entries = make(map[string]struct{}) - ) - for _, e := range e1 { - e1Entries[e.Name()] = struct{}{} - } - for _, e := range e2 { - e2Entries[e.Name()] = struct{}{} - } - if !reflect.DeepEqual(e1Entries, e2Entries) { - return fmt.Errorf("entries differ") - } - return nil -} - -// ListTar lists the entries of a tar. -func ListTar(f io.Reader) ([]string, error) { - tr := tar.NewReader(f) - var entries []string - - for { - th, err := tr.Next() - if err == io.EOF { - // end of tar archive - return entries, nil - } - if err != nil { - return entries, err - } - entries = append(entries, th.Name) - } -} - -// RandomTmpDirPath provides a temporary path with rand string appended. -// does not create or checks if it exists. -func RandomTmpDirPath(s string, platform string) string { - tmp := "/tmp" - if platform == "windows" { - tmp = os.Getenv("TEMP") - } - path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, stringutils.GenerateRandomAlphaOnlyString(10))) - if platform == "windows" { - return filepath.FromSlash(path) // Using \ - } - return filepath.ToSlash(path) // Using / -} - -// ConsumeWithSpeed reads chunkSize bytes from reader before sleeping -// for interval duration. Returns total read bytes. Send true to the -// stop channel to return before reading to EOF on the reader. -func ConsumeWithSpeed(reader io.Reader, chunkSize int, interval time.Duration, stop chan bool) (n int, err error) { - buffer := make([]byte, chunkSize) - for { - var readBytes int - readBytes, err = reader.Read(buffer) - n += readBytes - if err != nil { - if err == io.EOF { - err = nil - } - return - } - select { - case <-stop: - return - case <-time.After(interval): - } - } -} - -// ParseCgroupPaths parses 'procCgroupData', which is output of '/proc//cgroup', and returns -// a map which cgroup name as key and path as value. -func ParseCgroupPaths(procCgroupData string) map[string]string { - cgroupPaths := map[string]string{} - for _, line := range strings.Split(procCgroupData, "\n") { - parts := strings.Split(line, ":") - if len(parts) != 3 { - continue - } - cgroupPaths[parts[1]] = parts[2] - } - return cgroupPaths -} - -// ChannelBuffer holds a chan of byte array that can be populate in a goroutine. -type ChannelBuffer struct { - C chan []byte -} - -// Write implements Writer. -func (c *ChannelBuffer) Write(b []byte) (int, error) { - c.C <- b - return len(b), nil -} - -// Close closes the go channel. -func (c *ChannelBuffer) Close() error { - close(c.C) - return nil -} - -// ReadTimeout reads the content of the channel in the specified byte array with -// the specified duration as timeout. -func (c *ChannelBuffer) ReadTimeout(p []byte, n time.Duration) (int, error) { - select { - case b := <-c.C: - return copy(p[0:], b), nil - case <-time.After(n): - return -1, fmt.Errorf("timeout reading from channel") - } -} - -// ReadBody read the specified ReadCloser content and returns it -func ReadBody(b io.ReadCloser) ([]byte, error) { - defer b.Close() - return ioutil.ReadAll(b) -} diff --git a/pkg/testutil/utils_test.go b/pkg/testutil/utils_test.go deleted file mode 100644 index d37f3f4f83..0000000000 --- a/pkg/testutil/utils_test.go +++ /dev/null @@ -1,341 +0,0 @@ -package testutil - -import ( - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - "testing" - "time" -) - -func TestIsKilledFalseWithNonKilledProcess(t *testing.T) { - var lsCmd *exec.Cmd - if runtime.GOOS != "windows" { - lsCmd = exec.Command("ls") - } else { - lsCmd = exec.Command("cmd", "/c", "dir") - } - - err := lsCmd.Run() - if IsKilled(err) { - t.Fatalf("Expected the ls command to not be killed, was.") - } -} - -func TestIsKilledTrueWithKilledProcess(t *testing.T) { - var longCmd *exec.Cmd - if runtime.GOOS != "windows" { - longCmd = exec.Command("top") - } else { - longCmd = exec.Command("powershell", "while ($true) { sleep 1 }") - } - - // Start a command - err := longCmd.Start() - if err != nil { - t.Fatal(err) - } - // Capture the error when *dying* - done := make(chan error, 1) - go func() { - done <- longCmd.Wait() - }() - // Then kill it - longCmd.Process.Kill() - // Get the error - err = <-done - if !IsKilled(err) { - t.Fatalf("Expected the command to be killed, was not.") - } -} - -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) - } -} - -func TestConvertSliceOfStringsToMap(t *testing.T) { - input := []string{"a", "b"} - actual := ConvertSliceOfStringsToMap(input) - for _, key := range input { - if _, ok := actual[key]; !ok { - t.Fatalf("Expected output to contains key %s, did not: %v", key, actual) - } - } -} - -func TestCompareDirectoryEntries(t *testing.T) { - tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-compare-directories") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpFolder) - - file1 := filepath.Join(tmpFolder, "file1") - file2 := filepath.Join(tmpFolder, "file2") - os.Create(file1) - os.Create(file2) - - fi1, err := os.Stat(file1) - if err != nil { - t.Fatal(err) - } - fi1bis, err := os.Stat(file1) - if err != nil { - t.Fatal(err) - } - fi2, err := os.Stat(file2) - if err != nil { - t.Fatal(err) - } - - cases := []struct { - e1 []os.FileInfo - e2 []os.FileInfo - shouldError bool - }{ - // Empty directories - { - []os.FileInfo{}, - []os.FileInfo{}, - false, - }, - // Same FileInfos - { - []os.FileInfo{fi1}, - []os.FileInfo{fi1}, - false, - }, - // Different FileInfos but same names - { - []os.FileInfo{fi1}, - []os.FileInfo{fi1bis}, - false, - }, - // Different FileInfos, different names - { - []os.FileInfo{fi1}, - []os.FileInfo{fi2}, - true, - }, - } - for _, elt := range cases { - err := CompareDirectoryEntries(elt.e1, elt.e2) - if elt.shouldError && err == nil { - t.Fatalf("Should have return an error, did not with %v and %v", elt.e1, elt.e2) - } - if !elt.shouldError && err != nil { - t.Fatalf("Should have not returned an error, but did : %v with %v and %v", err, elt.e1, elt.e2) - } - } -} - -// FIXME make an "unhappy path" test for ListTar without "panicking" :-) -func TestListTar(t *testing.T) { - // TODO Windows: Figure out why this fails. Should be portable. - if runtime.GOOS == "windows" { - t.Skip("Failing on Windows - needs further investigation") - } - tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-list-tar") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpFolder) - - // Let's create a Tar file - srcFile := filepath.Join(tmpFolder, "src") - tarFile := filepath.Join(tmpFolder, "src.tar") - os.Create(srcFile) - cmd := exec.Command("sh", "-c", "tar cf "+tarFile+" "+srcFile) - _, err = cmd.CombinedOutput() - if err != nil { - t.Fatal(err) - } - - reader, err := os.Open(tarFile) - if err != nil { - t.Fatal(err) - } - defer reader.Close() - - entries, err := ListTar(reader) - if err != nil { - t.Fatal(err) - } - if len(entries) != 1 && entries[0] != "src" { - t.Fatalf("Expected a tar file with 1 entry (%s), got %v", srcFile, entries) - } -} - -func TestRandomTmpDirPath(t *testing.T) { - path := RandomTmpDirPath("something", runtime.GOOS) - - prefix := "/tmp/something" - if runtime.GOOS == "windows" { - prefix = os.Getenv("TEMP") + `\something` - } - expectedSize := len(prefix) + 11 - - if !strings.HasPrefix(path, prefix) { - t.Fatalf("Expected generated path to have '%s' as prefix, got %s'", prefix, path) - } - if len(path) != expectedSize { - t.Fatalf("Expected generated path to be %d, got %d", expectedSize, len(path)) - } -} - -func TestConsumeWithSpeed(t *testing.T) { - reader := strings.NewReader("1234567890") - chunksize := 2 - - bytes1, err := ConsumeWithSpeed(reader, chunksize, 10*time.Millisecond, nil) - if err != nil { - t.Fatal(err) - } - - if bytes1 != 10 { - t.Fatalf("Expected to have read 10 bytes, got %d", bytes1) - } - -} - -func TestConsumeWithSpeedWithStop(t *testing.T) { - reader := strings.NewReader("1234567890") - chunksize := 2 - - stopIt := make(chan bool) - - go func() { - time.Sleep(1 * time.Millisecond) - stopIt <- true - }() - - bytes1, err := ConsumeWithSpeed(reader, chunksize, 20*time.Millisecond, stopIt) - if err != nil { - t.Fatal(err) - } - - if bytes1 != 2 { - t.Fatalf("Expected to have read 2 bytes, got %d", bytes1) - } - -} - -func TestParseCgroupPathsEmpty(t *testing.T) { - cgroupMap := ParseCgroupPaths("") - if len(cgroupMap) != 0 { - t.Fatalf("Expected an empty map, got %v", cgroupMap) - } - cgroupMap = ParseCgroupPaths("\n") - if len(cgroupMap) != 0 { - t.Fatalf("Expected an empty map, got %v", cgroupMap) - } - cgroupMap = ParseCgroupPaths("something:else\nagain:here") - if len(cgroupMap) != 0 { - t.Fatalf("Expected an empty map, got %v", cgroupMap) - } -} - -func TestParseCgroupPaths(t *testing.T) { - cgroupMap := ParseCgroupPaths("2:memory:/a\n1:cpuset:/b") - if len(cgroupMap) != 2 { - t.Fatalf("Expected a map with 2 entries, got %v", cgroupMap) - } - if value, ok := cgroupMap["memory"]; !ok || value != "/a" { - t.Fatalf("Expected cgroupMap to contains an entry for 'memory' with value '/a', got %v", cgroupMap) - } - if value, ok := cgroupMap["cpuset"]; !ok || value != "/b" { - t.Fatalf("Expected cgroupMap to contains an entry for 'cpuset' with value '/b', got %v", cgroupMap) - } -} - -func TestChannelBufferTimeout(t *testing.T) { - expected := "11" - - buf := &ChannelBuffer{make(chan []byte, 1)} - defer buf.Close() - - done := make(chan struct{}, 1) - go func() { - time.Sleep(100 * time.Millisecond) - io.Copy(buf, strings.NewReader(expected)) - done <- struct{}{} - }() - - // Wait long enough - b := make([]byte, 2) - _, err := buf.ReadTimeout(b, 50*time.Millisecond) - if err == nil && err.Error() != "timeout reading from channel" { - t.Fatalf("Expected an error, got %s", err) - } - <-done -} - -func TestChannelBuffer(t *testing.T) { - expected := "11" - - buf := &ChannelBuffer{make(chan []byte, 1)} - defer buf.Close() - - go func() { - time.Sleep(100 * time.Millisecond) - io.Copy(buf, strings.NewReader(expected)) - }() - - // Wait long enough - b := make([]byte, 2) - _, err := buf.ReadTimeout(b, 200*time.Millisecond) - if err != nil { - t.Fatal(err) - } - - if string(b) != expected { - t.Fatalf("Expected '%s', got '%s'", expected, string(b)) - } -}