Merge pull request #512 from thaJeztah/18.03-backport-tests
[18.03] backport updates to tests, and fix empty LogPath with non-blocking logging mode
This commit is contained in:
@@ -142,7 +142,7 @@ RUN set -x \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT 5e28dcaace5f7b70cbe44c313b7a3b288fa38916
|
||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
||||
# To run integration tests docker-pycreds is required.
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
|
||||
@@ -106,7 +106,7 @@ RUN set -x \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT 5e28dcaace5f7b70cbe44c313b7a3b288fa38916
|
||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
||||
# To run integration tests docker-pycreds is required.
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
|
||||
@@ -104,7 +104,7 @@ RUN set -x \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT 5e28dcaace5f7b70cbe44c313b7a3b288fa38916
|
||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
||||
# To run integration tests docker-pycreds is required.
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
|
||||
@@ -102,7 +102,7 @@ RUN set -x \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT 5e28dcaace5f7b70cbe44c313b7a3b288fa38916
|
||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
||||
# To run integration tests docker-pycreds is required.
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
|
||||
@@ -96,7 +96,7 @@ RUN set -x \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT 5e28dcaace5f7b70cbe44c313b7a3b288fa38916
|
||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
||||
# To run integration tests docker-pycreds is required.
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/go-units"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
@@ -391,6 +391,8 @@ func (container *Container) StartLogger() (logger.Logger, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
container.LogPath = info.LogPath
|
||||
}
|
||||
|
||||
l, err := initDriver(info)
|
||||
@@ -974,11 +976,6 @@ func (container *Container) startLogging() error {
|
||||
copier.Run()
|
||||
container.LogDriver = l
|
||||
|
||||
// set LogPath field only for json-file logdriver
|
||||
if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok {
|
||||
container.LogPath = jl.LogPath()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package container // import "github.com/docker/docker/container"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/daemon/logger/jsonfilelog"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestContainerStopSignal(t *testing.T) {
|
||||
@@ -66,3 +71,56 @@ func TestContainerSecretReferenceDestTarget(t *testing.T) {
|
||||
t.Fatalf("expected secret dest %q; received %q", expected, d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerLogPathSetForJSONFileLogger(t *testing.T) {
|
||||
containerRoot, err := ioutil.TempDir("", "TestContainerLogPathSetForJSONFileLogger")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(containerRoot)
|
||||
|
||||
c := &Container{
|
||||
Config: &container.Config{},
|
||||
HostConfig: &container.HostConfig{
|
||||
LogConfig: container.LogConfig{
|
||||
Type: jsonfilelog.Name,
|
||||
},
|
||||
},
|
||||
ID: "TestContainerLogPathSetForJSONFileLogger",
|
||||
Root: containerRoot,
|
||||
}
|
||||
|
||||
logger, err := c.StartLogger()
|
||||
require.NoError(t, err)
|
||||
defer logger.Close()
|
||||
|
||||
expectedLogPath, err := filepath.Abs(filepath.Join(containerRoot, fmt.Sprintf("%s-json.log", c.ID)))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.LogPath, expectedLogPath)
|
||||
}
|
||||
|
||||
func TestContainerLogPathSetForRingLogger(t *testing.T) {
|
||||
containerRoot, err := ioutil.TempDir("", "TestContainerLogPathSetForRingLogger")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(containerRoot)
|
||||
|
||||
c := &Container{
|
||||
Config: &container.Config{},
|
||||
HostConfig: &container.HostConfig{
|
||||
LogConfig: container.LogConfig{
|
||||
Type: jsonfilelog.Name,
|
||||
Config: map[string]string{
|
||||
"mode": string(container.LogModeNonBlock),
|
||||
},
|
||||
},
|
||||
},
|
||||
ID: "TestContainerLogPathSetForRingLogger",
|
||||
Root: containerRoot,
|
||||
}
|
||||
|
||||
logger, err := c.StartLogger()
|
||||
require.NoError(t, err)
|
||||
defer logger.Close()
|
||||
|
||||
expectedLogPath, err := filepath.Abs(filepath.Join(containerRoot, fmt.Sprintf("%s-json.log", c.ID)))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, c.LogPath, expectedLogPath)
|
||||
}
|
||||
|
||||
@@ -150,11 +150,6 @@ func ValidateLogOpt(cfg map[string]string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LogPath returns the location the given json logger logs to.
|
||||
func (l *JSONFileLogger) LogPath() string {
|
||||
return l.writer.LogPath()
|
||||
}
|
||||
|
||||
// Close closes underlying file and signals all readers to stop.
|
||||
func (l *JSONFileLogger) Close() error {
|
||||
l.mu.Lock()
|
||||
|
||||
@@ -130,13 +130,6 @@ func rotate(name string, maxFiles int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LogPath returns the location the given writer logs to.
|
||||
func (w *LogFile) LogPath() string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.f.Name()
|
||||
}
|
||||
|
||||
// MaxFiles return maximum number of files
|
||||
func (w *LogFile) MaxFiles() int {
|
||||
return w.maxFiles
|
||||
|
||||
@@ -84,7 +84,7 @@ type DockerSuite struct {
|
||||
}
|
||||
|
||||
func (s *DockerSuite) OnTimeout(c *check.C) {
|
||||
if !testEnv.IsLocalDaemon() {
|
||||
if testEnv.IsRemoteDaemon() {
|
||||
return
|
||||
}
|
||||
path := filepath.Join(os.Getenv("DEST"), "docker.pid")
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/request"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestEventsAPIEmptyOutput(c *check.C) {
|
||||
type apiResp struct {
|
||||
resp *http.Response
|
||||
err error
|
||||
}
|
||||
chResp := make(chan *apiResp)
|
||||
go func() {
|
||||
resp, body, err := request.Get("/events")
|
||||
body.Close()
|
||||
chResp <- &apiResp{resp, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case r := <-chResp:
|
||||
c.Assert(r.err, checker.IsNil)
|
||||
c.Assert(r.resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
case <-time.After(3 * time.Second):
|
||||
c.Fatal("timeout waiting for events api to respond, should have responded immediately")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsAPIBackwardsCompatible(c *check.C) {
|
||||
since := daemonTime(c).Unix()
|
||||
ts := strconv.FormatInt(since, 10)
|
||||
|
||||
out := runSleepingContainer(c, "--name=foo", "-d")
|
||||
containerID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(containerID), checker.IsNil)
|
||||
|
||||
q := url.Values{}
|
||||
q.Set("since", ts)
|
||||
|
||||
_, body, err := request.Get("/events?" + q.Encode())
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer body.Close()
|
||||
|
||||
dec := json.NewDecoder(body)
|
||||
var containerCreateEvent *jsonmessage.JSONMessage
|
||||
for {
|
||||
var event jsonmessage.JSONMessage
|
||||
if err := dec.Decode(&event); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
c.Fatal(err)
|
||||
}
|
||||
if event.Status == "create" && event.ID == containerID {
|
||||
containerCreateEvent = &event
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(containerCreateEvent, checker.Not(checker.IsNil))
|
||||
c.Assert(containerCreateEvent.Status, checker.Equals, "create")
|
||||
c.Assert(containerCreateEvent.ID, checker.Equals, containerID)
|
||||
c.Assert(containerCreateEvent.From, checker.Equals, "busybox")
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestVolumesAPIList(c *check.C) {
|
||||
prefix, _ := getPrefixAndSlashFromDaemonPlatform()
|
||||
cid, _ := dockerCmd(c, "run", "-d", "-v", prefix+"/foo", "busybox")
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerInspect(context.Background(), strings.TrimSpace(cid))
|
||||
c.Assert(err, checker.IsNil)
|
||||
vname := container.Mounts[0].Name
|
||||
|
||||
volumes, err := cli.VolumeList(context.Background(), filters.Args{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
found := false
|
||||
for _, vol := range volumes.Volumes {
|
||||
if vol.Name == vname {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Assert(found, checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumesAPICreate(c *check.C) {
|
||||
config := volumetypes.VolumesCreateBody{
|
||||
Name: "test",
|
||||
}
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
vol, err := cli.VolumeCreate(context.Background(), config)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
c.Assert(filepath.Base(filepath.Dir(vol.Mountpoint)), checker.Equals, config.Name)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumesAPIRemove(c *check.C) {
|
||||
prefix, _ := getPrefixAndSlashFromDaemonPlatform()
|
||||
cid, _ := dockerCmd(c, "run", "-d", "-v", prefix+"/foo", "--name=test", "busybox")
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
container, err := cli.ContainerInspect(context.Background(), strings.TrimSpace(cid))
|
||||
c.Assert(err, checker.IsNil)
|
||||
vname := container.Mounts[0].Name
|
||||
|
||||
err = cli.VolumeRemove(context.Background(), vname, false)
|
||||
c.Assert(err.Error(), checker.Contains, "volume is in use")
|
||||
|
||||
dockerCmd(c, "rm", "-f", "test")
|
||||
err = cli.VolumeRemove(context.Background(), vname, false)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumesAPIInspect(c *check.C) {
|
||||
config := volumetypes.VolumesCreateBody{
|
||||
Name: "test",
|
||||
}
|
||||
|
||||
// sampling current time minus a minute so to now have false positive in case of delays
|
||||
now := time.Now().Truncate(time.Minute)
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.VolumeCreate(context.Background(), config)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
vol, err := cli.VolumeInspect(context.Background(), config.Name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(vol.Name, checker.Equals, config.Name)
|
||||
|
||||
// comparing CreatedAt field time for the new volume to now. Removing a minute from both to avoid false positive
|
||||
testCreatedAt, err := time.Parse(time.RFC3339, strings.TrimSpace(vol.CreatedAt))
|
||||
c.Assert(err, check.IsNil)
|
||||
testCreatedAt = testCreatedAt.Truncate(time.Minute)
|
||||
if !testCreatedAt.Equal(now) {
|
||||
c.Assert(fmt.Errorf("Time Volume is CreatedAt not equal to current time"), check.NotNil)
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestConfigInspect(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.Spec.Name, checker.Equals, testName)
|
||||
|
||||
out, err := d.Cmd("config", "inspect", testName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
var configs []swarm.Config
|
||||
c.Assert(json.Unmarshal([]byte(out), &configs), checker.IsNil)
|
||||
c.Assert(configs, checker.HasLen, 1)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestConfigInspectMultiple(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
testNames := []string{
|
||||
"test0",
|
||||
"test1",
|
||||
}
|
||||
for _, n := range testNames {
|
||||
id := d.CreateConfig(c, swarm.ConfigSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: n,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
|
||||
|
||||
config := d.GetConfig(c, id)
|
||||
c.Assert(config.Spec.Name, checker.Equals, n)
|
||||
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"config",
|
||||
"inspect",
|
||||
}
|
||||
args = append(args, testNames...)
|
||||
out, err := d.Cmd(args...)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
var configs []swarm.Config
|
||||
c.Assert(json.Unmarshal([]byte(out), &configs), checker.IsNil)
|
||||
c.Assert(configs, checker.HasLen, 2)
|
||||
}
|
||||
@@ -9,25 +9,8 @@ import (
|
||||
"github.com/gotestyourself/gotestyourself/icmd"
|
||||
)
|
||||
|
||||
// export an image and try to import it into a new one
|
||||
func (s *DockerSuite) TestExportContainerAndImportImage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := "testexportcontainerandimportimage"
|
||||
|
||||
dockerCmd(c, "run", "--name", containerID, "busybox", "true")
|
||||
|
||||
out, _ := dockerCmd(c, "export", containerID)
|
||||
|
||||
result := icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "import", "-", "repo/testexp:v1"},
|
||||
Stdin: strings.NewReader(out),
|
||||
})
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
cleanedImageID := strings.TrimSpace(result.Combined())
|
||||
c.Assert(cleanedImageID, checker.Not(checker.Equals), "", check.Commentf("output should have been an image id"))
|
||||
}
|
||||
|
||||
// TODO: Move this test to docker/cli, as it is essentially the same test
|
||||
// as TestExportContainerAndImportImage except output to a file.
|
||||
// Used to test output flag in the export command
|
||||
func (s *DockerSuite) TestExportContainerWithOutputAndImportImage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestRmContainerWithRemovedVolume(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
tempDir, err := ioutil.TempDir("", "test-rm-container-with-removed-volume-")
|
||||
if err != nil {
|
||||
c.Fatalf("failed to create temporary directory: %s", tempDir)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
dockerCmd(c, "run", "--name", "losemyvolumes", "-v", tempDir+":"+prefix+slash+"test", "busybox", "true")
|
||||
|
||||
err = os.RemoveAll(tempDir)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
dockerCmd(c, "rm", "-v", "losemyvolumes")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmContainerWithVolume(c *check.C) {
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
dockerCmd(c, "run", "--name", "foo", "-v", prefix+slash+"srv", "busybox", "true")
|
||||
|
||||
dockerCmd(c, "rm", "-v", "foo")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmContainerRunning(c *check.C) {
|
||||
createRunningContainer(c, "foo")
|
||||
|
||||
res, _, err := dockerCmdWithError("rm", "foo")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("Expected error, can't rm a running container"))
|
||||
c.Assert(res, checker.Contains, "cannot remove a running container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmContainerForceRemoveRunning(c *check.C) {
|
||||
createRunningContainer(c, "foo")
|
||||
|
||||
// Stop then remove with -f
|
||||
dockerCmd(c, "rm", "-f", "foo")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmContainerOrphaning(c *check.C) {
|
||||
dockerfile1 := `FROM busybox:latest
|
||||
ENTRYPOINT ["true"]`
|
||||
img := "test-container-orphaning"
|
||||
dockerfile2 := `FROM busybox:latest
|
||||
ENTRYPOINT ["true"]
|
||||
MAINTAINER Integration Tests`
|
||||
|
||||
// build first dockerfile
|
||||
buildImageSuccessfully(c, img, build.WithDockerfile(dockerfile1))
|
||||
img1 := getIDByName(c, img)
|
||||
// run container on first image
|
||||
dockerCmd(c, "run", img)
|
||||
// rebuild dockerfile with a small addition at the end
|
||||
buildImageSuccessfully(c, img, build.WithDockerfile(dockerfile2))
|
||||
// try to remove the image, should not error out.
|
||||
out, _, err := dockerCmdWithError("rmi", img)
|
||||
c.Assert(err, check.IsNil, check.Commentf("Expected to removing the image, but failed: %s", out))
|
||||
|
||||
// check if we deleted the first image
|
||||
out, _ = dockerCmd(c, "images", "-q", "--no-trunc")
|
||||
c.Assert(out, checker.Contains, img1, check.Commentf("Orphaned container (could not find %q in docker images): %s", img1, out))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmInvalidContainer(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("rm", "unknown")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("Expected error on rm unknown container, got none"))
|
||||
c.Assert(out, checker.Contains, "No such container")
|
||||
}
|
||||
|
||||
func createRunningContainer(c *check.C, name string) {
|
||||
runSleepingContainer(c, "-dt", "--name", name)
|
||||
}
|
||||
@@ -12,45 +12,6 @@ import (
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestSecretCreate(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.Spec.Name, checker.Equals, testName)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSecretCreateWithLabels(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{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
},
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
secret := d.GetSecret(c, id)
|
||||
c.Assert(secret.Spec.Name, checker.Equals, testName)
|
||||
c.Assert(len(secret.Spec.Labels), checker.Equals, 2)
|
||||
c.Assert(secret.Spec.Labels["key1"], checker.Equals, "value1")
|
||||
c.Assert(secret.Spec.Labels["key2"], checker.Equals, "value2")
|
||||
}
|
||||
|
||||
// Test case for 28884
|
||||
func (s *DockerSwarmSuite) TestSecretCreateResolve(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestSecretInspectMultiple(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
testNames := []string{
|
||||
"test0",
|
||||
"test1",
|
||||
}
|
||||
for _, n := range testNames {
|
||||
id := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: n,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
secret := d.GetSecret(c, id)
|
||||
c.Assert(secret.Spec.Name, checker.Equals, n)
|
||||
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"secret",
|
||||
"inspect",
|
||||
}
|
||||
args = append(args, testNames...)
|
||||
out, err := d.Cmd(args...)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
var secrets []swarm.Secret
|
||||
c.Assert(json.Unmarshal([]byte(out), &secrets), checker.IsNil)
|
||||
c.Assert(secrets, checker.HasLen, 2)
|
||||
}
|
||||
@@ -11,41 +11,6 @@ import (
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceUpdatePort(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
serviceName := "TestServiceUpdatePort"
|
||||
serviceArgs := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "-p", "8080:8081", defaultSleepImage}, sleepCommandForDaemonPlatform()...)
|
||||
|
||||
// Create a service with a port mapping of 8080:8081.
|
||||
out, err := d.Cmd(serviceArgs...)
|
||||
c.Assert(err, checker.IsNil)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
|
||||
// Update the service: changed the port mapping from 8080:8081 to 8082:8083.
|
||||
_, err = d.Cmd("service", "update", "--detach", "--publish-add", "8082:8083", "--publish-rm", "8081", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Inspect the service and verify port mapping
|
||||
expected := []swarm.PortConfig{
|
||||
{
|
||||
Protocol: "tcp",
|
||||
PublishedPort: 8082,
|
||||
TargetPort: 8083,
|
||||
PublishMode: "ingress",
|
||||
},
|
||||
}
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.EndpointSpec.Ports }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var portConfig []swarm.PortConfig
|
||||
if err := json.Unmarshal([]byte(out), &portConfig); err != nil {
|
||||
c.Fatalf("invalid JSON in inspect result: %v (%s)", err, out)
|
||||
}
|
||||
c.Assert(portConfig, checker.DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceUpdateLabel(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name=test", "busybox", "top")
|
||||
|
||||
@@ -42,6 +42,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
|
||||
master := "dm-dummy0"
|
||||
// simulate the master link the vlan tagged subinterface parent link will use
|
||||
createMasterDummy(c, master)
|
||||
// cleanup the master interface that also collects the slave dev
|
||||
defer deleteInterface(c, master)
|
||||
// create a network specifying the desired sub-interface name
|
||||
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.60", "dm-persist")
|
||||
assertNwIsAvailable(c, "dm-persist")
|
||||
@@ -49,8 +51,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
|
||||
s.d.Restart(c)
|
||||
// verify network is recreated from persistence
|
||||
assertNwIsAvailable(c, "dm-persist")
|
||||
// cleanup the master interface that also collects the slave dev
|
||||
deleteInterface(c, "dm-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
|
||||
@@ -60,6 +60,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
|
||||
master := "di-dummy0"
|
||||
// simulate the master link the vlan tagged subinterface parent link will use
|
||||
createMasterDummy(c, master)
|
||||
// cleanup the master interface that also collects the slave dev
|
||||
defer deleteInterface(c, master)
|
||||
// create a network specifying the desired sub-interface name
|
||||
dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.70", "di-persist")
|
||||
assertNwIsAvailable(c, "di-persist")
|
||||
@@ -67,8 +69,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
|
||||
s.d.Restart(c)
|
||||
// verify network is recreated from persistence
|
||||
assertNwIsAvailable(c, "di-persist")
|
||||
// cleanup the master interface that also collects the slave dev
|
||||
deleteInterface(c, "di-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
|
||||
@@ -78,11 +78,11 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
|
||||
master := "dm-dummy0"
|
||||
// simulate the master link the vlan tagged subinterface parent link will use
|
||||
createMasterDummy(c, master)
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
defer deleteInterface(c, master)
|
||||
// create a network specifying the desired sub-interface name
|
||||
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.50", "dm-subinterface")
|
||||
assertNwIsAvailable(c, "dm-subinterface")
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
deleteInterface(c, "dm-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
|
||||
@@ -92,11 +92,11 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
|
||||
master := "di-dummy0"
|
||||
// simulate the master link the vlan tagged subinterface parent link will use
|
||||
createMasterDummy(c, master)
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
defer deleteInterface(c, master)
|
||||
// create a network specifying the desired sub-interface name
|
||||
dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.60", "di-subinterface")
|
||||
assertNwIsAvailable(c, "di-subinterface")
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
deleteInterface(c, "di-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
|
||||
@@ -105,6 +105,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
|
||||
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
|
||||
master := "dm-dummy0"
|
||||
createMasterDummy(c, master)
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
defer deleteInterface(c, master)
|
||||
createVlanInterface(c, master, "dm-dummy0.40", "40")
|
||||
// create a network using an existing parent interface
|
||||
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.40", "dm-subinterface")
|
||||
@@ -113,8 +115,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.40", "dm-parent-net-overlap")
|
||||
// verify that the overlap returns an error
|
||||
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
deleteInterface(c, "dm-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
|
||||
@@ -123,6 +123,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
|
||||
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
|
||||
master := "di-dummy0"
|
||||
createMasterDummy(c, master)
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
defer deleteInterface(c, master)
|
||||
createVlanInterface(c, master, "di-dummy0.30", "30")
|
||||
// create a network using an existing parent interface
|
||||
dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.30", "di-subinterface")
|
||||
@@ -131,8 +133,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.30", "di-parent-net-overlap")
|
||||
// verify that the overlap returns an error
|
||||
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||
// cleanup the master interface which also collects the slave dev
|
||||
deleteInterface(c, "di-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
|
||||
@@ -471,6 +471,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
|
||||
netName := "dm-parent-exists"
|
||||
createMasterDummy(c, "dm-dummy0")
|
||||
defer deleteInterface(c, "dm-dummy0")
|
||||
//out, err := createVlanInterface(c, "dm-parent", "dm-slave", "macvlan", "bridge")
|
||||
// create a network using an existing parent interface
|
||||
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0", netName)
|
||||
@@ -480,7 +481,6 @@ func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
|
||||
assertNwNotAvailable(c, netName)
|
||||
// verify the network delete did not delete the predefined link
|
||||
linkExists(c, "dm-dummy0")
|
||||
deleteInterface(c, "dm-dummy0")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
|
||||
@@ -488,6 +488,8 @@ func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
|
||||
netName := "dm-subinterface"
|
||||
createMasterDummy(c, "dm-dummy0")
|
||||
// delete the parent interface which also collects the slave
|
||||
defer deleteInterface(c, "dm-dummy0")
|
||||
createVlanInterface(c, "dm-dummy0", "dm-dummy0.20", "20")
|
||||
// create a network using an existing parent interface
|
||||
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.20", netName)
|
||||
@@ -510,8 +512,6 @@ func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
|
||||
assertNwNotAvailable(c, netName)
|
||||
// verify the network delete did not delete the predefined sub-interface
|
||||
linkExists(c, "dm-dummy0.20")
|
||||
// delete the parent interface which also collects the slave
|
||||
deleteInterface(c, "dm-dummy0")
|
||||
}
|
||||
|
||||
func createMasterDummy(c *check.C, master string) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -327,3 +328,27 @@ func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigInspect(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 := t.Name()
|
||||
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
insp, body, err := client.ConfigInspectWithRaw(ctx, configID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, insp.Spec.Name, testName)
|
||||
|
||||
var config swarmtypes.Config
|
||||
err = json.Unmarshal(body, &config)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, config, insp)
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/gotestyourself/gotestyourself/skip"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
// the container process, then start dockerd back up and attempt to start the
|
||||
// container again.
|
||||
func TestContainerStartOnDaemonRestart(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
|
||||
t.Parallel()
|
||||
|
||||
d := daemon.New(t, "", "dockerd", daemon.Config{})
|
||||
@@ -36,22 +38,14 @@ func TestContainerStartOnDaemonRestart(t *testing.T) {
|
||||
assert.NoError(t, err, "error creating client")
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := client.ContainerCreate(ctx,
|
||||
&container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"top"},
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
"",
|
||||
)
|
||||
assert.NoError(t, err, "error creating test container")
|
||||
defer client.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
|
||||
cID := container.Create(t, ctx, client)
|
||||
defer client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
|
||||
assert.NoError(t, err, "error starting test container")
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, c.ID)
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NoError(t, err, "error getting inspect data")
|
||||
|
||||
ppid := getContainerdShimPid(t, inspect)
|
||||
@@ -67,7 +61,7 @@ func TestContainerStartOnDaemonRestart(t *testing.T) {
|
||||
|
||||
d.Start(t, "--iptables=false")
|
||||
|
||||
err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
|
||||
err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
|
||||
assert.NoError(t, err, "failed to start test container")
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@ import (
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
"github.com/gotestyourself/gotestyourself/skip"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// ensure that an added file shows up in docker diff
|
||||
func TestDiffFilenameShownInOutput(t *testing.T) {
|
||||
func TestDiff(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
@@ -27,72 +25,19 @@ func TestDiffFilenameShownInOutput(t *testing.T) {
|
||||
// it will take a few seconds to exit. Also there's no way in Windows to
|
||||
// differentiate between an Add or a Modify, and all files are under
|
||||
// a "Files/" prefix.
|
||||
lookingFor := containertypes.ContainerChangeResponseItem{Kind: archive.ChangeAdd, Path: "/foo/bar"}
|
||||
if testEnv.OSType == "windows" {
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(60*time.Second))
|
||||
lookingFor = containertypes.ContainerChangeResponseItem{Kind: archive.ChangeModify, Path: "Files/foo/bar"}
|
||||
expected := []containertypes.ContainerChangeResponseItem{
|
||||
{Kind: archive.ChangeAdd, Path: "/foo"},
|
||||
{Kind: archive.ChangeAdd, Path: "/foo/bar"},
|
||||
}
|
||||
|
||||
items, err := client.ContainerDiff(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, items, lookingFor)
|
||||
}
|
||||
|
||||
// test to ensure GH #3840 doesn't occur any more
|
||||
func TestDiffEnsureInitLayerFilesAreIgnored(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// this is a list of files which shouldn't show up in `docker diff`
|
||||
initLayerFiles := []string{"/etc/resolv.conf", "/etc/hostname", "/etc/hosts", "/.dockerenv"}
|
||||
containerCount := 5
|
||||
|
||||
// we might not run into this problem from the first run, so start a few containers
|
||||
for i := 0; i < containerCount; i++ {
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", `echo foo > /root/bar`))
|
||||
|
||||
items, err := client.ContainerDiff(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
for _, item := range items {
|
||||
assert.NotContains(t, initLayerFiles, item.Path)
|
||||
if testEnv.OSType == "windows" {
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(60*time.Second))
|
||||
expected = []containertypes.ContainerChangeResponseItem{
|
||||
{Kind: archive.ChangeModify, Path: "Files/foo"},
|
||||
{Kind: archive.ChangeModify, Path: "Files/foo/bar"},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffEnsureDefaultDevs(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sleep", "0"))
|
||||
|
||||
items, err := client.ContainerDiff(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := []containertypes.ContainerChangeResponseItem{
|
||||
{Kind: archive.ChangeModify, Path: "/dev"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/full"}, // busybox
|
||||
{Kind: archive.ChangeModify, Path: "/dev/ptmx"}, // libcontainer
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/mqueue"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/kmsg"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/fd"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/ptmx"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/null"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/random"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/stdout"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/stderr"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/tty1"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/stdin"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/tty"},
|
||||
{Kind: archive.ChangeAdd, Path: "/dev/urandom"},
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
assert.Contains(t, expected, item)
|
||||
}
|
||||
assert.Equal(t, expected, items)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
"github.com/gotestyourself/gotestyourself/skip"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// export an image and try to import it into a new one
|
||||
func TestExportContainerAndImportImage(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("true"))
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
reference := "repo/testexp:v1"
|
||||
exportResp, err := client.ContainerExport(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
importResp, err := client.ImageImport(ctx, types.ImageImportSource{
|
||||
Source: exportResp,
|
||||
SourceName: "-",
|
||||
}, reference, types.ImageImportOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the import is successfully, then the message output should contain
|
||||
// the image ID and match with the output from `docker images`.
|
||||
|
||||
dec := json.NewDecoder(importResp)
|
||||
var jm jsonmessage.JSONMessage
|
||||
err = dec.Decode(&jm)
|
||||
require.NoError(t, err)
|
||||
|
||||
images, err := client.ImageList(ctx, types.ImageListOptions{
|
||||
Filters: filters.NewArgs(filters.Arg("reference", reference)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, jm.Status, images[0].ID)
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func TestInspectCpusetInConfigPre120(t *testing.T) {
|
||||
c.HostConfig.Resources.CpusetCpus = "0"
|
||||
},
|
||||
)
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, name, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, name, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
_, body, err := client.ContainerInspectWithRaw(ctx, name, false)
|
||||
require.NoError(t, err)
|
||||
@@ -40,9 +40,9 @@ func TestInspectCpusetInConfigPre120(t *testing.T) {
|
||||
require.NoError(t, err, "unable to unmarshal body for version 1.19: %s", err)
|
||||
|
||||
config, ok := inspectJSON["Config"]
|
||||
assert.Equal(t, ok, true, "Unable to find 'Config'")
|
||||
assert.Equal(t, true, ok, "Unable to find 'Config'")
|
||||
|
||||
cfg := config.(map[string]interface{})
|
||||
_, ok = cfg["Cpuset"]
|
||||
assert.Equal(t, ok, true, "API version 1.19 expected to include Cpuset in 'Config'")
|
||||
assert.Equal(t, true, ok, "API version 1.19 expected to include Cpuset in 'Config'")
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ func TestKillContainerInvalidSignal(t *testing.T) {
|
||||
|
||||
err := client.ContainerKill(ctx, id, "0")
|
||||
require.EqualError(t, err, "Error response from daemon: Invalid signal: 0")
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err = client.ContainerKill(ctx, id, "SIG42")
|
||||
require.EqualError(t, err, "Error response from daemon: Invalid signal: SIG42")
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func TestKillContainer(t *testing.T) {
|
||||
@@ -64,7 +64,7 @@ func TestKillContainer(t *testing.T) {
|
||||
err := client.ContainerKill(ctx, id, tc.signal)
|
||||
require.NoError(t, err)
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ func TestKillWithStopSignalAndRestartPolicies(t *testing.T) {
|
||||
err := client.ContainerKill(ctx, id, "TERM")
|
||||
require.NoError(t, err)
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -141,11 +141,11 @@ func TestKillDifferentUserContainer(t *testing.T) {
|
||||
id := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.Config.User = "daemon"
|
||||
})
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerKill(ctx, id, "SIGKILL")
|
||||
require.NoError(t, err)
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, id, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func TestInspectOomKilledTrue(t *testing.T) {
|
||||
@@ -155,16 +155,15 @@ func TestInspectOomKilledTrue(t *testing.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) {
|
||||
cID := container.Run(t, ctx, client, 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))
|
||||
poll.WaitOn(t, container.IsInState(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)
|
||||
assert.Equal(t, true, inspect.State.OOMKilled)
|
||||
}
|
||||
|
||||
func TestInspectOomKilledFalse(t *testing.T) {
|
||||
@@ -174,12 +173,11 @@ func TestInspectOomKilledFalse(t *testing.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"))
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "echo hello world"))
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(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)
|
||||
assert.Equal(t, false, inspect.State.OOMKilled)
|
||||
}
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
"github.com/gotestyourself/gotestyourself/skip"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLinksEtcHostsContentMatch(t *testing.T) {
|
||||
skip.If(t, !testEnv.IsLocalDaemon())
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
hosts, err := ioutil.ReadFile("/etc/hosts")
|
||||
skip.If(t, os.IsNotExist(err))
|
||||
@@ -29,21 +25,13 @@ func TestLinksEtcHostsContentMatch(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("cat", "/etc/hosts"), container.WithNetworkMode("host"))
|
||||
|
||||
poll.WaitOn(t, containerIsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
body, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
})
|
||||
cID := container.Run(t, ctx, client, container.WithNetworkMode("host"))
|
||||
res, err := container.Exec(ctx, client, cID, []string{"cat", "/etc/hosts"})
|
||||
require.NoError(t, err)
|
||||
defer body.Close()
|
||||
require.Empty(t, res.Stderr())
|
||||
require.Equal(t, 0, res.ExitCode)
|
||||
|
||||
var b bytes.Buffer
|
||||
_, err = stdcopy.StdCopy(&b, ioutil.Discard, body)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, string(hosts), b.String())
|
||||
assert.Equal(t, string(hosts), res.Stdout())
|
||||
}
|
||||
|
||||
func TestLinksContainerNames(t *testing.T) {
|
||||
|
||||
@@ -20,7 +20,6 @@ func TestLogsFollowTailEmpty(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
id := container.Run(t, ctx, client, container.WithCmd("sleep", "100000"))
|
||||
defer client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
logs, err := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"})
|
||||
if logs != nil {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func TestContainerShmNoLeak(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
|
||||
t.Parallel()
|
||||
d := daemon.New(t, "docker", "dockerd", daemon.Config{})
|
||||
client, err := d.NewClient()
|
||||
@@ -94,7 +95,7 @@ func TestContainerShmNoLeak(t *testing.T) {
|
||||
|
||||
func TestContainerNetworkMountsNoChown(t *testing.T) {
|
||||
// chown only applies to Linux bind mounted volumes; must be same host to verify
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.IsLocalDaemon())
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNetworkNat(t *testing.T) {
|
||||
skip.If(t, !testEnv.IsLocalDaemon())
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
@@ -36,11 +36,11 @@ func TestNetworkNat(t *testing.T) {
|
||||
|
||||
data, err := ioutil.ReadAll(conn)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(string(data)), msg)
|
||||
assert.Equal(t, msg, strings.TrimSpace(string(data)))
|
||||
}
|
||||
|
||||
func TestNetworkLocalhostTCPNat(t *testing.T) {
|
||||
skip.If(t, !testEnv.IsLocalDaemon())
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
@@ -53,11 +53,11 @@ func TestNetworkLocalhostTCPNat(t *testing.T) {
|
||||
|
||||
data, err := ioutil.ReadAll(conn)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(string(data)), msg)
|
||||
assert.Equal(t, msg, strings.TrimSpace(string(data)))
|
||||
}
|
||||
|
||||
func TestNetworkLoopbackNat(t *testing.T) {
|
||||
skip.If(t, !testEnv.IsLocalDaemon())
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
msg := "it works"
|
||||
startServerContainer(t, msg, 8080)
|
||||
@@ -69,7 +69,7 @@ func TestNetworkLoopbackNat(t *testing.T) {
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", fmt.Sprintf("stty raw && nc -w 5 %s 8080", endpoint.String())), container.WithTty(true), container.WithNetworkMode("container:server"))
|
||||
|
||||
poll.WaitOn(t, containerIsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
body, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
@@ -81,7 +81,7 @@ func TestNetworkLoopbackNat(t *testing.T) {
|
||||
_, err = io.Copy(&b, body)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, strings.TrimSpace(b.String()), msg)
|
||||
assert.Equal(t, msg, strings.TrimSpace(b.String()))
|
||||
}
|
||||
|
||||
func startServerContainer(t *testing.T, msg string, port int) string {
|
||||
@@ -98,7 +98,7 @@ func startServerContainer(t *testing.T, msg string, port int) string {
|
||||
}
|
||||
})
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
return cID
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func getExternalAddress(t *testing.T) net.IP {
|
||||
|
||||
ifaceAddrs, err := iface.Addrs()
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, len(ifaceAddrs), 0)
|
||||
assert.NotEqual(t, 0, len(ifaceAddrs))
|
||||
|
||||
ifaceIP, _, err := net.ParseCIDR(ifaceAddrs[0].String())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -25,20 +25,19 @@ func TestPause(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
name := "testeventpause"
|
||||
cID := container.Run(t, ctx, client, container.WithName(name))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
cID := container.Run(t, ctx, client)
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
since := request.DaemonUnixTime(ctx, t, client, testEnv)
|
||||
|
||||
err := client.ContainerPause(ctx, name)
|
||||
err := client.ContainerPause(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.State.Paused, true)
|
||||
assert.Equal(t, true, inspect.State.Paused)
|
||||
|
||||
err = client.ContainerUnpause(ctx, name)
|
||||
err = client.ContainerUnpause(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
|
||||
until := request.DaemonUnixTime(ctx, t, client, testEnv)
|
||||
@@ -46,9 +45,9 @@ func TestPause(t *testing.T) {
|
||||
messages, errs := client.Events(ctx, types.EventsOptions{
|
||||
Since: since,
|
||||
Until: until,
|
||||
Filters: filters.NewArgs(filters.Arg("container", name)),
|
||||
Filters: filters.NewArgs(filters.Arg("container", cID)),
|
||||
})
|
||||
assert.Equal(t, getEventActions(t, messages, errs), []string{"pause", "unpause"})
|
||||
assert.Equal(t, []string{"pause", "unpause"}, getEventActions(t, messages, errs))
|
||||
}
|
||||
|
||||
func TestPauseFailsOnWindowsServerContainers(t *testing.T) {
|
||||
@@ -59,7 +58,7 @@ func TestPauseFailsOnWindowsServerContainers(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerPause(ctx, cID)
|
||||
testutil.ErrorContains(t, err, "cannot pause Windows Server Containers")
|
||||
@@ -73,7 +72,7 @@ func TestPauseStopPausedContainer(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerPause(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
@@ -81,7 +80,7 @@ func TestPauseStopPausedContainer(t *testing.T) {
|
||||
err = client.ContainerStop(ctx, cID, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
poll.WaitOn(t, containerIsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan error) []string {
|
||||
@@ -89,7 +88,7 @@ func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan e
|
||||
for {
|
||||
select {
|
||||
case err := <-errs:
|
||||
assert.Equal(t, err == nil || err == io.EOF, true)
|
||||
assert.True(t, err == nil || err == io.EOF)
|
||||
return actions
|
||||
case e := <-messages:
|
||||
actions = append(actions, e.Status)
|
||||
|
||||
@@ -5,9 +5,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -18,23 +17,9 @@ func TestPsFilter(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
createContainerForFilter := func(ctx context.Context, name string) string {
|
||||
body, err := client.ContainerCreate(ctx,
|
||||
&container.Config{
|
||||
Cmd: []string{"top"},
|
||||
Image: "busybox",
|
||||
},
|
||||
&container.HostConfig{},
|
||||
&network.NetworkingConfig{},
|
||||
name,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
return body.ID
|
||||
}
|
||||
|
||||
prev := createContainerForFilter(ctx, "prev")
|
||||
createContainerForFilter(ctx, "top")
|
||||
next := createContainerForFilter(ctx, "next")
|
||||
prev := container.Create(t, ctx, client, container.WithName("prev"))
|
||||
container.Create(t, ctx, client, container.WithName("top"))
|
||||
next := container.Create(t, ctx, client, container.WithName("next"))
|
||||
|
||||
containerIDs := func(containers []types.Container) []string {
|
||||
entries := []string{}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/docker/docker/internal/testutil"
|
||||
"github.com/gotestyourself/gotestyourself/fs"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
"github.com/gotestyourself/gotestyourself/skip"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
||||
if testEnv.OSType == "windows" {
|
||||
return "c:", `\`
|
||||
}
|
||||
return "", "/"
|
||||
}
|
||||
|
||||
// Test case for #5244: `docker rm` fails if bind dir doesn't exist anymore
|
||||
func TestRemoveContainerWithRemovedVolume(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
tempDir := fs.NewDir(t, "test-rm-container-with-removed-volume", fs.WithMode(0755))
|
||||
defer tempDir.Remove()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("true"), container.WithBind(tempDir.Path(), prefix+slash+"test"))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := os.RemoveAll(tempDir.Path())
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
|
||||
RemoveVolumes: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = client.ContainerInspectWithRaw(ctx, cID, true)
|
||||
testutil.ErrorContains(t, err, "No such container")
|
||||
}
|
||||
|
||||
// Test case for #2099/#2125
|
||||
func TestRemoveContainerWithVolume(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("true"), container.WithVolume(prefix+slash+"srv"))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
insp, _, err := client.ContainerInspectWithRaw(ctx, cID, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(insp.Mounts))
|
||||
volName := insp.Mounts[0].Name
|
||||
|
||||
err = client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
|
||||
RemoveVolumes: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
volumes, err := client.VolumeList(ctx, filters.NewArgs(filters.Arg("name", volName)))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(volumes.Volumes))
|
||||
}
|
||||
|
||||
func TestRemoveContainerRunning(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
err := client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{})
|
||||
testutil.ErrorContains(t, err, "cannot remove a running container")
|
||||
}
|
||||
|
||||
func TestRemoveContainerForceRemoveRunning(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
err := client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRemoveInvalidContainer(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
err := client.ContainerRemove(ctx, "unknown", types.ContainerRemoveOptions{})
|
||||
testutil.ErrorContains(t, err, "No such container")
|
||||
}
|
||||
@@ -51,11 +51,11 @@ func TestRenameStoppedContainer(t *testing.T) {
|
||||
|
||||
oldName := "first_name"
|
||||
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))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.Name, "/"+oldName)
|
||||
assert.Equal(t, "/"+oldName, inspect.Name)
|
||||
|
||||
newName := "new_name" + stringid.GenerateNonCryptoID()
|
||||
err = client.ContainerRename(ctx, oldName, newName)
|
||||
@@ -63,7 +63,7 @@ func TestRenameStoppedContainer(t *testing.T) {
|
||||
|
||||
inspect, err = client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.Name, "/"+newName)
|
||||
assert.Equal(t, "/"+newName, inspect.Name)
|
||||
}
|
||||
|
||||
func TestRenameRunningContainerAndReuse(t *testing.T) {
|
||||
@@ -73,7 +73,7 @@ func TestRenameRunningContainerAndReuse(t *testing.T) {
|
||||
|
||||
oldName := "first_name"
|
||||
cID := container.Run(t, ctx, client, container.WithName(oldName))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
newName := "new_name" + stringid.GenerateNonCryptoID()
|
||||
err := client.ContainerRename(ctx, oldName, newName)
|
||||
@@ -81,17 +81,17 @@ func TestRenameRunningContainerAndReuse(t *testing.T) {
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.Name, "/"+newName)
|
||||
assert.Equal(t, "/"+newName, inspect.Name)
|
||||
|
||||
_, err = client.ContainerInspect(ctx, oldName)
|
||||
testutil.ErrorContains(t, err, "No such container: "+oldName)
|
||||
|
||||
cID = container.Run(t, ctx, client, container.WithName(oldName))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err = client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.Name, "/"+oldName)
|
||||
assert.Equal(t, "/"+oldName, inspect.Name)
|
||||
}
|
||||
|
||||
func TestRenameInvalidName(t *testing.T) {
|
||||
@@ -101,14 +101,14 @@ func TestRenameInvalidName(t *testing.T) {
|
||||
|
||||
oldName := "first_name"
|
||||
cID := container.Run(t, ctx, client, container.WithName(oldName))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerRename(ctx, oldName, "new:invalid")
|
||||
testutil.ErrorContains(t, err, "Invalid container name")
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, oldName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.ID, cID)
|
||||
assert.Equal(t, cID, inspect.ID)
|
||||
}
|
||||
|
||||
// Test case for GitHub issue 22466
|
||||
@@ -133,10 +133,14 @@ func TestRenameAnonymousContainer(t *testing.T) {
|
||||
})
|
||||
err = client.ContainerRename(ctx, cID, "container1")
|
||||
require.NoError(t, err)
|
||||
// Stop/Start the container to get registered
|
||||
// FIXME(vdemeester) this is a really weird behavior as it fails otherwise
|
||||
err = client.ContainerStop(ctx, "container1", nil)
|
||||
require.NoError(t, err)
|
||||
err = client.ContainerStart(ctx, "container1", types.ContainerStartOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
count := "-c"
|
||||
if testEnv.OSType == "windows" {
|
||||
@@ -148,11 +152,11 @@ func TestRenameAnonymousContainer(t *testing.T) {
|
||||
}
|
||||
c.HostConfig.NetworkMode = "network1"
|
||||
}, container.WithCmd("ping", count, "1", "container1"))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.State.ExitCode, 0)
|
||||
assert.Equal(t, 0, inspect.State.ExitCode, "container %s exited with the wrong exitcode: %+v", cID, inspect)
|
||||
}
|
||||
|
||||
// TODO: should be a unit test
|
||||
@@ -162,7 +166,7 @@ func TestRenameContainerWithSameName(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithName("old"))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(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")
|
||||
err = client.ContainerRename(ctx, cID, "old")
|
||||
@@ -175,22 +179,22 @@ func TestRenameContainerWithSameName(t *testing.T) {
|
||||
// of the linked container should be updated so that the other
|
||||
// container could still reference to the container that is renamed.
|
||||
func TestRenameContainerWithLinkedContainer(t *testing.T) {
|
||||
skip.If(t, !testEnv.IsLocalDaemon())
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
db1ID := container.Run(t, ctx, client, container.WithName("db1"))
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, db1ID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, db1ID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
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))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, app1ID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerRename(ctx, "app1", "app2")
|
||||
require.NoError(t, err)
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, "app2/mysql")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, inspect.ID, db1ID)
|
||||
assert.Equal(t, db1ID, inspect.ID)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestResize(t *testing.T) {
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerResize(ctx, cID, types.ResizeOptions{
|
||||
Height: 40,
|
||||
@@ -39,12 +39,12 @@ func TestResizeWithInvalidSize(t *testing.T) {
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
endpoint := "/containers/" + cID + "/resize?h=foo&w=bar"
|
||||
res, _, err := req.Post(endpoint)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, res.StatusCode, http.StatusBadRequest)
|
||||
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestResizeWhenContainerNotStarted(t *testing.T) {
|
||||
@@ -54,7 +54,7 @@ func TestResizeWhenContainerNotStarted(t *testing.T) {
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("echo"))
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerResize(ctx, cID, types.ResizeOptions{
|
||||
Height: 40,
|
||||
|
||||
@@ -9,9 +9,11 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/gotestyourself/gotestyourself/skip"
|
||||
)
|
||||
|
||||
func TestDaemonRestartKillContainers(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
|
||||
type testCase struct {
|
||||
desc string
|
||||
config *container.Config
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestStats(t *testing.T) {
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
resp, err := client.ContainerStats(ctx, cID, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/gotestyourself/gotestyourself/icmd"
|
||||
@@ -30,7 +29,7 @@ func TestStopContainerWithRestartPolicyAlways(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, name, "running", "restarting"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, name, "running", "restarting"), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
@@ -39,7 +38,7 @@ func TestStopContainerWithRestartPolicyAlways(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
poll.WaitOn(t, containerIsStopped(ctx, client, name), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, name), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +51,7 @@ func TestDeleteDevicemapper(t *testing.T) {
|
||||
|
||||
id := container.Run(t, ctx, client, container.WithName("foo"), container.WithCmd("echo"))
|
||||
|
||||
poll.WaitOn(t, containerIsStopped(ctx, client, id), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, id), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, id)
|
||||
require.NoError(t, err)
|
||||
@@ -70,33 +69,3 @@ func TestDeleteDevicemapper(t *testing.T) {
|
||||
err = client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func containerIsStopped(ctx context.Context, client client.APIClient, containerID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case !inspect.State.Running:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("waiting for container to be stopped")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func containerIsInState(ctx context.Context, client client.APIClient, containerID string, state ...string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
return poll.Error(err)
|
||||
}
|
||||
for _, v := range state {
|
||||
if inspect.State.Status == v {
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
return poll.Continue("waiting for container to be running, currently %s", inspect.State.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestUpdateMemory(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
const (
|
||||
setMemory int64 = 314572800
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestUpdateRestartPolicy(t *testing.T) {
|
||||
timeout = 180 * time.Second
|
||||
}
|
||||
|
||||
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(timeout))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(timeout))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -16,10 +16,9 @@ func TestCommitInheritsEnv(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
createResp1, err := client.ContainerCreate(ctx, &container.Config{Image: "busybox"}, nil, nil, "")
|
||||
require.NoError(t, err)
|
||||
cID1 := container.Create(t, ctx, client)
|
||||
|
||||
commitResp1, err := client.ContainerCommit(ctx, createResp1.ID, types.ContainerCommitOptions{
|
||||
commitResp1, err := client.ContainerCommit(ctx, cID1, types.ContainerCommitOptions{
|
||||
Changes: []string{"ENV PATH=/bin"},
|
||||
Reference: "test-commit-image",
|
||||
})
|
||||
@@ -31,10 +30,9 @@ func TestCommitInheritsEnv(t *testing.T) {
|
||||
expectedEnv1 := []string{"PATH=/bin"}
|
||||
assert.Equal(t, expectedEnv1, image1.Config.Env)
|
||||
|
||||
createResp2, err := client.ContainerCreate(ctx, &container.Config{Image: image1.ID}, nil, nil, "")
|
||||
require.NoError(t, err)
|
||||
cID2 := container.Create(t, ctx, client, container.WithImage(image1.ID))
|
||||
|
||||
commitResp2, err := client.ContainerCommit(ctx, createResp2.ID, types.ContainerCommitOptions{
|
||||
commitResp2, err := client.ContainerCommit(ctx, cID2, types.ContainerCommitOptions{
|
||||
Changes: []string{"ENV PATH=/usr/bin:$PATH"},
|
||||
Reference: "test-commit-image",
|
||||
})
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package image // import "github.com/docker/docker/integration/image"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/docker/docker/internal/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRemoveImageOrphaning(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
img := "test-container-orphaning"
|
||||
|
||||
// Create a container from busybox, and commit a small change so we have a new image
|
||||
cID1 := container.Create(t, ctx, client, container.WithCmd(""))
|
||||
commitResp1, err := client.ContainerCommit(ctx, cID1, types.ContainerCommitOptions{
|
||||
Changes: []string{`ENTRYPOINT ["true"]`},
|
||||
Reference: img,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// verifies that reference now points to first image
|
||||
resp, _, err := client.ImageInspectWithRaw(ctx, img)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, resp.ID, commitResp1.ID)
|
||||
|
||||
// Create a container from created image, and commit a small change with same reference name
|
||||
cID2 := container.Create(t, ctx, client, container.WithImage(img), container.WithCmd(""))
|
||||
commitResp2, err := client.ContainerCommit(ctx, cID2, types.ContainerCommitOptions{
|
||||
Changes: []string{`LABEL Maintainer="Integration Tests"`},
|
||||
Reference: img,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// verifies that reference now points to second image
|
||||
resp, _, err = client.ImageInspectWithRaw(ctx, img)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, resp.ID, commitResp2.ID)
|
||||
|
||||
// try to remove the image, should not error out.
|
||||
_, err = client.ImageRemove(ctx, img, types.ImageRemoveOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// check if the first image is still there
|
||||
resp, _, err = client.ImageInspectWithRaw(ctx, commitResp1.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, resp.ID, commitResp1.ID)
|
||||
|
||||
// check if the second image has been deleted
|
||||
_, _, err = client.ImageInspectWithRaw(ctx, commitResp2.ID)
|
||||
testutil.ErrorContains(t, err, "No such image:")
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
@@ -20,6 +22,13 @@ func WithLinks(links ...string) func(*TestContainerConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// WithImage sets the image of the container
|
||||
func WithImage(image string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Config.Image = image
|
||||
}
|
||||
}
|
||||
|
||||
// WithCmd sets the comannds of the container
|
||||
func WithCmd(cmds ...string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
@@ -57,3 +66,20 @@ func WithWorkingDir(dir string) func(*TestContainerConfig) {
|
||||
c.Config.WorkingDir = dir
|
||||
}
|
||||
}
|
||||
|
||||
// WithVolume sets the volume of the container
|
||||
func WithVolume(name string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.Config.Volumes == nil {
|
||||
c.Config.Volumes = map[string]struct{}{}
|
||||
}
|
||||
c.Config.Volumes[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// WithBind sets the bind mount of the container
|
||||
func WithBind(src, target string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.HostConfig.Binds = append(c.HostConfig.Binds, fmt.Sprintf("%s:%s", src, target))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/gotestyourself/gotestyourself/poll"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// IsStopped verifies the container is in stopped state.
|
||||
func IsStopped(ctx context.Context, client client.APIClient, containerID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case !inspect.State.Running:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("waiting for container to be stopped")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsInState verifies the container is in one of the specified state, e.g., "running", "exited", etc.
|
||||
func IsInState(ctx context.Context, client client.APIClient, containerID string, state ...string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
return poll.Error(err)
|
||||
}
|
||||
for _, v := range state {
|
||||
if inspect.State.Status == v {
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
return poll.Continue("waiting for container to be one of (%s), currently %s", strings.Join(state, ", "), inspect.State.Status)
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,8 @@ func NewAPIClient(t *testing.T, ops ...func(*client.Client) error) client.APICli
|
||||
return clt
|
||||
}
|
||||
|
||||
// daemonTime provides the current time on the daemon host
|
||||
func daemonTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time {
|
||||
// DaemonTime provides the current time on the daemon host
|
||||
func DaemonTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time {
|
||||
if testEnv.IsLocalDaemon() {
|
||||
return time.Now()
|
||||
}
|
||||
@@ -37,6 +37,6 @@ func daemonTime(ctx context.Context, t *testing.T, client client.APIClient, test
|
||||
// DaemonUnixTime returns the current time on the daemon host with nanoseconds precision.
|
||||
// It return the time formatted how the client sends timestamps to the server.
|
||||
func DaemonUnixTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) string {
|
||||
dt := daemonTime(ctx, t, client, testEnv)
|
||||
dt := DaemonTime(ctx, t, client, testEnv)
|
||||
return fmt.Sprintf("%d.%09d", dt.Unix(), int64(dt.Nanosecond()))
|
||||
}
|
||||
|
||||
@@ -129,32 +129,7 @@ func createSecret(ctx context.Context, t *testing.T, client client.APIClient, na
|
||||
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) {
|
||||
func TestSecretsCreateAndDelete(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
@@ -167,12 +142,17 @@ func TestSecretsDelete(t *testing.T) {
|
||||
|
||||
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)
|
||||
// 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")
|
||||
|
||||
// Ported from original TestSecretsDelete
|
||||
err = client.SecretRemove(ctx, secretID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -181,6 +161,20 @@ func TestSecretsDelete(t *testing.T) {
|
||||
|
||||
err = client.SecretRemove(ctx, "non-existin")
|
||||
testutil.ErrorContains(t, err, "No such secret: non-existin")
|
||||
|
||||
// Ported from original TestSecretsCreteaWithLabels
|
||||
testName = "test_secret_with_labels"
|
||||
secretID = createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), map[string]string{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
})
|
||||
|
||||
insp, _, err := client.SecretInspectWithRaw(ctx, secretID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, insp.Spec.Name, testName)
|
||||
assert.Equal(t, len(insp.Spec.Labels), 2)
|
||||
assert.Equal(t, insp.Spec.Labels["key1"], "value1")
|
||||
assert.Equal(t, insp.Spec.Labels["key2"], "value2")
|
||||
}
|
||||
|
||||
func TestSecretsUpdate(t *testing.T) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func TestInspect(t *testing.T) {
|
||||
skip.IfCondition(t, !testEnv.IsLocalDaemon())
|
||||
skip.IfCondition(t, testEnv.IsRemoteDaemon())
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
|
||||
@@ -2,15 +2,22 @@ package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
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/pkg/jsonmessage"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -58,3 +65,55 @@ func TestEvents(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test case for #18888: Events messages have been switched from generic
|
||||
// `JSONMessage` to `events.Message` types. The switch does not break the
|
||||
// backward compatibility so old `JSONMessage` could still be used.
|
||||
// This test verifies that backward compatibility maintains.
|
||||
func TestEventsBackwardsCompatible(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
since := request.DaemonTime(ctx, t, client, testEnv)
|
||||
ts := strconv.FormatInt(since.Unix(), 10)
|
||||
|
||||
cID := container.Create(t, ctx, client)
|
||||
|
||||
// In case there is no events, the API should have responded immediately (not blocking),
|
||||
// The test here makes sure the response time is less than 3 sec.
|
||||
expectedTime := time.Now().Add(3 * time.Second)
|
||||
emptyResp, emptyBody, err := req.Get("/events")
|
||||
require.NoError(t, err)
|
||||
defer emptyBody.Close()
|
||||
assert.Equal(t, http.StatusOK, emptyResp.StatusCode)
|
||||
assert.True(t, time.Now().Before(expectedTime), "timeout waiting for events api to respond, should have responded immediately")
|
||||
|
||||
// We also test to make sure the `events.Message` is compatible with `JSONMessage`
|
||||
q := url.Values{}
|
||||
q.Set("since", ts)
|
||||
_, body, err := req.Get("/events?" + q.Encode())
|
||||
require.NoError(t, err)
|
||||
defer body.Close()
|
||||
|
||||
dec := json.NewDecoder(body)
|
||||
var containerCreateEvent *jsonmessage.JSONMessage
|
||||
for {
|
||||
var event jsonmessage.JSONMessage
|
||||
if err := dec.Decode(&event); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
if event.Status == "create" && event.ID == cID {
|
||||
containerCreateEvent = &event
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.NotNil(t, containerCreateEvent)
|
||||
assert.Equal(t, "create", containerCreateEvent.Status)
|
||||
assert.Equal(t, cID, containerCreateEvent.ID)
|
||||
assert.Equal(t, "busybox", containerCreateEvent.From)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package volume // import "github.com/docker/docker/integration/volume"
|
||||
|
||||
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) }
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package volume
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/request"
|
||||
"github.com/docker/docker/internal/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestVolumesCreateAndList(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
name := t.Name()
|
||||
vol, err := client.VolumeCreate(ctx, volumetypes.VolumesCreateBody{
|
||||
Name: name,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := types.Volume{
|
||||
// Ignore timestamp of CreatedAt
|
||||
CreatedAt: vol.CreatedAt,
|
||||
Driver: "local",
|
||||
Scope: "local",
|
||||
Name: name,
|
||||
Mountpoint: fmt.Sprintf("%s/volumes/%s/_data", testEnv.DaemonInfo.DockerRootDir, name),
|
||||
}
|
||||
assert.Equal(t, vol, expected)
|
||||
|
||||
volumes, err := client.VolumeList(ctx, filters.Args{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, len(volumes.Volumes), 1)
|
||||
assert.NotNil(t, volumes.Volumes[0])
|
||||
assert.Equal(t, *volumes.Volumes[0], expected)
|
||||
}
|
||||
|
||||
func TestVolumesRemove(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
prefix, _ := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
id := container.Create(t, ctx, client, container.WithVolume(prefix+"foo"))
|
||||
|
||||
c, err := client.ContainerInspect(ctx, id)
|
||||
require.NoError(t, err)
|
||||
vname := c.Mounts[0].Name
|
||||
|
||||
err = client.VolumeRemove(ctx, vname, false)
|
||||
testutil.ErrorContains(t, err, "volume is in use")
|
||||
|
||||
err = client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.VolumeRemove(ctx, vname, false)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestVolumesInspect(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// sampling current time minus a minute so to now have false positive in case of delays
|
||||
now := time.Now().Truncate(time.Minute)
|
||||
|
||||
name := t.Name()
|
||||
_, err := client.VolumeCreate(ctx, volumetypes.VolumesCreateBody{
|
||||
Name: name,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
vol, err := client.VolumeInspect(ctx, name)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := types.Volume{
|
||||
// Ignore timestamp of CreatedAt
|
||||
CreatedAt: vol.CreatedAt,
|
||||
Driver: "local",
|
||||
Scope: "local",
|
||||
Name: name,
|
||||
Mountpoint: fmt.Sprintf("%s/volumes/%s/_data", testEnv.DaemonInfo.DockerRootDir, name),
|
||||
}
|
||||
assert.Equal(t, vol, expected)
|
||||
|
||||
// comparing CreatedAt field time for the new volume to now. Removing a minute from both to avoid false positive
|
||||
testCreatedAt, err := time.Parse(time.RFC3339, strings.TrimSpace(vol.CreatedAt))
|
||||
require.NoError(t, err)
|
||||
testCreatedAt = testCreatedAt.Truncate(time.Minute)
|
||||
assert.Equal(t, testCreatedAt.Equal(now), true, "Time Volume is CreatedAt not equal to current time")
|
||||
}
|
||||
|
||||
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
||||
if testEnv.OSType == "windows" {
|
||||
return "c:", `\`
|
||||
}
|
||||
return "", "/"
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func toSlash(path string) string {
|
||||
}
|
||||
|
||||
// IsLocalDaemon is true if the daemon under test is on the same
|
||||
// host as the CLI.
|
||||
// host as the test process.
|
||||
//
|
||||
// Deterministically working out the environment in which CI is running
|
||||
// to evaluate whether the daemon is local or remote is not possible through
|
||||
@@ -115,6 +115,12 @@ func (e *Execution) IsLocalDaemon() bool {
|
||||
return os.Getenv("DOCKER_REMOTE_DAEMON") == ""
|
||||
}
|
||||
|
||||
// IsRemoteDaemon is true if the daemon under test is on different host
|
||||
// as the test process.
|
||||
func (e *Execution) IsRemoteDaemon() bool {
|
||||
return !e.IsLocalDaemon()
|
||||
}
|
||||
|
||||
// Print the execution details to stdout
|
||||
// TODO: print everything
|
||||
func (e *Execution) Print() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package plugins // import "github.com/docker/docker/pkg/plugins"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -13,7 +14,9 @@ import (
|
||||
|
||||
"github.com/docker/docker/pkg/plugins/transport"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -232,3 +235,43 @@ func TestClientSendFile(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, m, output)
|
||||
}
|
||||
|
||||
func TestClientWithRequestTimeout(t *testing.T) {
|
||||
timeout := 1 * time.Millisecond
|
||||
testHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(timeout + 1*time.Millisecond)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(testHandler))
|
||||
defer srv.Close()
|
||||
|
||||
client := &Client{http: srv.Client(), requestFactory: &testRequestWrapper{srv}}
|
||||
_, err := client.callWithRetry("/Plugin.Hello", nil, false, WithRequestTimeout(timeout))
|
||||
require.Error(t, err, "expected error")
|
||||
|
||||
err = errors.Cause(err)
|
||||
|
||||
switch e := err.(type) {
|
||||
case *url.Error:
|
||||
err = e.Err
|
||||
}
|
||||
require.Equal(t, context.DeadlineExceeded, err)
|
||||
}
|
||||
|
||||
type testRequestWrapper struct {
|
||||
*httptest.Server
|
||||
}
|
||||
|
||||
func (w *testRequestWrapper) NewRequest(path string, data io.Reader) (*http.Request, error) {
|
||||
req, err := http.NewRequest("POST", path, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := url.Parse(w.Server.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.URL = u
|
||||
return req, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -28,7 +29,10 @@ func setMeta(tx *bolt.Tx, name string, meta volumeMetadata) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := tx.Bucket(volumeBucketName)
|
||||
b, err := tx.CreateBucketIfNotExists(volumeBucketName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error creating volume bucket")
|
||||
}
|
||||
return errors.Wrap(b.Put([]byte(name), metaJSON), "error setting volume metadata")
|
||||
}
|
||||
|
||||
@@ -42,8 +46,11 @@ func (s *VolumeStore) getMeta(name string) (volumeMetadata, error) {
|
||||
|
||||
func getMeta(tx *bolt.Tx, name string, meta *volumeMetadata) error {
|
||||
b := tx.Bucket(volumeBucketName)
|
||||
if b == nil {
|
||||
return errdefs.NotFound(errors.New("volume bucket does not exist"))
|
||||
}
|
||||
val := b.Get([]byte(name))
|
||||
if string(val) == "" {
|
||||
if len(val) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(val, meta); err != nil {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSetGetMeta(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir, err := ioutil.TempDir("", "test-set-get")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
db, err := bolt.Open(filepath.Join(dir, "db"), 0600, &bolt.Options{Timeout: 1 * time.Second})
|
||||
require.NoError(t, err)
|
||||
|
||||
store := &VolumeStore{db: db}
|
||||
|
||||
_, err = store.getMeta("test")
|
||||
require.Error(t, err)
|
||||
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucket(volumeBucketName)
|
||||
return err
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
meta, err := store.getMeta("test")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, volumeMetadata{}, meta)
|
||||
|
||||
testMeta := volumeMetadata{
|
||||
Name: "test",
|
||||
Driver: "fake",
|
||||
Labels: map[string]string{"a": "1", "b": "2"},
|
||||
Options: map[string]string{"foo": "bar"},
|
||||
}
|
||||
err = store.setMeta("test", testMeta)
|
||||
require.NoError(t, err)
|
||||
|
||||
meta, err = store.getMeta("test")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, testMeta, meta)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/volume"
|
||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
volumetestutils "github.com/docker/docker/volume/testutils"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRestore(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir, err := ioutil.TempDir("", "test-restore")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
driverName := "test-restore"
|
||||
volumedrivers.Register(volumetestutils.NewFakeDriver(driverName), driverName)
|
||||
defer volumedrivers.Unregister("test-restore")
|
||||
|
||||
s, err := New(dir)
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown()
|
||||
|
||||
_, err = s.Create("test1", driverName, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
testLabels := map[string]string{"a": "1"}
|
||||
testOpts := map[string]string{"foo": "bar"}
|
||||
_, err = s.Create("test2", driverName, testOpts, testLabels)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.Shutdown()
|
||||
|
||||
s, err = New(dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
v, err := s.Get("test1")
|
||||
require.NoError(t, err)
|
||||
|
||||
dv := v.(volume.DetailedVolume)
|
||||
var nilMap map[string]string
|
||||
require.Equal(t, nilMap, dv.Options())
|
||||
require.Equal(t, nilMap, dv.Labels())
|
||||
|
||||
v, err = s.Get("test2")
|
||||
require.NoError(t, err)
|
||||
dv = v.(volume.DetailedVolume)
|
||||
require.Equal(t, testOpts, dv.Options())
|
||||
require.Equal(t, testLabels, dv.Labels())
|
||||
}
|
||||
@@ -29,7 +29,10 @@ type volumeWrapper struct {
|
||||
}
|
||||
|
||||
func (v volumeWrapper) Options() map[string]string {
|
||||
options := map[string]string{}
|
||||
if v.options == nil {
|
||||
return nil
|
||||
}
|
||||
options := make(map[string]string, len(v.options))
|
||||
for key, value := range v.options {
|
||||
options[key] = value
|
||||
}
|
||||
@@ -37,7 +40,15 @@ func (v volumeWrapper) Options() map[string]string {
|
||||
}
|
||||
|
||||
func (v volumeWrapper) Labels() map[string]string {
|
||||
return v.labels
|
||||
if v.labels == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
labels := make(map[string]string, len(v.labels))
|
||||
for key, value := range v.labels {
|
||||
labels[key] = value
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
func (v volumeWrapper) Scope() string {
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/docker/volume/drivers"
|
||||
volumetestutils "github.com/docker/docker/volume/testutils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
@@ -291,6 +293,7 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
|
||||
|
||||
pg := volumetestutils.NewFakePluginGetter(p)
|
||||
volumedrivers.RegisterPluginGetter(pg)
|
||||
defer volumedrivers.RegisterPluginGetter(nil)
|
||||
|
||||
dir, err := ioutil.TempDir("", "test-plugin-deref-err")
|
||||
if err != nil {
|
||||
@@ -320,3 +323,103 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
|
||||
t.Fatalf("expected 1 plugin reference, got: %d", refs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefDerefRemove(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
driverName := "test-ref-deref-remove"
|
||||
s, cleanup := setupTest(t, driverName)
|
||||
defer cleanup(t)
|
||||
|
||||
v, err := s.CreateWithRef("test", driverName, "test-ref", nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Remove(v)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, errVolumeInUse, err.(*OpErr).Err)
|
||||
|
||||
s.Dereference(v, "test-ref")
|
||||
err = s.Remove(v)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
driverName := "test-get"
|
||||
s, cleanup := setupTest(t, driverName)
|
||||
defer cleanup(t)
|
||||
|
||||
_, err := s.Get("not-exist")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, errNoSuchVolume, err.(*OpErr).Err)
|
||||
|
||||
v1, err := s.Create("test", driverName, nil, map[string]string{"a": "1"})
|
||||
require.NoError(t, err)
|
||||
|
||||
v2, err := s.Get("test")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, v1, v2)
|
||||
|
||||
dv := v2.(volume.DetailedVolume)
|
||||
require.Equal(t, "1", dv.Labels()["a"])
|
||||
|
||||
err = s.Remove(v1)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGetWithRef(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
driverName := "test-get-with-ref"
|
||||
s, cleanup := setupTest(t, driverName)
|
||||
defer cleanup(t)
|
||||
|
||||
_, err := s.GetWithRef("not-exist", driverName, "test-ref")
|
||||
require.Error(t, err)
|
||||
|
||||
v1, err := s.Create("test", driverName, nil, map[string]string{"a": "1"})
|
||||
require.NoError(t, err)
|
||||
|
||||
v2, err := s.GetWithRef("test", driverName, "test-ref")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, v1, v2)
|
||||
|
||||
err = s.Remove(v2)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, errVolumeInUse, err.(*OpErr).Err)
|
||||
|
||||
s.Dereference(v2, "test-ref")
|
||||
err = s.Remove(v2)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T, name string) (*VolumeStore, func(*testing.T)) {
|
||||
t.Helper()
|
||||
s, cleanup := newTestStore(t)
|
||||
|
||||
volumedrivers.Register(volumetestutils.NewFakeDriver(name), name)
|
||||
return s, func(t *testing.T) {
|
||||
cleanup(t)
|
||||
volumedrivers.Unregister(name)
|
||||
}
|
||||
}
|
||||
|
||||
func newTestStore(t *testing.T) (*VolumeStore, func(*testing.T)) {
|
||||
t.Helper()
|
||||
|
||||
dir, err := ioutil.TempDir("", "store-root")
|
||||
require.NoError(t, err)
|
||||
|
||||
cleanup := func(t *testing.T) {
|
||||
err := os.RemoveAll(dir)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
s, err := New(dir)
|
||||
assert.NoError(t, err)
|
||||
return s, func(t *testing.T) {
|
||||
s.Shutdown()
|
||||
cleanup(t)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user