Browse code

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 <cpuguy83@gmail.com>
(cherry picked from commit e5ec575b32d6979914dce576f1b8bb71f3057cea)
Signed-off-by: Tibor Vass <tibor@docker.com>

Brian Goff authored on 2016/06/30 03:00:11
Showing 4 changed files
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"os"
6 6
 	"path/filepath"
7
+	"sync"
7 8
 	"testing"
8 9
 
9 10
 	"github.com/docker/docker/cliconfig"
... ...
@@ -194,9 +195,10 @@ func init() {
194 194
 }
195 195
 
196 196
 type DockerSwarmSuite struct {
197
-	ds        *DockerSuite
198
-	daemons   []*SwarmDaemon
199
-	portIndex int
197
+	ds          *DockerSuite
198
+	daemons     []*SwarmDaemon
199
+	daemonsLock sync.Mutex // protect access to daemons
200
+	portIndex   int
200 201
 }
201 202
 
202 203
 func (s *DockerSwarmSuite) SetUpTest(c *check.C) {
... ...
@@ -227,19 +229,23 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *Swarm
227 227
 	}
228 228
 
229 229
 	s.portIndex++
230
+	s.daemonsLock.Lock()
230 231
 	s.daemons = append(s.daemons, d)
232
+	s.daemonsLock.Unlock()
231 233
 
232 234
 	return d
233 235
 }
234 236
 
235 237
 func (s *DockerSwarmSuite) TearDownTest(c *check.C) {
236 238
 	testRequires(c, DaemonIsLinux)
239
+	s.daemonsLock.Lock()
237 240
 	for _, d := range s.daemons {
238 241
 		d.Stop()
239 242
 	}
240 243
 	s.daemons = nil
241
-	s.portIndex = 0
244
+	s.daemonsLock.Unlock()
242 245
 
246
+	s.portIndex = 0
243 247
 	s.ds.TearDownTest(c)
244 248
 }
245 249
 
... ...
@@ -9,6 +9,7 @@ import (
9 9
 
10 10
 	"github.com/docker/docker/pkg/integration/checker"
11 11
 	"github.com/docker/engine-api/types"
12
+	"github.com/docker/engine-api/types/filters"
12 13
 	"github.com/docker/engine-api/types/swarm"
13 14
 	"github.com/go-check/check"
14 15
 )
... ...
@@ -131,6 +132,32 @@ func (d *SwarmDaemon) getService(c *check.C, id string) *swarm.Service {
131 131
 	return &service
132 132
 }
133 133
 
134
+func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task {
135
+	var tasks []swarm.Task
136
+
137
+	filterArgs := filters.NewArgs()
138
+	filterArgs.Add("desired-state", "running")
139
+	filterArgs.Add("service", service)
140
+	filters, err := filters.ToParam(filterArgs)
141
+	c.Assert(err, checker.IsNil)
142
+
143
+	status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil)
144
+	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
145
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
146
+	c.Assert(json.Unmarshal(out, &tasks), checker.IsNil)
147
+	return tasks
148
+}
149
+
150
+func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task {
151
+	var task swarm.Task
152
+
153
+	status, out, err := d.SockRequest("GET", "/tasks/"+id, nil)
154
+	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
155
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
156
+	c.Assert(json.Unmarshal(out, &task), checker.IsNil)
157
+	return task
158
+}
159
+
134 160
 func (d *SwarmDaemon) updateService(c *check.C, service *swarm.Service, f ...serviceConstructor) {
135 161
 	for _, fn := range f {
136 162
 		fn(service)
137 163
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+package main
1
+
2
+import "github.com/go-check/check"
3
+
4
+func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *SwarmDaemon {
5
+	s.daemonsLock.Lock()
6
+	defer s.daemonsLock.Unlock()
7
+	for _, d := range s.daemons {
8
+		if d.NodeID == nodeID {
9
+			return d
10
+		}
11
+	}
12
+	c.Fatalf("could not find node with id: %s", nodeID)
13
+	return nil
14
+}
15
+
16
+// nodeCmd executes a command on a given node via the normal docker socket
17
+func (s *DockerSwarmSuite) nodeCmd(c *check.C, id, cmd string, args ...string) (string, error) {
18
+	return s.getDaemon(c, id).Cmd(cmd, args...)
19
+}
0 20
new file mode 100644
... ...
@@ -0,0 +1,45 @@
0
+// +build !windows
1
+
2
+package main
3
+
4
+import (
5
+	"encoding/json"
6
+	"strings"
7
+
8
+	"github.com/docker/docker/pkg/integration/checker"
9
+	"github.com/docker/engine-api/types"
10
+	"github.com/docker/engine-api/types/swarm"
11
+	"github.com/go-check/check"
12
+)
13
+
14
+func (s *DockerSwarmSuite) TestServiceCreateMountVolume(c *check.C) {
15
+	d := s.AddDaemon(c, true, true)
16
+	out, err := d.Cmd("service", "create", "--mount", "type=volume,source=foo,target=/foo", "busybox", "top")
17
+	c.Assert(err, checker.IsNil, check.Commentf(out))
18
+	id := strings.TrimSpace(out)
19
+
20
+	var tasks []swarm.Task
21
+	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
22
+		tasks = d.getServiceTasks(c, id)
23
+		return len(tasks) > 0, nil
24
+	}, checker.Equals, true)
25
+
26
+	task := tasks[0]
27
+	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
28
+		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
29
+			task = d.getTask(c, task.ID)
30
+		}
31
+		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
32
+	}, checker.Equals, true)
33
+
34
+	out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID)
35
+	c.Assert(err, checker.IsNil, check.Commentf(out))
36
+
37
+	var mounts []types.MountPoint
38
+	c.Assert(json.Unmarshal([]byte(out), &mounts), checker.IsNil)
39
+	c.Assert(mounts, checker.HasLen, 1)
40
+
41
+	c.Assert(mounts[0].Name, checker.Equals, "foo")
42
+	c.Assert(mounts[0].Destination, checker.Equals, "/foo")
43
+	c.Assert(mounts[0].RW, checker.Equals, false)
44
+}