From 8ea0c8eb22501028d684779e3360fd0db2aa4205 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 8 Feb 2018 12:45:18 +0100 Subject: [PATCH 01/14] Fix string type for buildargs API definition Signed-off-by: Jon Surrell Upstream-commit: f281358ba2de6204a61cdb062fa67a8b7134739c Component: engine --- components/engine/api/swagger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index cc3ee80cb2..a70906a140 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -6174,7 +6174,7 @@ paths: - name: "buildargs" in: "query" description: "JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)" - type: "integer" + type: "string" - name: "shmsize" in: "query" description: "Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB." From 0a75e5196f84c103b85d2fd4a50cd655651ce665 Mon Sep 17 00:00:00 2001 From: John Howard Date: Fri, 9 Feb 2018 11:39:57 -0800 Subject: [PATCH 02/14] Windows: Bump to final RS3 build number Signed-off-by: John Howard Upstream-commit: c04504383a913c1af9868b23880c6401651c71b1 Component: engine --- .../integration-cli/docker_api_containers_windows_test.go | 2 +- components/engine/integration-cli/docker_cli_run_test.go | 2 +- components/engine/libcontainerd/client_local_windows.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/engine/integration-cli/docker_api_containers_windows_test.go b/components/engine/integration-cli/docker_api_containers_windows_test.go index ae60cfec00..25bc767e55 100644 --- a/components/engine/integration-cli/docker_api_containers_windows_test.go +++ b/components/engine/integration-cli/docker_api_containers_windows_test.go @@ -16,7 +16,7 @@ import ( ) func (s *DockerSuite) TestContainersAPICreateMountsBindNamedPipe(c *check.C) { - testRequires(c, SameHostDaemon, DaemonIsWindowsAtLeastBuild(16210)) // Named pipe support was added in RS3 + testRequires(c, SameHostDaemon, DaemonIsWindowsAtLeastBuild(16299)) // Named pipe support was added in RS3 // Create a host pipe to map into the container hostPipeName := fmt.Sprintf(`\\.\pipe\docker-cli-test-pipe-%x`, rand.Uint64()) diff --git a/components/engine/integration-cli/docker_cli_run_test.go b/components/engine/integration-cli/docker_cli_run_test.go index bf0cb0ddf8..2a652e35e4 100644 --- a/components/engine/integration-cli/docker_cli_run_test.go +++ b/components/engine/integration-cli/docker_cli_run_test.go @@ -4002,7 +4002,7 @@ func (s *DockerSuite) TestRunAttachFailedNoLeak(c *check.C) { v, err := kernel.GetKernelVersion() c.Assert(err, checker.IsNil) build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0]) - if build >= 16292 { // @jhowardmsft TODO - replace with final RS3 build and == + if build == 16299 { c.Skip("Temporarily disabled on RS3 builds") } } diff --git a/components/engine/libcontainerd/client_local_windows.go b/components/engine/libcontainerd/client_local_windows.go index 51475b42d0..34ad0d771e 100644 --- a/components/engine/libcontainerd/client_local_windows.go +++ b/components/engine/libcontainerd/client_local_windows.go @@ -223,7 +223,7 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter if configuration.HvPartition { // We don't currently support setting the utility VM image explicitly. - // TODO @swernli/jhowardmsft circa RS3/4, this may be re-locatable. + // TODO @swernli/jhowardmsft circa RS5, this may be re-locatable. if spec.Windows.HyperV.UtilityVMPath != "" { return errors.New("runtime does not support an explicit utility VM path for Hyper-V containers") } @@ -303,7 +303,7 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter } } configuration.MappedDirectories = mds - if len(mps) > 0 && system.GetOSVersion().Build < 16210 { // replace with Win10 RS3 build number at RTM + if len(mps) > 0 && system.GetOSVersion().Build < 16299 { // RS3 return errors.New("named pipe mounts are not supported on this version of Windows") } configuration.MappedPipes = mps From d92fe4f6a1b63e9766d1649d5a16d72fbe22cbd2 Mon Sep 17 00:00:00 2001 From: Drew Erny Date: Fri, 9 Feb 2018 15:10:58 -0800 Subject: [PATCH 03/14] Fix TLS from environment variables in client A recent change accidently caused any TLS configuration in FromEnv to be ignored. This change alters WithHost to create a new http client only if one doesn't already exist, and otherwise applies the logic to the transport on the existing client. This preserves the TLS configuration that might already be on the client. Signed-off-by: Drew Erny Upstream-commit: 80904e9571e7724328160c97ede6a71864f3c06a Component: engine --- components/engine/client/client.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/components/engine/client/client.go b/components/engine/client/client.go index 240e32ae05..6ce0cdba1f 100644 --- a/components/engine/client/client.go +++ b/components/engine/client/client.go @@ -133,23 +133,15 @@ func FromEnv(c *Client) error { }, CheckRedirect: CheckRedirect, } + WithHTTPClient(httpClient)(c) } host := os.Getenv("DOCKER_HOST") if host != "" { - var err error + // WithHost will create an API client if it doesn't exist if err := WithHost(host)(c); err != nil { return err } - httpClient, err = defaultHTTPClient(host) - if err != nil { - return err - } - } - if httpClient != nil { - if err := WithHTTPClient(httpClient)(c); err != nil { - return err - } } version := os.Getenv("DOCKER_API_VERSION") if version != "" { @@ -167,7 +159,8 @@ func WithVersion(version string) func(*Client) error { } } -// WithHost overrides the client host with the specified one +// WithHost overrides the client host with the specified one, creating a new +// http client if one doesn't exist func WithHost(host string) func(*Client) error { return func(c *Client) error { hostURL, err := ParseHostURL(host) @@ -178,11 +171,17 @@ func WithHost(host string) func(*Client) error { c.proto = hostURL.Scheme c.addr = hostURL.Host c.basePath = hostURL.Path - client, err := defaultHTTPClient(host) - if err != nil { - return err + if c.client == nil { + client, err := defaultHTTPClient(host) + if err != nil { + return err + } + return WithHTTPClient(client)(c) } - return WithHTTPClient(client)(c) + if transport, ok := c.client.Transport.(*http.Transport); ok { + return sockets.ConfigureTransport(transport, c.proto, c.addr) + } + return fmt.Errorf("cannot apply host to http transport") } } From 6a659ff498a005217075fdce652b0bba1b337c11 Mon Sep 17 00:00:00 2001 From: bin liu Date: Sat, 10 Feb 2018 19:28:12 +0800 Subject: [PATCH 04/14] Fix typos in pkg Signed-off-by: bin liu Upstream-commit: 7a7a8a33a4a79e7ea1e67f8a77b4060f95e936ea Component: engine --- components/engine/pkg/system/path.go | 2 +- components/engine/pkg/tailfile/tailfile.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/engine/pkg/system/path.go b/components/engine/pkg/system/path.go index 3d209b1bdf..a3d957afab 100644 --- a/components/engine/pkg/system/path.go +++ b/components/engine/pkg/system/path.go @@ -35,7 +35,7 @@ func DefaultPathEnv(os string) string { // This is used, for example, when validating a user provided path in docker cp. // If a drive letter is supplied, it must be the system drive. The drive letter // is always removed. Also, it translates it to OS semantics (IOW / to \). We -// need the path in this syntax so that it can ultimately be contatenated with +// need the path in this syntax so that it can ultimately be concatenated with // a Windows long-path which doesn't support drive-letters. Examples: // C: --> Fail // C:\ --> \ diff --git a/components/engine/pkg/tailfile/tailfile.go b/components/engine/pkg/tailfile/tailfile.go index a223f66b75..e835893746 100644 --- a/components/engine/pkg/tailfile/tailfile.go +++ b/components/engine/pkg/tailfile/tailfile.go @@ -16,7 +16,7 @@ var eol = []byte("\n") // ErrNonPositiveLinesNumber is an error returned if the lines number was negative. var ErrNonPositiveLinesNumber = errors.New("The number of lines to extract from the file must be positive") -//TailFile returns last n lines of reader f (could be a fil). +//TailFile returns last n lines of reader f (could be a nil). func TailFile(f io.ReadSeeker, n int) ([][]byte, error) { if n <= 0 { return nil, ErrNonPositiveLinesNumber From dd36e404932d96193bfc3f111133174610505b77 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 9 Feb 2018 21:44:11 +0000 Subject: [PATCH 05/14] Remove integration-cli/docker_cli_config_ls_test.go Signed-off-by: Yong Tang Upstream-commit: 955a2b81940181ef51b31feacbf234dab98e56d1 Component: engine --- .../docker_cli_config_ls_test.go | 126 ------------------ 1 file changed, 126 deletions(-) delete mode 100644 components/engine/integration-cli/docker_cli_config_ls_test.go diff --git a/components/engine/integration-cli/docker_cli_config_ls_test.go b/components/engine/integration-cli/docker_cli_config_ls_test.go deleted file mode 100644 index 5f002bcab6..0000000000 --- a/components/engine/integration-cli/docker_cli_config_ls_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// +build !windows - -package main - -import ( - "strings" - - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/integration-cli/checker" - "github.com/go-check/check" -) - -func (s *DockerSwarmSuite) TestConfigList(c *check.C) { - testRequires(c, SameHostDaemon) - d := s.AddDaemon(c, true, true) - - testName0 := "test0" - testName1 := "test1" - - // create config test0 - id0 := d.CreateConfig(c, swarm.ConfigSpec{ - Annotations: swarm.Annotations{ - Name: testName0, - Labels: map[string]string{"type": "test"}, - }, - Data: []byte("TESTINGDATA0"), - }) - c.Assert(id0, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id0)) - - config := d.GetConfig(c, id0) - c.Assert(config.Spec.Name, checker.Equals, testName0) - - // create config test1 - id1 := d.CreateConfig(c, swarm.ConfigSpec{ - Annotations: swarm.Annotations{ - Name: testName1, - Labels: map[string]string{"type": "production"}, - }, - Data: []byte("TESTINGDATA1"), - }) - c.Assert(id1, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id1)) - - config = d.GetConfig(c, id1) - c.Assert(config.Spec.Name, checker.Equals, testName1) - - // test by command `docker config ls` - out, err := d.Cmd("config", "ls") - c.Assert(err, checker.IsNil, check.Commentf(out)) - c.Assert(strings.TrimSpace(out), checker.Contains, testName0) - c.Assert(strings.TrimSpace(out), checker.Contains, testName1) - - // test filter by name `docker config ls --filter name=xxx` - args := []string{ - "config", - "ls", - "--filter", - "name=test0", - } - out, err = d.Cmd(args...) - c.Assert(err, checker.IsNil, check.Commentf(out)) - - c.Assert(strings.TrimSpace(out), checker.Contains, testName0) - c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName1) - - // test filter by id `docker config ls --filter id=xxx` - args = []string{ - "config", - "ls", - "--filter", - "id=" + id1, - } - out, err = d.Cmd(args...) - c.Assert(err, checker.IsNil, check.Commentf(out)) - - c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName0) - c.Assert(strings.TrimSpace(out), checker.Contains, testName1) - - // test filter by label `docker config ls --filter label=xxx` - args = []string{ - "config", - "ls", - "--filter", - "label=type", - } - out, err = d.Cmd(args...) - c.Assert(err, checker.IsNil, check.Commentf(out)) - - c.Assert(strings.TrimSpace(out), checker.Contains, testName0) - c.Assert(strings.TrimSpace(out), checker.Contains, testName1) - - args = []string{ - "config", - "ls", - "--filter", - "label=type=test", - } - out, err = d.Cmd(args...) - c.Assert(err, checker.IsNil, check.Commentf(out)) - - c.Assert(strings.TrimSpace(out), checker.Contains, testName0) - c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName1) - - args = []string{ - "config", - "ls", - "--filter", - "label=type=production", - } - out, err = d.Cmd(args...) - c.Assert(err, checker.IsNil, check.Commentf(out)) - - c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName0) - c.Assert(strings.TrimSpace(out), checker.Contains, testName1) - - // test invalid filter `docker config ls --filter noexisttype=xxx` - args = []string{ - "config", - "ls", - "--filter", - "noexisttype=test0", - } - out, err = d.Cmd(args...) - c.Assert(err, checker.NotNil, check.Commentf(out)) - - c.Assert(strings.TrimSpace(out), checker.Contains, "Error response from daemon: Invalid filter 'noexisttype'") -} From bf8ec4c4d266fb481c2ea85b8e1d0e04cea94c84 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 9 Feb 2018 21:44:28 +0000 Subject: [PATCH 06/14] Migrate config list tests from integration-cli to api tests This fix migrates config list tests from integration-cli to api tests Signed-off-by: Yong Tang Upstream-commit: 246f450ac4fcaff15f36874475f15f435ab03a15 Component: engine --- .../engine/integration/config/config_test.go | 102 ++++++++++++++++++ .../engine/integration/config/main_test.go | 33 ++++++ 2 files changed, 135 insertions(+) create mode 100644 components/engine/integration/config/config_test.go create mode 100644 components/engine/integration/config/main_test.go diff --git a/components/engine/integration/config/config_test.go b/components/engine/integration/config/config_test.go new file mode 100644 index 0000000000..0d7c557fad --- /dev/null +++ b/components/engine/integration/config/config_test.go @@ -0,0 +1,102 @@ +package config + +import ( + "sort" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + swarmtypes "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/client" + "github.com/docker/docker/integration/internal/swarm" + "github.com/gotestyourself/gotestyourself/skip" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" +) + +func TestConfigList(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + d := swarm.NewSwarm(t, testEnv) + defer d.Stop(t) + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + ctx := context.Background() + + testName0 := "test0" + testName1 := "test1" + testNames := []string{testName0, testName1} + sort.Strings(testNames) + + // create config test0 + createConfig(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"}) + + config1ID := createConfig(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"}) + + names := func(entries []swarmtypes.Config) []string { + values := []string{} + for _, entry := range entries { + values = append(values, entry.Spec.Name) + } + sort.Strings(values) + return values + } + + // test by `config ls` + entries, err := client.ConfigList(ctx, types.ConfigListOptions{}) + require.NoError(t, err) + assert.Equal(t, names(entries), testNames) + + testCases := []struct { + filters filters.Args + expected []string + }{ + // test filter by name `config ls --filter name=xxx` + { + filters: filters.NewArgs(filters.Arg("name", testName0)), + expected: []string{testName0}, + }, + // test filter by id `config ls --filter id=xxx` + { + filters: filters.NewArgs(filters.Arg("id", config1ID)), + expected: []string{testName1}, + }, + // test filter by label `config ls --filter label=xxx` + { + filters: filters.NewArgs(filters.Arg("label", "type")), + expected: testNames, + }, + { + filters: filters.NewArgs(filters.Arg("label", "type=test")), + expected: []string{testName0}, + }, + { + filters: filters.NewArgs(filters.Arg("label", "type=production")), + expected: []string{testName1}, + }, + } + for _, tc := range testCases { + entries, err = client.ConfigList(ctx, types.ConfigListOptions{ + Filters: tc.filters, + }) + require.NoError(t, err) + assert.Equal(t, names(entries), tc.expected) + + } +} + +func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string { + config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{ + Annotations: swarmtypes.Annotations{ + Name: name, + Labels: labels, + }, + Data: data, + }) + require.NoError(t, err) + assert.NotEqual(t, config.ID, "") + return config.ID +} diff --git a/components/engine/integration/config/main_test.go b/components/engine/integration/config/main_test.go new file mode 100644 index 0000000000..32df97d2c6 --- /dev/null +++ b/components/engine/integration/config/main_test.go @@ -0,0 +1,33 @@ +package config + +import ( + "fmt" + "os" + "testing" + + "github.com/docker/docker/internal/test/environment" +) + +var testEnv *environment.Execution + +func TestMain(m *testing.M) { + var err error + testEnv, err = environment.New() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = environment.EnsureFrozenImagesLinux(testEnv) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + testEnv.Print() + os.Exit(m.Run()) +} + +func setupTest(t *testing.T) func() { + environment.ProtectAll(t, testEnv) + return func() { testEnv.Clean(t) } +} From e2c834a1a9a604ed267817854e4956a34d47a78d Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 9 Feb 2018 13:02:36 +0000 Subject: [PATCH 07/14] Migrate docker_cli_oom_killed_test.go to api tests This fix migrates tests in integration-cli/docker_cli_oom_killed_test.go to api tests. Signed-off-by: Yong Tang Upstream-commit: 3c21274b76323883e8ffb146fb989850c4de221a Component: engine --- .../docker_cli_oom_killed_test.go | 30 --------------- .../engine/integration/container/kill_test.go | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+), 30 deletions(-) delete mode 100644 components/engine/integration-cli/docker_cli_oom_killed_test.go diff --git a/components/engine/integration-cli/docker_cli_oom_killed_test.go b/components/engine/integration-cli/docker_cli_oom_killed_test.go deleted file mode 100644 index 54c34d206a..0000000000 --- a/components/engine/integration-cli/docker_cli_oom_killed_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build !windows - -package main - -import ( - "github.com/docker/docker/integration-cli/checker" - "github.com/go-check/check" -) - -func (s *DockerSuite) TestInspectOomKilledTrue(c *check.C) { - testRequires(c, DaemonIsLinux, memoryLimitSupport, swapMemorySupport) - - name := "testoomkilled" - _, exitCode, _ := dockerCmdWithError("run", "--name", name, "--memory", "32MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done") - - c.Assert(exitCode, checker.Equals, 137, check.Commentf("OOM exit should be 137")) - - oomKilled := inspectField(c, name, "State.OOMKilled") - c.Assert(oomKilled, checker.Equals, "true") -} - -func (s *DockerSuite) TestInspectOomKilledFalse(c *check.C) { - testRequires(c, DaemonIsLinux, memoryLimitSupport, swapMemorySupport) - - name := "testoomkilled" - dockerCmd(c, "run", "--name", name, "--memory", "32MB", "busybox", "sh", "-c", "echo hello world") - - oomKilled := inspectField(c, name, "State.OOMKilled") - c.Assert(oomKilled, checker.Equals, "false") -} diff --git a/components/engine/integration/container/kill_test.go b/components/engine/integration/container/kill_test.go index 6efc5fc61d..d399213ac6 100644 --- a/components/engine/integration/container/kill_test.go +++ b/components/engine/integration/container/kill_test.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/integration/internal/request" "github.com/gotestyourself/gotestyourself/poll" "github.com/gotestyourself/gotestyourself/skip" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -146,3 +147,39 @@ func TestKillDifferentUserContainer(t *testing.T) { require.NoError(t, err) poll.WaitOn(t, containerIsInState(ctx, client, id, "exited"), poll.WithDelay(100*time.Millisecond)) } + +func TestInspectOomKilledTrue(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.MemoryLimit || !testEnv.DaemonInfo.SwapLimit) + + defer setupTest(t)() + ctx := context.Background() + client := request.NewAPIClient(t) + + name := "testoomkilled" + cID := container.Run(t, ctx, client, container.WithName(name), container.WithCmd("sh", "-c", "x=a; while true; do x=$x$x$x$x; done"), func(c *container.TestContainerConfig) { + c.HostConfig.Resources.Memory = 32 * 1024 * 1024 + }) + + poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond)) + + inspect, err := client.ContainerInspect(ctx, cID) + require.NoError(t, err) + assert.Equal(t, inspect.State.OOMKilled, true) +} + +func TestInspectOomKilledFalse(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.MemoryLimit || !testEnv.DaemonInfo.SwapLimit) + + defer setupTest(t)() + ctx := context.Background() + client := request.NewAPIClient(t) + + name := "testoomkilled" + cID := container.Run(t, ctx, client, container.WithName(name), container.WithCmd("sh", "-c", "echo hello world")) + + poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond)) + + inspect, err := client.ContainerInspect(ctx, cID) + require.NoError(t, err) + assert.Equal(t, inspect.State.OOMKilled, false) +} From 4571efe6b5bf99f06b4dc52aba4da2b511e00c6e Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 11 Feb 2018 21:17:25 +0000 Subject: [PATCH 08/14] Remove docker_api_swarm_secret_test.go Signed-off-by: Yong Tang Upstream-commit: 3499557c9b3aa728cb52402c1bb4302f80ab4721 Component: engine --- .../docker_api_swarm_secret_test.go | 136 ------------------ 1 file changed, 136 deletions(-) delete mode 100644 components/engine/integration-cli/docker_api_swarm_secret_test.go diff --git a/components/engine/integration-cli/docker_api_swarm_secret_test.go b/components/engine/integration-cli/docker_api_swarm_secret_test.go deleted file mode 100644 index c30e2237d8..0000000000 --- a/components/engine/integration-cli/docker_api_swarm_secret_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// +build !windows - -package main - -import ( - "net/http" - - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/integration-cli/checker" - "github.com/go-check/check" - "golang.org/x/net/context" -) - -func (s *DockerSwarmSuite) TestAPISwarmSecretsEmptyList(c *check.C) { - d := s.AddDaemon(c, true, true) - - secrets := d.ListSecrets(c) - c.Assert(secrets, checker.NotNil) - c.Assert(len(secrets), checker.Equals, 0, check.Commentf("secrets: %#v", secrets)) -} - -func (s *DockerSwarmSuite) TestAPISwarmSecretsCreate(c *check.C) { - d := s.AddDaemon(c, true, true) - - testName := "test_secret" - secretSpec := swarm.SecretSpec{ - Annotations: swarm.Annotations{ - Name: testName, - }, - Data: []byte("TESTINGDATA"), - } - - id := d.CreateSecret(c, secretSpec) - c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id)) - - secrets := d.ListSecrets(c) - c.Assert(len(secrets), checker.Equals, 1, check.Commentf("secrets: %#v", secrets)) - name := secrets[0].Spec.Annotations.Name - c.Assert(name, checker.Equals, testName, check.Commentf("secret: %s", name)) - - // create an already existing secret, daemon should return a status code of 409 - status, out, err := d.SockRequest("POST", "/secrets/create", secretSpec) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusConflict, check.Commentf("secret create: %s", string(out))) -} - -func (s *DockerSwarmSuite) TestAPISwarmSecretsDelete(c *check.C) { - d := s.AddDaemon(c, true, true) - - testName := "test_secret" - id := d.CreateSecret(c, swarm.SecretSpec{Annotations: swarm.Annotations{ - Name: testName, - }, - Data: []byte("TESTINGDATA"), - }) - c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id)) - - secret := d.GetSecret(c, id) - c.Assert(secret.ID, checker.Equals, id, check.Commentf("secret: %v", secret)) - - d.DeleteSecret(c, secret.ID) - - cli, err := d.NewClient() - c.Assert(err, checker.IsNil) - defer cli.Close() - - _, _, err = cli.SecretInspectWithRaw(context.Background(), id) - c.Assert(err.Error(), checker.Contains, "No such secret") - - id = "non-existing" - err = cli.SecretRemove(context.Background(), id) - c.Assert(err.Error(), checker.Contains, "No such secret: non-existing") -} - -func (s *DockerSwarmSuite) TestAPISwarmSecretsUpdate(c *check.C) { - d := s.AddDaemon(c, true, true) - - testName := "test_secret" - id := d.CreateSecret(c, swarm.SecretSpec{ - Annotations: swarm.Annotations{ - Name: testName, - Labels: map[string]string{ - "test": "test1", - }, - }, - Data: []byte("TESTINGDATA"), - }) - c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id)) - - secret := d.GetSecret(c, id) - c.Assert(secret.ID, checker.Equals, id, check.Commentf("secret: %v", secret)) - - // test UpdateSecret with full ID - d.UpdateSecret(c, id, func(s *swarm.Secret) { - s.Spec.Labels = map[string]string{ - "test": "test1", - } - }) - - secret = d.GetSecret(c, id) - c.Assert(secret.Spec.Labels["test"], checker.Equals, "test1", check.Commentf("secret: %v", secret)) - - // test UpdateSecret with full name - d.UpdateSecret(c, secret.Spec.Name, func(s *swarm.Secret) { - s.Spec.Labels = map[string]string{ - "test": "test2", - } - }) - - secret = d.GetSecret(c, id) - c.Assert(secret.Spec.Labels["test"], checker.Equals, "test2", check.Commentf("secret: %v", secret)) - - // test UpdateSecret with prefix ID - d.UpdateSecret(c, id[:1], func(s *swarm.Secret) { - s.Spec.Labels = map[string]string{ - "test": "test3", - } - }) - - secret = d.GetSecret(c, id) - c.Assert(secret.Spec.Labels["test"], checker.Equals, "test3", check.Commentf("secret: %v", secret)) - - // test UpdateSecret in updating Data which is not supported in daemon - // this test will produce an error in func UpdateSecret - secret = d.GetSecret(c, id) - secret.Spec.Data = []byte("TESTINGDATA2") - - cli, err := d.NewClient() - c.Assert(err, checker.IsNil) - defer cli.Close() - - expected := "only updates to Labels are allowed" - - err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec) - c.Assert(err.Error(), checker.Contains, expected) -} From 46e07309bdc0983b45ccdf79f3baeec426ed20ef Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 11 Feb 2018 21:17:44 +0000 Subject: [PATCH 09/14] Migrates several swarm secrets from integration-cli to api tests This fix migrates several swarm secrets from integration-cli to api tests Signed-off-by: Yong Tang Upstream-commit: f955d2e2042cabaeac8a451b83a507b76e606d33 Component: engine --- .../engine/integration/secret/secret_test.go | 110 +++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/components/engine/integration/secret/secret_test.go b/components/engine/integration/secret/secret_test.go index 3915bf5e82..a6e9983e23 100644 --- a/components/engine/integration/secret/secret_test.go +++ b/components/engine/integration/secret/secret_test.go @@ -9,6 +9,7 @@ import ( swarmtypes "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" "github.com/docker/docker/integration/internal/swarm" + "github.com/docker/docker/internal/testutil" "github.com/gotestyourself/gotestyourself/skip" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -35,7 +36,7 @@ func TestSecretInspect(t *testing.T) { secret, _, err = client.SecretInspectWithRaw(context.Background(), testName) require.NoError(t, err) - assert.Equal(t, secret.ID, secretID) + assert.Equal(t, secretID, secretID) } func TestSecretList(t *testing.T) { @@ -124,3 +125,110 @@ func createSecret(ctx context.Context, t *testing.T, client client.APIClient, na assert.NotEqual(t, secret.ID, "") return secret.ID } + +func TestSecretsCreate(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + d := swarm.NewSwarm(t, testEnv) + defer d.Stop(t) + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + ctx := context.Background() + + testName := "test_secret" + createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) + require.NoError(t, err) + + // create an already existin secret, daemon should return a status code of 409 + _, err = client.SecretCreate(ctx, swarmtypes.SecretSpec{ + Annotations: swarmtypes.Annotations{ + Name: testName, + }, + Data: []byte("TESTINGDATA"), + }) + testutil.ErrorContains(t, err, "already exists") +} + +func TestSecretsDelete(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + d := swarm.NewSwarm(t, testEnv) + defer d.Stop(t) + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + ctx := context.Background() + + testName := "test_secret" + secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) + require.NoError(t, err) + + insp, _, err := client.SecretInspectWithRaw(ctx, secretID) + require.NoError(t, err) + assert.Equal(t, insp.ID, secretID) + + err = client.SecretRemove(ctx, secretID) + require.NoError(t, err) + + _, _, err = client.SecretInspectWithRaw(ctx, secretID) + testutil.ErrorContains(t, err, "No such secret") + + err = client.SecretRemove(ctx, "non-existin") + testutil.ErrorContains(t, err, "No such secret: non-existin") +} + +func TestSecretsUpdate(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + d := swarm.NewSwarm(t, testEnv) + defer d.Stop(t) + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + ctx := context.Background() + + testName := "test_secret" + secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) + require.NoError(t, err) + + insp, _, err := client.SecretInspectWithRaw(ctx, secretID) + require.NoError(t, err) + assert.Equal(t, insp.ID, secretID) + + // test UpdateSecret with full ID + insp.Spec.Labels = map[string]string{"test": "test1"} + err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) + require.NoError(t, err) + + insp, _, err = client.SecretInspectWithRaw(ctx, secretID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Labels["test"], "test1") + + // test UpdateSecret with full name + insp.Spec.Labels = map[string]string{"test": "test2"} + err = client.SecretUpdate(ctx, testName, insp.Version, insp.Spec) + require.NoError(t, err) + + insp, _, err = client.SecretInspectWithRaw(ctx, secretID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Labels["test"], "test2") + + // test UpdateSecret with prefix ID + insp.Spec.Labels = map[string]string{"test": "test3"} + err = client.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec) + require.NoError(t, err) + + insp, _, err = client.SecretInspectWithRaw(ctx, secretID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Labels["test"], "test3") + + // test UpdateSecret in updating Data which is not supported in daemon + // this test will produce an error in func UpdateSecret + insp.Spec.Data = []byte("TESTINGDATA2") + err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) + testutil.ErrorContains(t, err, "only updates to Labels are allowed") +} From 535cb21e7e64b767c8301ba84c5c03fa7dbc2647 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Mon, 12 Feb 2018 13:48:03 +0100 Subject: [PATCH 10/14] Reformat to multi-line Signed-off-by: Jon Surrell Upstream-commit: de2b2b5e4ba0cb297d47a7b05614190fa44f54a2 Component: engine --- components/engine/api/swagger.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index a70906a140..2262de6bfa 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -6173,7 +6173,12 @@ paths: type: "integer" - name: "buildargs" in: "query" - description: "JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)" + description: > + JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker + uses the buildargs as the environment context for commands run via the `Dockerfile` RUN + instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for + passing secret values. + [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) type: "string" - name: "shmsize" in: "query" From 4816de08ce0d2ef2069f3e16649fd91603c66c90 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Mon, 12 Feb 2018 14:02:54 +0100 Subject: [PATCH 11/14] Add example buildargs usage Signed-off-by: Jon Surrell Upstream-commit: 344c73ac672cd4d4f70a08b5a41b6835d9873926 Component: engine --- components/engine/api/swagger.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index 2262de6bfa..8174ce387c 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -6178,6 +6178,12 @@ paths: uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. + + + For example, the build arg `FOO=bar` would become `{"FOO":"bar"}` in JSON. This would result in the + the query parameter `buildargs={"FOO":"bar"}`. Note that `{"FOO":"bar"}` should be URI component encoded. + + [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) type: "string" - name: "shmsize" From 4d79f94efee3977b84fca9045e74adc0f951501f Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 11 Feb 2018 22:32:15 +0000 Subject: [PATCH 12/14] Migrate some update restart tests to api tests This fix migrates some update restart tests in integration-cli to api tests in integration. Signed-off-by: Yong Tang Upstream-commit: 5b65cee9150b343c97606adc525cf680fb330642 Component: engine --- .../integration-cli/docker_cli_update_test.go | 43 ------------ .../integration/container/update_test.go | 65 +++++++++++++++++++ 2 files changed, 65 insertions(+), 43 deletions(-) delete mode 100644 components/engine/integration-cli/docker_cli_update_test.go create mode 100644 components/engine/integration/container/update_test.go diff --git a/components/engine/integration-cli/docker_cli_update_test.go b/components/engine/integration-cli/docker_cli_update_test.go deleted file mode 100644 index dce137ebf8..0000000000 --- a/components/engine/integration-cli/docker_cli_update_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "strings" - "time" - - "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/cli" - "github.com/go-check/check" - "github.com/gotestyourself/gotestyourself/icmd" -) - -func (s *DockerSuite) TestUpdateRestartPolicy(c *check.C) { - out := cli.DockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "sh", "-c", "sleep 1 && false").Combined() - timeout := 60 * time.Second - if testEnv.OSType == "windows" { - timeout = 180 * time.Second - } - - id := strings.TrimSpace(string(out)) - - // update restart policy to on-failure:5 - cli.DockerCmd(c, "update", "--restart=on-failure:5", id) - - cli.WaitExited(c, id, timeout) - - count := inspectField(c, id, "RestartCount") - c.Assert(count, checker.Equals, "5") - - maximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") - c.Assert(maximumRetryCount, checker.Equals, "5") -} - -func (s *DockerSuite) TestUpdateRestartWithAutoRemoveFlag(c *check.C) { - out := runSleepingContainer(c, "--rm") - id := strings.TrimSpace(out) - - // update restart policy for an AutoRemove container - cli.Docker(cli.Args("update", "--restart=always", id)).Assert(c, icmd.Expected{ - ExitCode: 1, - Err: "Restart policy cannot be updated because AutoRemove is enabled for the container", - }) -} diff --git a/components/engine/integration/container/update_test.go b/components/engine/integration/container/update_test.go new file mode 100644 index 0000000000..aee95804a1 --- /dev/null +++ b/components/engine/integration/container/update_test.go @@ -0,0 +1,65 @@ +package container // import "github.com/docker/docker/integration/container" + +import ( + "context" + "testing" + "time" + + containertypes "github.com/docker/docker/api/types/container" + "github.com/docker/docker/integration/internal/container" + "github.com/docker/docker/integration/internal/request" + "github.com/docker/docker/internal/testutil" + "github.com/gotestyourself/gotestyourself/poll" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUpdateRestartPolicy(t *testing.T) { + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "sleep 1 && false"), func(c *container.TestContainerConfig) { + c.HostConfig.RestartPolicy = containertypes.RestartPolicy{ + Name: "on-failure", + MaximumRetryCount: 3, + } + }) + + _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{ + RestartPolicy: containertypes.RestartPolicy{ + Name: "on-failure", + MaximumRetryCount: 5, + }, + }) + require.NoError(t, err) + + timeout := 60 * time.Second + if testEnv.OSType == "windows" { + timeout = 180 * time.Second + } + + poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(timeout)) + + inspect, err := client.ContainerInspect(ctx, cID) + require.NoError(t, err) + assert.Equal(t, inspect.RestartCount, 5) + assert.Equal(t, inspect.HostConfig.RestartPolicy.MaximumRetryCount, 5) +} + +func TestUpdateRestartWithAutoRemove(t *testing.T) { + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) { + c.HostConfig.AutoRemove = true + }) + + _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{ + RestartPolicy: containertypes.RestartPolicy{ + Name: "always", + }, + }) + testutil.ErrorContains(t, err, "Restart policy cannot be updated because AutoRemove is enabled for the container") +} From f06f7f18497bca7c58401e1b2c939c978baa83f6 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 11 Feb 2018 23:43:12 +0000 Subject: [PATCH 13/14] Remove docker_api_swarm_config_test.go Signed-off-by: Yong Tang Upstream-commit: 31301769106f53a86d194ad68ff02642204a60cf Component: engine --- .../docker_api_swarm_config_test.go | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 components/engine/integration-cli/docker_api_swarm_config_test.go diff --git a/components/engine/integration-cli/docker_api_swarm_config_test.go b/components/engine/integration-cli/docker_api_swarm_config_test.go deleted file mode 100644 index c01d80ff7f..0000000000 --- a/components/engine/integration-cli/docker_api_swarm_config_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// +build !windows - -package main - -import ( - "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/integration-cli/checker" - "github.com/go-check/check" - "golang.org/x/net/context" -) - -func (s *DockerSwarmSuite) TestAPISwarmConfigsEmptyList(c *check.C) { - d := s.AddDaemon(c, true, true) - - configs := d.ListConfigs(c) - c.Assert(configs, checker.NotNil) - c.Assert(len(configs), checker.Equals, 0, check.Commentf("configs: %#v", configs)) -} - -func (s *DockerSwarmSuite) TestAPISwarmConfigsCreate(c *check.C) { - d := s.AddDaemon(c, true, true) - - testName := "test_config" - id := d.CreateConfig(c, swarm.ConfigSpec{ - Annotations: swarm.Annotations{ - Name: testName, - }, - Data: []byte("TESTINGDATA"), - }) - c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id)) - - configs := d.ListConfigs(c) - c.Assert(len(configs), checker.Equals, 1, check.Commentf("configs: %#v", configs)) - name := configs[0].Spec.Annotations.Name - c.Assert(name, checker.Equals, testName, check.Commentf("configs: %s", name)) -} - -func (s *DockerSwarmSuite) TestAPISwarmConfigsDelete(c *check.C) { - d := s.AddDaemon(c, true, true) - - testName := "test_config" - id := d.CreateConfig(c, swarm.ConfigSpec{Annotations: swarm.Annotations{ - Name: testName, - }, - Data: []byte("TESTINGDATA"), - }) - c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id)) - - config := d.GetConfig(c, id) - c.Assert(config.ID, checker.Equals, id, check.Commentf("config: %v", config)) - - d.DeleteConfig(c, config.ID) - - cli, err := d.NewClient() - c.Assert(err, checker.IsNil) - defer cli.Close() - - _, _, err = cli.ConfigInspectWithRaw(context.Background(), id) - c.Assert(err.Error(), checker.Contains, "No such config") -} - -func (s *DockerSwarmSuite) TestAPISwarmConfigsUpdate(c *check.C) { - d := s.AddDaemon(c, true, true) - - testName := "test_config" - id := d.CreateConfig(c, swarm.ConfigSpec{ - Annotations: swarm.Annotations{ - Name: testName, - Labels: map[string]string{ - "test": "test1", - }, - }, - Data: []byte("TESTINGDATA"), - }) - c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id)) - - config := d.GetConfig(c, id) - c.Assert(config.ID, checker.Equals, id, check.Commentf("config: %v", config)) - - // test UpdateConfig with full ID - d.UpdateConfig(c, id, func(s *swarm.Config) { - s.Spec.Labels = map[string]string{ - "test": "test1", - } - }) - - config = d.GetConfig(c, id) - c.Assert(config.Spec.Labels["test"], checker.Equals, "test1", check.Commentf("config: %v", config)) - - // test UpdateConfig with full name - d.UpdateConfig(c, config.Spec.Name, func(s *swarm.Config) { - s.Spec.Labels = map[string]string{ - "test": "test2", - } - }) - - config = d.GetConfig(c, id) - c.Assert(config.Spec.Labels["test"], checker.Equals, "test2", check.Commentf("config: %v", config)) - - // test UpdateConfig with prefix ID - d.UpdateConfig(c, id[:1], func(s *swarm.Config) { - s.Spec.Labels = map[string]string{ - "test": "test3", - } - }) - - config = d.GetConfig(c, id) - c.Assert(config.Spec.Labels["test"], checker.Equals, "test3", check.Commentf("config: %v", config)) - - // test UpdateConfig in updating Data which is not supported in daemon - // this test will produce an error in func UpdateConfig - config = d.GetConfig(c, id) - config.Spec.Data = []byte("TESTINGDATA2") - - cli, err := d.NewClient() - c.Assert(err, checker.IsNil) - defer cli.Close() - - expected := "only updates to Labels are allowed" - - err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec) - c.Assert(err.Error(), checker.Contains, expected) -} From c28bbfe97ad67720828e7d6bc2e630e72191c7b3 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 11 Feb 2018 23:43:24 +0000 Subject: [PATCH 14/14] Migrates several swarm configs tests from integration-cli to api tests This fix migrates several swarm configs tests from integration-cli to api tests Signed-off-by: Yong Tang Upstream-commit: 63bd2425fd5ec0dd17aad830652c1b0c5515a31c Component: engine --- .../engine/integration/config/config_test.go | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/components/engine/integration/config/config_test.go b/components/engine/integration/config/config_test.go index 0d7c557fad..fa2a205953 100644 --- a/components/engine/integration/config/config_test.go +++ b/components/engine/integration/config/config_test.go @@ -9,6 +9,7 @@ import ( swarmtypes "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" "github.com/docker/docker/integration/internal/swarm" + "github.com/docker/docker/internal/testutil" "github.com/gotestyourself/gotestyourself/skip" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -26,6 +27,11 @@ func TestConfigList(t *testing.T) { ctx := context.Background() + // This test case is ported from the original TestConfigsEmptyList + configs, err := client.ConfigList(ctx, types.ConfigListOptions{}) + require.NoError(t, err) + assert.Equal(t, len(configs), 0) + testName0 := "test0" testName1 := "test1" testNames := []string{testName0, testName1} @@ -100,3 +106,85 @@ func createConfig(ctx context.Context, t *testing.T, client client.APIClient, na assert.NotEqual(t, config.ID, "") return config.ID } + +func TestConfigsCreateAndDelete(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + d := swarm.NewSwarm(t, testEnv) + defer d.Stop(t) + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + ctx := context.Background() + + testName := "test_config" + + // This test case is ported from the original TestConfigsCreate + configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil) + + insp, _, err := client.ConfigInspectWithRaw(ctx, configID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Name, testName) + + // This test case is ported from the original TestConfigsDelete + err = client.ConfigRemove(ctx, configID) + require.NoError(t, err) + + insp, _, err = client.ConfigInspectWithRaw(ctx, configID) + testutil.ErrorContains(t, err, "No such config") +} + +func TestConfigsUpdate(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + d := swarm.NewSwarm(t, testEnv) + defer d.Stop(t) + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + ctx := context.Background() + + testName := "test_config" + + // This test case is ported from the original TestConfigsCreate + configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil) + + insp, _, err := client.ConfigInspectWithRaw(ctx, configID) + require.NoError(t, err) + assert.Equal(t, insp.ID, configID) + + // test UpdateConfig with full ID + insp.Spec.Labels = map[string]string{"test": "test1"} + err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec) + require.NoError(t, err) + + insp, _, err = client.ConfigInspectWithRaw(ctx, configID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Labels["test"], "test1") + + // test UpdateConfig with full name + insp.Spec.Labels = map[string]string{"test": "test2"} + err = client.ConfigUpdate(ctx, testName, insp.Version, insp.Spec) + require.NoError(t, err) + + insp, _, err = client.ConfigInspectWithRaw(ctx, configID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Labels["test"], "test2") + + // test UpdateConfig with prefix ID + insp.Spec.Labels = map[string]string{"test": "test3"} + err = client.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec) + require.NoError(t, err) + + insp, _, err = client.ConfigInspectWithRaw(ctx, configID) + require.NoError(t, err) + assert.Equal(t, insp.Spec.Labels["test"], "test3") + + // test UpdateConfig in updating Data which is not supported in daemon + // this test will produce an error in func UpdateConfig + insp.Spec.Data = []byte("TESTINGDATA2") + err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec) + testutil.ErrorContains(t, err, "only updates to Labels are allowed") +}