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>
This commit is contained in:
Vincent Demeester 2018-02-09 19:37:55 +01:00
parent 3053006679
commit 0bb7d42b03
No known key found for this signature in database
GPG Key ID: 083CC6FD6EB699A3
7 changed files with 135 additions and 151 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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