Parcourir la source

Add an integration/internal/container helper package

To help creating/running/… containers using the client for test integration.
This should make test more readable and reduce duplication a bit.

Usage example

```
// Create a default container named foo
id1 := container.Create(t, ctx, client, container.WithName("foo"))
// Run a default container with a custom command
id2 := container.Run(t, ctx, client, container.WithCmd("echo", "hello world"))
```

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Vincent Demeester il y a 7 ans
Parent
commit
0bb7d42b03

+ 7 - 6
integration/container/inspect_test.go

@@ -6,9 +6,8 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types/container"
-	"github.com/docker/docker/api/types/network"
 	"github.com/docker/docker/client"
+	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/integration/internal/request"
 	"github.com/gotestyourself/gotestyourself/poll"
 	"github.com/gotestyourself/gotestyourself/skip"
@@ -25,10 +24,12 @@ func TestInspectCpusetInConfigPre120(t *testing.T) {
 
 	name := "cpusetinconfig-pre120"
 	// Create container with up to-date-API
-	runSimpleContainer(ctx, t, request.NewAPIClient(t), name, func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		config.Cmd = []string{"true"}
-		hostConfig.Resources.CpusetCpus = "0"
-	})
+	container.Run(t, ctx, request.NewAPIClient(t), container.WithName(name),
+		container.WithCmd("true"),
+		func(c *container.TestContainerConfig) {
+			c.HostConfig.Resources.CpusetCpus = "0"
+		},
+	)
 	poll.WaitOn(t, containerIsInState(ctx, client, name, "exited"), poll.WithDelay(100*time.Millisecond))
 
 	_, body, err := client.ContainerInspectWithRaw(ctx, name, false)

+ 27 - 74
integration/container/kill_test.go

@@ -5,11 +5,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/api/types/container"
-	"github.com/docker/docker/api/types/network"
-	"github.com/docker/docker/api/types/strslice"
+	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/client"
+	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/integration/internal/request"
 	"github.com/gotestyourself/gotestyourself/poll"
 	"github.com/gotestyourself/gotestyourself/skip"
@@ -20,25 +18,15 @@ func TestKillContainerInvalidSignal(t *testing.T) {
 	defer setupTest(t)()
 	client := request.NewAPIClient(t)
 	ctx := context.Background()
-	c, err := client.ContainerCreate(ctx,
-		&container.Config{
-			Image: "busybox",
-			Cmd:   strslice.StrSlice([]string{"top"}),
-		},
-		&container.HostConfig{},
-		&network.NetworkingConfig{},
-		"")
-	require.NoError(t, err)
-	err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
-	require.NoError(t, err)
+	id := container.Run(t, ctx, client)
 
-	err = client.ContainerKill(ctx, c.ID, "0")
+	err := client.ContainerKill(ctx, id, "0")
 	require.EqualError(t, err, "Error response from daemon: Invalid signal: 0")
-	poll.WaitOn(t, containerIsInState(ctx, client, c.ID, "running"), poll.WithDelay(100*time.Millisecond))
+	poll.WaitOn(t, containerIsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
 
-	err = client.ContainerKill(ctx, c.ID, "SIG42")
+	err = client.ContainerKill(ctx, id, "SIG42")
 	require.EqualError(t, err, "Error response from daemon: Invalid signal: SIG42")
-	poll.WaitOn(t, containerIsInState(ctx, client, c.ID, "running"), poll.WithDelay(100*time.Millisecond))
+	poll.WaitOn(t, containerIsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
 }
 
 func TestKillContainer(t *testing.T) {
@@ -71,21 +59,11 @@ func TestKillContainer(t *testing.T) {
 		tc := tc
 		t.Run(tc.doc, func(t *testing.T) {
 			ctx := context.Background()
-			c, err := client.ContainerCreate(ctx,
-				&container.Config{
-					Image: "busybox",
-					Cmd:   strslice.StrSlice([]string{"top"}),
-				},
-				&container.HostConfig{},
-				&network.NetworkingConfig{},
-				"")
-			require.NoError(t, err)
-			err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
-			require.NoError(t, err)
-			err = client.ContainerKill(ctx, c.ID, tc.signal)
+			id := container.Run(t, ctx, client)
+			err := client.ContainerKill(ctx, id, tc.signal)
 			require.NoError(t, err)
 
-			poll.WaitOn(t, containerIsInState(ctx, client, c.ID, tc.status), poll.WithDelay(100*time.Millisecond))
+			poll.WaitOn(t, containerIsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
 		})
 	}
 }
@@ -116,25 +94,16 @@ func TestKillWithStopSignalAndRestartPolicies(t *testing.T) {
 		tc := tc
 		t.Run(tc.doc, func(t *testing.T) {
 			ctx := context.Background()
-			c, err := client.ContainerCreate(ctx,
-				&container.Config{
-					Image:      "busybox",
-					Cmd:        strslice.StrSlice([]string{"top"}),
-					StopSignal: tc.stopsignal,
-				},
-				&container.HostConfig{
-					RestartPolicy: container.RestartPolicy{
-						Name: "always",
-					}},
-				&network.NetworkingConfig{},
-				"")
-			require.NoError(t, err)
-			err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
-			require.NoError(t, err)
-			err = client.ContainerKill(ctx, c.ID, "TERM")
+			id := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
+				c.Config.StopSignal = tc.stopsignal
+				c.HostConfig.RestartPolicy = containertypes.RestartPolicy{
+					Name: "always",
+				}
+			})
+			err := client.ContainerKill(ctx, id, "TERM")
 			require.NoError(t, err)
 
-			poll.WaitOn(t, containerIsInState(ctx, client, c.ID, tc.status), poll.WithDelay(100*time.Millisecond))
+			poll.WaitOn(t, containerIsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
 		})
 	}
 }
@@ -144,16 +113,8 @@ func TestKillStoppedContainer(t *testing.T) {
 	defer setupTest(t)()
 	ctx := context.Background()
 	client := request.NewAPIClient(t)
-	c, err := client.ContainerCreate(ctx,
-		&container.Config{
-			Image: "busybox",
-			Cmd:   strslice.StrSlice([]string{"top"}),
-		},
-		&container.HostConfig{},
-		&network.NetworkingConfig{},
-		"")
-	require.NoError(t, err)
-	err = client.ContainerKill(ctx, c.ID, "SIGKILL")
+	id := container.Create(t, ctx, client)
+	err := client.ContainerKill(ctx, id, "SIGKILL")
 	require.Error(t, err)
 	require.Contains(t, err.Error(), "is not running")
 }
@@ -163,16 +124,8 @@ func TestKillStoppedContainerAPIPre120(t *testing.T) {
 	defer setupTest(t)()
 	ctx := context.Background()
 	client := request.NewAPIClient(t, client.WithVersion("1.19"))
-	c, err := client.ContainerCreate(ctx,
-		&container.Config{
-			Image: "busybox",
-			Cmd:   strslice.StrSlice([]string{"top"}),
-		},
-		&container.HostConfig{},
-		&network.NetworkingConfig{},
-		"")
-	require.NoError(t, err)
-	err = client.ContainerKill(ctx, c.ID, "SIGKILL")
+	id := container.Create(t, ctx, client)
+	err := client.ContainerKill(ctx, id, "SIGKILL")
 	require.NoError(t, err)
 }
 
@@ -184,12 +137,12 @@ func TestKillDifferentUserContainer(t *testing.T) {
 	ctx := context.Background()
 	client := request.NewAPIClient(t, client.WithVersion("1.19"))
 
-	cID := runSimpleContainer(ctx, t, client, "", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		config.User = "daemon"
+	id := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
+		c.Config.User = "daemon"
 	})
-	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
+	poll.WaitOn(t, containerIsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
 
-	err := client.ContainerKill(ctx, cID, "SIGKILL")
+	err := client.ContainerKill(ctx, id, "SIGKILL")
 	require.NoError(t, err)
-	poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
+	poll.WaitOn(t, containerIsInState(ctx, client, id, "exited"), poll.WithDelay(100*time.Millisecond))
 }

+ 0 - 35
integration/container/main_test.go

@@ -1,17 +1,11 @@
 package container // import "github.com/docker/docker/integration/container"
 
 import (
-	"context"
 	"fmt"
 	"os"
 	"testing"
 
-	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/api/types/container"
-	"github.com/docker/docker/api/types/network"
-	"github.com/docker/docker/client"
 	"github.com/docker/docker/internal/test/environment"
-	"github.com/stretchr/testify/require"
 )
 
 var testEnv *environment.Execution
@@ -37,32 +31,3 @@ func setupTest(t *testing.T) func() {
 	environment.ProtectAll(t, testEnv)
 	return func() { testEnv.Clean(t) }
 }
-
-type containerConstructor func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig)
-
-func createSimpleContainer(ctx context.Context, t *testing.T, client client.APIClient, name string, f ...containerConstructor) string {
-	config := &container.Config{
-		Cmd:   []string{"top"},
-		Image: "busybox",
-	}
-	hostConfig := &container.HostConfig{}
-	networkingConfig := &network.NetworkingConfig{}
-
-	for _, fn := range f {
-		fn(config, hostConfig, networkingConfig)
-	}
-
-	c, err := client.ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
-	require.NoError(t, err)
-
-	return c.ID
-}
-
-func runSimpleContainer(ctx context.Context, t *testing.T, client client.APIClient, name string, f ...containerConstructor) string {
-	cID := createSimpleContainer(ctx, t, client, name, f...)
-
-	err := client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
-	require.NoError(t, err)
-
-	return cID
-}

+ 19 - 29
integration/container/rename_test.go

@@ -6,8 +6,8 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/network"
+	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/integration/internal/request"
 	"github.com/docker/docker/internal/testutil"
 	"github.com/docker/docker/pkg/stringid"
@@ -26,23 +26,18 @@ func TestRenameLinkedContainer(t *testing.T) {
 	ctx := context.Background()
 	client := request.NewAPIClient(t)
 
-	aID := runSimpleContainer(ctx, t, client, "a0")
-
-	bID := runSimpleContainer(ctx, t, client, "b0", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		hostConfig.Links = []string{"a0"}
-	})
+	aID := container.Run(t, ctx, client, container.WithName("a0"))
+	bID := container.Run(t, ctx, client, container.WithName("b0"), container.WithLinks("a0"))
 
 	err := client.ContainerRename(ctx, aID, "a1")
 	require.NoError(t, err)
 
-	runSimpleContainer(ctx, t, client, "a0")
+	container.Run(t, ctx, client, container.WithName("a0"))
 
 	err = client.ContainerRemove(ctx, bID, types.ContainerRemoveOptions{Force: true})
 	require.NoError(t, err)
 
-	bID = runSimpleContainer(ctx, t, client, "b0", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		hostConfig.Links = []string{"a0"}
-	})
+	bID = container.Run(t, ctx, client, container.WithName("b0"), container.WithLinks("a0"))
 
 	inspect, err := client.ContainerInspect(ctx, bID)
 	require.NoError(t, err)
@@ -55,9 +50,7 @@ func TestRenameStoppedContainer(t *testing.T) {
 	client := request.NewAPIClient(t)
 
 	oldName := "first_name"
-	cID := runSimpleContainer(ctx, t, client, oldName, func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		config.Cmd = []string{"sh"}
-	})
+	cID := container.Run(t, ctx, client, container.WithName(oldName), container.WithCmd("sh"))
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
 
 	inspect, err := client.ContainerInspect(ctx, cID)
@@ -79,7 +72,7 @@ func TestRenameRunningContainerAndReuse(t *testing.T) {
 	client := request.NewAPIClient(t)
 
 	oldName := "first_name"
-	cID := runSimpleContainer(ctx, t, client, oldName)
+	cID := container.Run(t, ctx, client, container.WithName(oldName))
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
 
 	newName := "new_name" + stringid.GenerateNonCryptoID()
@@ -93,7 +86,7 @@ func TestRenameRunningContainerAndReuse(t *testing.T) {
 	_, err = client.ContainerInspect(ctx, oldName)
 	testutil.ErrorContains(t, err, "No such container: "+oldName)
 
-	cID = runSimpleContainer(ctx, t, client, oldName)
+	cID = container.Run(t, ctx, client, container.WithName(oldName))
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
 
 	inspect, err = client.ContainerInspect(ctx, cID)
@@ -107,7 +100,7 @@ func TestRenameInvalidName(t *testing.T) {
 	client := request.NewAPIClient(t)
 
 	oldName := "first_name"
-	cID := runSimpleContainer(ctx, t, client, oldName)
+	cID := container.Run(t, ctx, client, container.WithName(oldName))
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
 
 	err := client.ContainerRename(ctx, oldName, "new:invalid")
@@ -132,11 +125,11 @@ func TestRenameAnonymousContainer(t *testing.T) {
 
 	_, err := client.NetworkCreate(ctx, "network1", types.NetworkCreate{})
 	require.NoError(t, err)
-	cID := createSimpleContainer(ctx, t, client, "", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		networkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
+	cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
+		c.NetworkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
 			"network1": {},
 		}
-		hostConfig.NetworkMode = "network1"
+		c.HostConfig.NetworkMode = "network1"
 	})
 	err = client.ContainerRename(ctx, cID, "container1")
 	require.NoError(t, err)
@@ -149,13 +142,12 @@ func TestRenameAnonymousContainer(t *testing.T) {
 	if testEnv.OSType == "windows" {
 		count = "-n"
 	}
-	cID = runSimpleContainer(ctx, t, client, "", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		networkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
+	cID = container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
+		c.NetworkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
 			"network1": {},
 		}
-		hostConfig.NetworkMode = "network1"
-		config.Cmd = []string{"ping", count, "1", "container1"}
-	})
+		c.HostConfig.NetworkMode = "network1"
+	}, container.WithCmd("ping", count, "1", "container1"))
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
 
 	inspect, err := client.ContainerInspect(ctx, cID)
@@ -169,7 +161,7 @@ func TestRenameContainerWithSameName(t *testing.T) {
 	ctx := context.Background()
 	client := request.NewAPIClient(t)
 
-	cID := runSimpleContainer(ctx, t, client, "old")
+	cID := container.Run(t, ctx, client, container.WithName("old"))
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
 	err := client.ContainerRename(ctx, "old", "old")
 	testutil.ErrorContains(t, err, "Renaming a container with the same name")
@@ -189,12 +181,10 @@ func TestRenameContainerWithLinkedContainer(t *testing.T) {
 	ctx := context.Background()
 	client := request.NewAPIClient(t)
 
-	db1ID := runSimpleContainer(ctx, t, client, "db1")
+	db1ID := container.Run(t, ctx, client, container.WithName("db1"))
 	poll.WaitOn(t, containerIsInState(ctx, client, db1ID, "running"), poll.WithDelay(100*time.Millisecond))
 
-	app1ID := runSimpleContainer(ctx, t, client, "app1", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		hostConfig.Links = []string{"db1:/mysql"}
-	})
+	app1ID := container.Run(t, ctx, client, container.WithName("app1"), container.WithLinks("db1:/mysql"))
 	poll.WaitOn(t, containerIsInState(ctx, client, app1ID, "running"), poll.WithDelay(100*time.Millisecond))
 
 	err := client.ContainerRename(ctx, "app1", "app2")

+ 4 - 7
integration/container/resize_test.go

@@ -7,9 +7,8 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/api/types/container"
-	"github.com/docker/docker/api/types/network"
 	req "github.com/docker/docker/integration-cli/request"
+	"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"
@@ -22,7 +21,7 @@ func TestResize(t *testing.T) {
 	client := request.NewAPIClient(t)
 	ctx := context.Background()
 
-	cID := runSimpleContainer(ctx, t, client, "")
+	cID := container.Run(t, ctx, client)
 
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
 
@@ -38,7 +37,7 @@ func TestResizeWithInvalidSize(t *testing.T) {
 	client := request.NewAPIClient(t)
 	ctx := context.Background()
 
-	cID := runSimpleContainer(ctx, t, client, "")
+	cID := container.Run(t, ctx, client)
 
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
 
@@ -53,9 +52,7 @@ func TestResizeWhenContainerNotStarted(t *testing.T) {
 	client := request.NewAPIClient(t)
 	ctx := context.Background()
 
-	cID := runSimpleContainer(ctx, t, client, "", func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) {
-		config.Cmd = []string{"echo"}
-	})
+	cID := container.Run(t, ctx, client, container.WithCmd("echo"))
 
 	poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
 

+ 54 - 0
integration/internal/container/container.go

@@ -0,0 +1,54 @@
+package container
+
+import (
+	"context"
+	"testing"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/network"
+	"github.com/docker/docker/client"
+	"github.com/stretchr/testify/require"
+)
+
+// TestContainerConfig holds container configuration struct that
+// are used in api calls.
+type TestContainerConfig struct {
+	Name             string
+	Config           *container.Config
+	HostConfig       *container.HostConfig
+	NetworkingConfig *network.NetworkingConfig
+}
+
+// Create creates a container with the specified options
+func Create(t *testing.T, ctx context.Context, client client.APIClient, ops ...func(*TestContainerConfig)) string { // nolint: golint
+	t.Helper()
+	config := &TestContainerConfig{
+		Config: &container.Config{
+			Image: "busybox",
+			Cmd:   []string{"top"},
+		},
+		HostConfig:       &container.HostConfig{},
+		NetworkingConfig: &network.NetworkingConfig{},
+	}
+
+	for _, op := range ops {
+		op(config)
+	}
+
+	c, err := client.ContainerCreate(ctx, config.Config, config.HostConfig, config.NetworkingConfig, config.Name)
+	require.NoError(t, err)
+
+	return c.ID
+}
+
+// Run creates and start a container with the specified options
+func Run(t *testing.T, ctx context.Context, client client.APIClient, ops ...func(*TestContainerConfig)) string { // nolint: golint
+	t.Helper()
+	id := Create(t, ctx, client, ops...)
+
+	err := client.ContainerStart(ctx, id, types.ContainerStartOptions{})
+	require.NoError(t, err)
+
+	return id
+}

+ 24 - 0
integration/internal/container/ops.go

@@ -0,0 +1,24 @@
+package container
+
+import "github.com/docker/docker/api/types/strslice"
+
+// WithName sets the name of the container
+func WithName(name string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.Name = name
+	}
+}
+
+// WithLinks sets the links of the container
+func WithLinks(links ...string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.HostConfig.Links = links
+	}
+}
+
+// WithCmd sets the comannds of the container
+func WithCmd(cmds ...string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.Config.Cmd = strslice.StrSlice(cmds)
+	}
+}