From e5ec575b32d6979914dce576f1b8bb71f3057cea Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Wed, 29 Jun 2016 14:00:11 -0400 Subject: [PATCH] Implement service integration tests This is done in a hacky way as currently there is no better way. Uses known implementation details about how tasks are scheduled to be able to operate on the underlying container. Signed-off-by: Brian Goff --- integration-cli/check_test.go | 14 ++++-- integration-cli/daemon_swarm.go | 27 +++++++++++ integration-cli/daemon_swarm_hack.go | 20 +++++++++ .../docker_cli_service_create_hack_test.go | 45 +++++++++++++++++++ 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 integration-cli/daemon_swarm_hack.go create mode 100644 integration-cli/docker_cli_service_create_hack_test.go diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go index d14bdb5244..06f599407d 100644 --- a/integration-cli/check_test.go +++ b/integration-cli/check_test.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "sync" "testing" "github.com/docker/docker/cliconfig" @@ -194,9 +195,10 @@ func init() { } type DockerSwarmSuite struct { - ds *DockerSuite - daemons []*SwarmDaemon - portIndex int + ds *DockerSuite + daemons []*SwarmDaemon + daemonsLock sync.Mutex // protect access to daemons + portIndex int } func (s *DockerSwarmSuite) SetUpTest(c *check.C) { @@ -227,19 +229,23 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *Swarm } s.portIndex++ + s.daemonsLock.Lock() s.daemons = append(s.daemons, d) + s.daemonsLock.Unlock() return d } func (s *DockerSwarmSuite) TearDownTest(c *check.C) { testRequires(c, DaemonIsLinux) + s.daemonsLock.Lock() for _, d := range s.daemons { d.Stop() } s.daemons = nil - s.portIndex = 0 + s.daemonsLock.Unlock() + s.portIndex = 0 s.ds.TearDownTest(c) } diff --git a/integration-cli/daemon_swarm.go b/integration-cli/daemon_swarm.go index 47ca4422e8..3212bc06ed 100644 --- a/integration-cli/daemon_swarm.go +++ b/integration-cli/daemon_swarm.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/pkg/integration/checker" "github.com/docker/engine-api/types" + "github.com/docker/engine-api/types/filters" "github.com/docker/engine-api/types/swarm" "github.com/go-check/check" ) @@ -131,6 +132,32 @@ func (d *SwarmDaemon) getService(c *check.C, id string) *swarm.Service { return &service } +func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task { + var tasks []swarm.Task + + filterArgs := filters.NewArgs() + filterArgs.Add("desired-state", "running") + filterArgs.Add("service", service) + filters, err := filters.ToParam(filterArgs) + c.Assert(err, checker.IsNil) + + status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) + c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + c.Assert(err, checker.IsNil, check.Commentf(string(out))) + c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) + return tasks +} + +func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task { + var task swarm.Task + + status, out, err := d.SockRequest("GET", "/tasks/"+id, nil) + c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + c.Assert(err, checker.IsNil, check.Commentf(string(out))) + c.Assert(json.Unmarshal(out, &task), checker.IsNil) + return task +} + func (d *SwarmDaemon) updateService(c *check.C, service *swarm.Service, f ...serviceConstructor) { for _, fn := range f { fn(service) diff --git a/integration-cli/daemon_swarm_hack.go b/integration-cli/daemon_swarm_hack.go new file mode 100644 index 0000000000..d516ec4012 --- /dev/null +++ b/integration-cli/daemon_swarm_hack.go @@ -0,0 +1,20 @@ +package main + +import "github.com/go-check/check" + +func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *SwarmDaemon { + s.daemonsLock.Lock() + defer s.daemonsLock.Unlock() + for _, d := range s.daemons { + if d.NodeID == nodeID { + return d + } + } + c.Fatalf("could not find node with id: %s", nodeID) + return nil +} + +// nodeCmd executes a command on a given node via the normal docker socket +func (s *DockerSwarmSuite) nodeCmd(c *check.C, id, cmd string, args ...string) (string, error) { + return s.getDaemon(c, id).Cmd(cmd, args...) +} diff --git a/integration-cli/docker_cli_service_create_hack_test.go b/integration-cli/docker_cli_service_create_hack_test.go new file mode 100644 index 0000000000..abffa977ab --- /dev/null +++ b/integration-cli/docker_cli_service_create_hack_test.go @@ -0,0 +1,45 @@ +// +build !windows + +package main + +import ( + "encoding/json" + "strings" + + "github.com/docker/docker/pkg/integration/checker" + "github.com/docker/engine-api/types" + "github.com/docker/engine-api/types/swarm" + "github.com/go-check/check" +) + +func (s *DockerSwarmSuite) TestServiceCreateMountVolume(c *check.C) { + d := s.AddDaemon(c, true, true) + out, err := d.Cmd("service", "create", "--mount", "type=volume,source=foo,target=/foo", "busybox", "top") + c.Assert(err, checker.IsNil, check.Commentf(out)) + id := strings.TrimSpace(out) + + var tasks []swarm.Task + waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { + tasks = d.getServiceTasks(c, id) + return len(tasks) > 0, nil + }, checker.Equals, true) + + task := tasks[0] + waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { + if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" { + task = d.getTask(c, task.ID) + } + return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil + }, checker.Equals, true) + + out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID) + c.Assert(err, checker.IsNil, check.Commentf(out)) + + var mounts []types.MountPoint + c.Assert(json.Unmarshal([]byte(out), &mounts), checker.IsNil) + c.Assert(mounts, checker.HasLen, 1) + + c.Assert(mounts[0].Name, checker.Equals, "foo") + c.Assert(mounts[0].Destination, checker.Equals, "/foo") + c.Assert(mounts[0].RW, checker.Equals, false) +}