Browse code

Setup tests

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2019/08/09 09:38:35
Showing 11 changed files
... ...
@@ -2,12 +2,14 @@ package main
2 2
 
3 3
 import (
4 4
 	"context"
5
+	"flag"
5 6
 	"fmt"
6 7
 	"io/ioutil"
7 8
 	"net/http/httptest"
8 9
 	"os"
9 10
 	"path"
10 11
 	"path/filepath"
12
+	"runtime"
11 13
 	"strconv"
12 14
 	"sync"
13 15
 	"syscall"
... ...
@@ -22,6 +24,7 @@ import (
22 22
 	"github.com/docker/docker/internal/test/fakestorage"
23 23
 	"github.com/docker/docker/internal/test/fixtures/plugin"
24 24
 	"github.com/docker/docker/internal/test/registry"
25
+	"github.com/docker/docker/internal/test/suite"
25 26
 	"github.com/docker/docker/pkg/reexec"
26 27
 	"gotest.tools/assert"
27 28
 )
... ...
@@ -57,6 +60,9 @@ func init() {
57 57
 }
58 58
 
59 59
 func TestMain(m *testing.M) {
60
+	flag.Parse()
61
+
62
+	// Global set up
60 63
 	dockerBinary = testEnv.DockerBinary()
61 64
 	err := ienv.EnsureFrozenImagesLinux(&testEnv.Execution)
62 65
 	if err != nil {
... ...
@@ -72,11 +78,21 @@ func Test(t *testing.T) {
72 72
 	cli.SetTestEnvironment(testEnv)
73 73
 	fakestorage.SetTestEnvironment(&testEnv.Execution)
74 74
 	ienv.ProtectAll(t, &testEnv.Execution)
75
-	/*check.TestingT(t)*/
76
-}
77
-
78
-func init() {
79
-	/*check.Suite(&DockerSuite{})*/
75
+	suite.Run(t, &DockerSuite{})
76
+	suite.Run(t, &DockerRegistrySuite{ds: &DockerSuite{}})
77
+	suite.Run(t, &DockerSchema1RegistrySuite{ds: &DockerSuite{}})
78
+	suite.Run(t, &DockerRegistryAuthHtpasswdSuite{ds: &DockerSuite{}})
79
+	suite.Run(t, &DockerRegistryAuthTokenSuite{ds: &DockerSuite{}})
80
+	suite.Run(t, &DockerDaemonSuite{ds: &DockerSuite{}})
81
+	suite.Run(t, &DockerSwarmSuite{ds: &DockerSuite{}})
82
+	suite.Run(t, &DockerPluginSuite{ds: &DockerSuite{}})
83
+	if runtime.GOOS != "windows" {
84
+		suite.Run(t, &DockerExternalVolumeSuite{ds: &DockerSuite{}})
85
+		suite.Run(t, &DockerNetworkSuite{ds: &DockerSuite{}})
86
+		// FIXME. Temporarily turning this off for Windows as GH16039 was breaking
87
+		// Windows to Linux CI @icecrime
88
+		suite.Run(t, newDockerHubPullSuite())
89
+	}
80 90
 }
81 91
 
82 92
 type DockerSuite struct {
... ...
@@ -107,10 +123,6 @@ func (s *DockerSuite) TearDownTest(c *testing.T) {
107 107
 	testEnv.Clean(c)
108 108
 }
109 109
 
110
-func init() {
111
-	/*check.Suite(&DockerRegistrySuite{ds: &DockerSuite{}})*/
112
-}
113
-
114 110
 type DockerRegistrySuite struct {
115 111
 	ds  *DockerSuite
116 112
 	reg *registry.V2
... ...
@@ -138,10 +150,6 @@ func (s *DockerRegistrySuite) TearDownTest(c *testing.T) {
138 138
 	s.ds.TearDownTest(c)
139 139
 }
140 140
 
141
-func init() {
142
-	/*check.Suite(&DockerSchema1RegistrySuite{ds: &DockerSuite{}})*/
143
-}
144
-
145 141
 type DockerSchema1RegistrySuite struct {
146 142
 	ds  *DockerSuite
147 143
 	reg *registry.V2
... ...
@@ -169,10 +177,6 @@ func (s *DockerSchema1RegistrySuite) TearDownTest(c *testing.T) {
169 169
 	s.ds.TearDownTest(c)
170 170
 }
171 171
 
172
-func init() {
173
-	/*check.Suite(&DockerRegistryAuthHtpasswdSuite{ds: &DockerSuite{}})*/
174
-}
175
-
176 172
 type DockerRegistryAuthHtpasswdSuite struct {
177 173
 	ds  *DockerSuite
178 174
 	reg *registry.V2
... ...
@@ -202,10 +206,6 @@ func (s *DockerRegistryAuthHtpasswdSuite) TearDownTest(c *testing.T) {
202 202
 	s.ds.TearDownTest(c)
203 203
 }
204 204
 
205
-func init() {
206
-	/*check.Suite(&DockerRegistryAuthTokenSuite{ds: &DockerSuite{}})*/
207
-}
208
-
209 205
 type DockerRegistryAuthTokenSuite struct {
210 206
 	ds  *DockerSuite
211 207
 	reg *registry.V2
... ...
@@ -241,10 +241,6 @@ func (s *DockerRegistryAuthTokenSuite) setupRegistryWithTokenService(c *testing.
241 241
 	s.reg.WaitReady(c)
242 242
 }
243 243
 
244
-func init() {
245
-	/*check.Suite(&DockerDaemonSuite{ds: &DockerSuite{}})*/
246
-}
247
-
248 244
 type DockerDaemonSuite struct {
249 245
 	ds *DockerSuite
250 246
 	d  *daemon.Daemon
... ...
@@ -284,10 +280,6 @@ func (s *DockerDaemonSuite) TearDownSuite(c *testing.T) {
284 284
 
285 285
 const defaultSwarmPort = 2477
286 286
 
287
-func init() {
288
-	/*check.Suite(&DockerSwarmSuite{ds: &DockerSuite{}})*/
289
-}
290
-
291 287
 type DockerSwarmSuite struct {
292 288
 	server      *httptest.Server
293 289
 	ds          *DockerSuite
... ...
@@ -346,10 +338,6 @@ func (s *DockerSwarmSuite) TearDownTest(c *testing.T) {
346 346
 	s.ds.TearDownTest(c)
347 347
 }
348 348
 
349
-func init() {
350
-	/*check.Suite(&DockerPluginSuite{ds: &DockerSuite{}})*/
351
-}
352
-
353 349
 type DockerPluginSuite struct {
354 350
 	ds       *DockerSuite
355 351
 	registry *registry.V2
356 352
new file mode 100644
... ...
@@ -0,0 +1,619 @@
0
+package main
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"net/http"
8
+	"net/http/httptest"
9
+	"os"
10
+	"os/exec"
11
+	"path/filepath"
12
+	"strings"
13
+	"testing"
14
+	"time"
15
+
16
+	"github.com/docker/docker/api/types"
17
+	"github.com/docker/docker/integration-cli/daemon"
18
+	testdaemon "github.com/docker/docker/internal/test/daemon"
19
+	"github.com/docker/docker/pkg/stringid"
20
+	"github.com/docker/docker/volume"
21
+	"gotest.tools/assert"
22
+)
23
+
24
+const volumePluginName = "test-external-volume-driver"
25
+
26
+type eventCounter struct {
27
+	activations int
28
+	creations   int
29
+	removals    int
30
+	mounts      int
31
+	unmounts    int
32
+	paths       int
33
+	lists       int
34
+	gets        int
35
+	caps        int
36
+}
37
+
38
+type DockerExternalVolumeSuite struct {
39
+	ds *DockerSuite
40
+	d  *daemon.Daemon
41
+	*volumePlugin
42
+}
43
+
44
+func (s *DockerExternalVolumeSuite) SetUpTest(c *testing.T) {
45
+	testRequires(c, testEnv.IsLocalDaemon)
46
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
47
+	s.ec = &eventCounter{}
48
+}
49
+
50
+func (s *DockerExternalVolumeSuite) TearDownTest(c *testing.T) {
51
+	if s.d != nil {
52
+		s.d.Stop(c)
53
+		s.ds.TearDownTest(c)
54
+	}
55
+}
56
+
57
+func (s *DockerExternalVolumeSuite) SetUpSuite(c *testing.T) {
58
+	s.volumePlugin = newVolumePlugin(c, volumePluginName)
59
+}
60
+
61
+type volumePlugin struct {
62
+	ec *eventCounter
63
+	*httptest.Server
64
+	vols map[string]vol
65
+}
66
+
67
+type vol struct {
68
+	Name       string
69
+	Mountpoint string
70
+	Ninja      bool // hack used to trigger a null volume return on `Get`
71
+	Status     map[string]interface{}
72
+	Options    map[string]string
73
+}
74
+
75
+func (p *volumePlugin) Close() {
76
+	p.Server.Close()
77
+}
78
+
79
+func newVolumePlugin(c *testing.T, name string) *volumePlugin {
80
+	mux := http.NewServeMux()
81
+	s := &volumePlugin{Server: httptest.NewServer(mux), ec: &eventCounter{}, vols: make(map[string]vol)}
82
+
83
+	type pluginRequest struct {
84
+		Name string
85
+		Opts map[string]string
86
+		ID   string
87
+	}
88
+
89
+	type pluginResp struct {
90
+		Mountpoint string `json:",omitempty"`
91
+		Err        string `json:",omitempty"`
92
+	}
93
+
94
+	read := func(b io.ReadCloser) (pluginRequest, error) {
95
+		defer b.Close()
96
+		var pr pluginRequest
97
+		err := json.NewDecoder(b).Decode(&pr)
98
+		return pr, err
99
+	}
100
+
101
+	send := func(w http.ResponseWriter, data interface{}) {
102
+		switch t := data.(type) {
103
+		case error:
104
+			http.Error(w, t.Error(), 500)
105
+		case string:
106
+			w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
107
+			fmt.Fprintln(w, t)
108
+		default:
109
+			w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
110
+			json.NewEncoder(w).Encode(&data)
111
+		}
112
+	}
113
+
114
+	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
115
+		s.ec.activations++
116
+		send(w, `{"Implements": ["VolumeDriver"]}`)
117
+	})
118
+
119
+	mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) {
120
+		s.ec.creations++
121
+		pr, err := read(r.Body)
122
+		if err != nil {
123
+			send(w, err)
124
+			return
125
+		}
126
+		_, isNinja := pr.Opts["ninja"]
127
+		status := map[string]interface{}{"Hello": "world"}
128
+		s.vols[pr.Name] = vol{Name: pr.Name, Ninja: isNinja, Status: status, Options: pr.Opts}
129
+		send(w, nil)
130
+	})
131
+
132
+	mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) {
133
+		s.ec.lists++
134
+		vols := make([]vol, 0, len(s.vols))
135
+		for _, v := range s.vols {
136
+			if v.Ninja {
137
+				continue
138
+			}
139
+			vols = append(vols, v)
140
+		}
141
+		send(w, map[string][]vol{"Volumes": vols})
142
+	})
143
+
144
+	mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) {
145
+		s.ec.gets++
146
+		pr, err := read(r.Body)
147
+		if err != nil {
148
+			send(w, err)
149
+			return
150
+		}
151
+
152
+		v, exists := s.vols[pr.Name]
153
+		if !exists {
154
+			send(w, `{"Err": "no such volume"}`)
155
+		}
156
+
157
+		if v.Ninja {
158
+			send(w, map[string]vol{})
159
+			return
160
+		}
161
+
162
+		v.Mountpoint = hostVolumePath(pr.Name)
163
+		send(w, map[string]vol{"Volume": v})
164
+		return
165
+	})
166
+
167
+	mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
168
+		s.ec.removals++
169
+		pr, err := read(r.Body)
170
+		if err != nil {
171
+			send(w, err)
172
+			return
173
+		}
174
+
175
+		v, ok := s.vols[pr.Name]
176
+		if !ok {
177
+			send(w, nil)
178
+			return
179
+		}
180
+
181
+		if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
182
+			send(w, &pluginResp{Err: err.Error()})
183
+			return
184
+		}
185
+		delete(s.vols, v.Name)
186
+		send(w, nil)
187
+	})
188
+
189
+	mux.HandleFunc("/VolumeDriver.Path", func(w http.ResponseWriter, r *http.Request) {
190
+		s.ec.paths++
191
+
192
+		pr, err := read(r.Body)
193
+		if err != nil {
194
+			send(w, err)
195
+			return
196
+		}
197
+		p := hostVolumePath(pr.Name)
198
+		send(w, &pluginResp{Mountpoint: p})
199
+	})
200
+
201
+	mux.HandleFunc("/VolumeDriver.Mount", func(w http.ResponseWriter, r *http.Request) {
202
+		s.ec.mounts++
203
+
204
+		pr, err := read(r.Body)
205
+		if err != nil {
206
+			send(w, err)
207
+			return
208
+		}
209
+
210
+		if v, exists := s.vols[pr.Name]; exists {
211
+			// Use this to simulate a mount failure
212
+			if _, exists := v.Options["invalidOption"]; exists {
213
+				send(w, fmt.Errorf("invalid argument"))
214
+				return
215
+			}
216
+		}
217
+
218
+		p := hostVolumePath(pr.Name)
219
+		if err := os.MkdirAll(p, 0755); err != nil {
220
+			send(w, &pluginResp{Err: err.Error()})
221
+			return
222
+		}
223
+
224
+		if err := ioutil.WriteFile(filepath.Join(p, "test"), []byte(s.Server.URL), 0644); err != nil {
225
+			send(w, err)
226
+			return
227
+		}
228
+
229
+		if err := ioutil.WriteFile(filepath.Join(p, "mountID"), []byte(pr.ID), 0644); err != nil {
230
+			send(w, err)
231
+			return
232
+		}
233
+
234
+		send(w, &pluginResp{Mountpoint: p})
235
+	})
236
+
237
+	mux.HandleFunc("/VolumeDriver.Unmount", func(w http.ResponseWriter, r *http.Request) {
238
+		s.ec.unmounts++
239
+
240
+		_, err := read(r.Body)
241
+		if err != nil {
242
+			send(w, err)
243
+			return
244
+		}
245
+
246
+		send(w, nil)
247
+	})
248
+
249
+	mux.HandleFunc("/VolumeDriver.Capabilities", func(w http.ResponseWriter, r *http.Request) {
250
+		s.ec.caps++
251
+
252
+		_, err := read(r.Body)
253
+		if err != nil {
254
+			send(w, err)
255
+			return
256
+		}
257
+
258
+		send(w, `{"Capabilities": { "Scope": "global" }}`)
259
+	})
260
+
261
+	err := os.MkdirAll("/etc/docker/plugins", 0755)
262
+	assert.NilError(c, err)
263
+
264
+	err = ioutil.WriteFile("/etc/docker/plugins/"+name+".spec", []byte(s.Server.URL), 0644)
265
+	assert.NilError(c, err)
266
+	return s
267
+}
268
+
269
+func (s *DockerExternalVolumeSuite) TearDownSuite(c *testing.T) {
270
+	s.volumePlugin.Close()
271
+
272
+	err := os.RemoveAll("/etc/docker/plugins")
273
+	assert.NilError(c, err)
274
+}
275
+
276
+func (s *DockerExternalVolumeSuite) TestVolumeCLICreateOptionConflict(c *testing.T) {
277
+	dockerCmd(c, "volume", "create", "test")
278
+
279
+	out, _, err := dockerCmdWithError("volume", "create", "test", "--driver", volumePluginName)
280
+	assert.Assert(c, err != nil, "volume create exception name already in use with another driver")
281
+	assert.Assert(c, strings.Contains(out, "must be unique"))
282
+	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Driver }}", "test")
283
+	_, _, err = dockerCmdWithError("volume", "create", "test", "--driver", strings.TrimSpace(out))
284
+	assert.NilError(c, err)
285
+}
286
+
287
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverNamed(c *testing.T) {
288
+	s.d.StartWithBusybox(c)
289
+
290
+	out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
291
+	assert.NilError(c, err, out)
292
+	assert.Assert(c, strings.Contains(out, s.Server.URL))
293
+	_, err = s.d.Cmd("volume", "rm", "external-volume-test")
294
+	assert.NilError(c, err)
295
+
296
+	p := hostVolumePath("external-volume-test")
297
+	_, err = os.Lstat(p)
298
+	assert.ErrorContains(c, err, "")
299
+	assert.Assert(c, os.IsNotExist(err), fmt.Sprintf("Expected volume path in host to not exist: %s, %v\n", p, err))
300
+
301
+	assert.Equal(c, s.ec.activations, 1)
302
+	assert.Equal(c, s.ec.creations, 1)
303
+	assert.Equal(c, s.ec.removals, 1)
304
+	assert.Equal(c, s.ec.mounts, 1)
305
+	assert.Equal(c, s.ec.unmounts, 1)
306
+}
307
+
308
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnnamed(c *testing.T) {
309
+	s.d.StartWithBusybox(c)
310
+
311
+	out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
312
+	assert.NilError(c, err, out)
313
+	assert.Assert(c, strings.Contains(out, s.Server.URL))
314
+	assert.Equal(c, s.ec.activations, 1)
315
+	assert.Equal(c, s.ec.creations, 1)
316
+	assert.Equal(c, s.ec.removals, 1)
317
+	assert.Equal(c, s.ec.mounts, 1)
318
+	assert.Equal(c, s.ec.unmounts, 1)
319
+}
320
+
321
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverVolumesFrom(c *testing.T) {
322
+	s.d.StartWithBusybox(c)
323
+
324
+	out, err := s.d.Cmd("run", "--name", "vol-test1", "-v", "/foo", "--volume-driver", volumePluginName, "busybox:latest")
325
+	assert.NilError(c, err, out)
326
+
327
+	out, err = s.d.Cmd("run", "--rm", "--volumes-from", "vol-test1", "--name", "vol-test2", "busybox", "ls", "/tmp")
328
+	assert.NilError(c, err, out)
329
+
330
+	out, err = s.d.Cmd("rm", "-fv", "vol-test1")
331
+	assert.NilError(c, err, out)
332
+
333
+	assert.Equal(c, s.ec.activations, 1)
334
+	assert.Equal(c, s.ec.creations, 1)
335
+	assert.Equal(c, s.ec.removals, 1)
336
+	assert.Equal(c, s.ec.mounts, 2)
337
+	assert.Equal(c, s.ec.unmounts, 2)
338
+}
339
+
340
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverDeleteContainer(c *testing.T) {
341
+	s.d.StartWithBusybox(c)
342
+
343
+	out, err := s.d.Cmd("run", "--name", "vol-test1", "-v", "/foo", "--volume-driver", volumePluginName, "busybox:latest")
344
+	assert.NilError(c, err, out)
345
+
346
+	out, err = s.d.Cmd("rm", "-fv", "vol-test1")
347
+	assert.NilError(c, err, out)
348
+
349
+	assert.Equal(c, s.ec.activations, 1)
350
+	assert.Equal(c, s.ec.creations, 1)
351
+	assert.Equal(c, s.ec.removals, 1)
352
+	assert.Equal(c, s.ec.mounts, 1)
353
+	assert.Equal(c, s.ec.unmounts, 1)
354
+}
355
+
356
+func hostVolumePath(name string) string {
357
+	return fmt.Sprintf("/var/lib/docker/volumes/%s", name)
358
+}
359
+
360
+// Make sure a request to use a down driver doesn't block other requests
361
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *testing.T) {
362
+	specPath := "/etc/docker/plugins/down-driver.spec"
363
+	err := ioutil.WriteFile(specPath, []byte("tcp://127.0.0.7:9999"), 0644)
364
+	assert.NilError(c, err)
365
+	defer os.RemoveAll(specPath)
366
+
367
+	chCmd1 := make(chan struct{})
368
+	chCmd2 := make(chan error)
369
+	cmd1 := exec.Command(dockerBinary, "volume", "create", "-d", "down-driver")
370
+	cmd2 := exec.Command(dockerBinary, "volume", "create")
371
+
372
+	assert.Assert(c, cmd1.Start() == nil)
373
+	defer cmd1.Process.Kill()
374
+	time.Sleep(100 * time.Millisecond) // ensure API has been called
375
+	assert.Assert(c, cmd2.Start() == nil)
376
+
377
+	go func() {
378
+		cmd1.Wait()
379
+		close(chCmd1)
380
+	}()
381
+	go func() {
382
+		chCmd2 <- cmd2.Wait()
383
+	}()
384
+
385
+	select {
386
+	case <-chCmd1:
387
+		cmd2.Process.Kill()
388
+		c.Fatalf("volume create with down driver finished unexpectedly")
389
+	case err := <-chCmd2:
390
+		assert.NilError(c, err)
391
+	case <-time.After(5 * time.Second):
392
+		cmd2.Process.Kill()
393
+		c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
394
+	}
395
+}
396
+
397
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverRetryNotImmediatelyExists(c *testing.T) {
398
+	s.d.StartWithBusybox(c)
399
+	driverName := "test-external-volume-driver-retry"
400
+
401
+	errchan := make(chan error)
402
+	started := make(chan struct{})
403
+	go func() {
404
+		close(started)
405
+		if out, err := s.d.Cmd("run", "--rm", "--name", "test-data-retry", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", driverName, "busybox:latest"); err != nil {
406
+			errchan <- fmt.Errorf("%v:\n%s", err, out)
407
+		}
408
+		close(errchan)
409
+	}()
410
+
411
+	<-started
412
+	// wait for a retry to occur, then create spec to allow plugin to register
413
+	time.Sleep(2 * time.Second)
414
+	p := newVolumePlugin(c, driverName)
415
+	defer p.Close()
416
+
417
+	select {
418
+	case err := <-errchan:
419
+		assert.NilError(c, err)
420
+	case <-time.After(8 * time.Second):
421
+		c.Fatal("volume creates fail when plugin not immediately available")
422
+	}
423
+
424
+	_, err := s.d.Cmd("volume", "rm", "external-volume-test")
425
+	assert.NilError(c, err)
426
+
427
+	assert.Equal(c, p.ec.activations, 1)
428
+	assert.Equal(c, p.ec.creations, 1)
429
+	assert.Equal(c, p.ec.removals, 1)
430
+	assert.Equal(c, p.ec.mounts, 1)
431
+	assert.Equal(c, p.ec.unmounts, 1)
432
+}
433
+
434
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverBindExternalVolume(c *testing.T) {
435
+	dockerCmd(c, "volume", "create", "-d", volumePluginName, "foo")
436
+	dockerCmd(c, "run", "-d", "--name", "testing", "-v", "foo:/bar", "busybox", "top")
437
+
438
+	var mounts []struct {
439
+		Name   string
440
+		Driver string
441
+	}
442
+	out := inspectFieldJSON(c, "testing", "Mounts")
443
+	assert.Assert(c, json.NewDecoder(strings.NewReader(out)).Decode(&mounts) == nil)
444
+	assert.Equal(c, len(mounts), 1, fmt.Sprintf("%s", out))
445
+	assert.Equal(c, mounts[0].Name, "foo")
446
+	assert.Equal(c, mounts[0].Driver, volumePluginName)
447
+}
448
+
449
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverList(c *testing.T) {
450
+	dockerCmd(c, "volume", "create", "-d", volumePluginName, "abc3")
451
+	out, _ := dockerCmd(c, "volume", "ls")
452
+	ls := strings.Split(strings.TrimSpace(out), "\n")
453
+	assert.Equal(c, len(ls), 2, fmt.Sprintf("\n%s", out))
454
+
455
+	vol := strings.Fields(ls[len(ls)-1])
456
+	assert.Equal(c, len(vol), 2, fmt.Sprintf("%v", vol))
457
+	assert.Equal(c, vol[0], volumePluginName)
458
+	assert.Equal(c, vol[1], "abc3")
459
+
460
+	assert.Equal(c, s.ec.lists, 1)
461
+}
462
+
463
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGet(c *testing.T) {
464
+	out, _, err := dockerCmdWithError("volume", "inspect", "dummy")
465
+	assert.ErrorContains(c, err, "", out)
466
+	assert.Assert(c, strings.Contains(out, "No such volume"))
467
+	assert.Equal(c, s.ec.gets, 1)
468
+
469
+	dockerCmd(c, "volume", "create", "test", "-d", volumePluginName)
470
+	out, _ = dockerCmd(c, "volume", "inspect", "test")
471
+
472
+	type vol struct {
473
+		Status map[string]string
474
+	}
475
+	var st []vol
476
+
477
+	assert.Assert(c, json.Unmarshal([]byte(out), &st) == nil)
478
+	assert.Equal(c, len(st), 1)
479
+	assert.Equal(c, len(st[0].Status), 1, fmt.Sprintf("%v", st[0]))
480
+	assert.Equal(c, st[0].Status["Hello"], "world", fmt.Sprintf("%v", st[0].Status))
481
+}
482
+
483
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverWithDaemonRestart(c *testing.T) {
484
+	dockerCmd(c, "volume", "create", "-d", volumePluginName, "abc1")
485
+	s.d.Restart(c)
486
+
487
+	dockerCmd(c, "run", "--name=test", "-v", "abc1:/foo", "busybox", "true")
488
+	var mounts []types.MountPoint
489
+	inspectFieldAndUnmarshall(c, "test", "Mounts", &mounts)
490
+	assert.Equal(c, len(mounts), 1)
491
+	assert.Equal(c, mounts[0].Driver, volumePluginName)
492
+}
493
+
494
+// Ensures that the daemon handles when the plugin responds to a `Get` request with a null volume and a null error.
495
+// Prior the daemon would panic in this scenario.
496
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGetEmptyResponse(c *testing.T) {
497
+	s.d.Start(c)
498
+
499
+	out, err := s.d.Cmd("volume", "create", "-d", volumePluginName, "abc2", "--opt", "ninja=1")
500
+	assert.NilError(c, err, out)
501
+
502
+	out, err = s.d.Cmd("volume", "inspect", "abc2")
503
+	assert.ErrorContains(c, err, "", out)
504
+	assert.Assert(c, strings.Contains(out, "No such volume"))
505
+}
506
+
507
+// Ensure only cached paths are used in volume list to prevent N+1 calls to `VolumeDriver.Path`
508
+//
509
+// TODO(@cpuguy83): This test is testing internal implementation. In all the cases here, there may not even be a path
510
+// 	available because the volume is not even mounted. Consider removing this test.
511
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverPathCalls(c *testing.T) {
512
+	s.d.Start(c)
513
+	assert.Equal(c, s.ec.paths, 0)
514
+
515
+	out, err := s.d.Cmd("volume", "create", "test", "--driver=test-external-volume-driver")
516
+	assert.NilError(c, err, out)
517
+	assert.Equal(c, s.ec.paths, 0)
518
+
519
+	out, err = s.d.Cmd("volume", "ls")
520
+	assert.NilError(c, err, out)
521
+	assert.Equal(c, s.ec.paths, 0)
522
+}
523
+
524
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverMountID(c *testing.T) {
525
+	s.d.StartWithBusybox(c)
526
+
527
+	out, err := s.d.Cmd("run", "--rm", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
528
+	assert.NilError(c, err, out)
529
+	assert.Assert(c, strings.TrimSpace(out) != "")
530
+}
531
+
532
+// Check that VolumeDriver.Capabilities gets called, and only called once
533
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverCapabilities(c *testing.T) {
534
+	s.d.Start(c)
535
+	assert.Equal(c, s.ec.caps, 0)
536
+
537
+	for i := 0; i < 3; i++ {
538
+		out, err := s.d.Cmd("volume", "create", "-d", volumePluginName, fmt.Sprintf("test%d", i))
539
+		assert.NilError(c, err, out)
540
+		assert.Equal(c, s.ec.caps, 1)
541
+		out, err = s.d.Cmd("volume", "inspect", "--format={{.Scope}}", fmt.Sprintf("test%d", i))
542
+		assert.NilError(c, err)
543
+		assert.Equal(c, strings.TrimSpace(out), volume.GlobalScope)
544
+	}
545
+}
546
+
547
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverOutOfBandDelete(c *testing.T) {
548
+	driverName := stringid.GenerateRandomID()
549
+	p := newVolumePlugin(c, driverName)
550
+	defer p.Close()
551
+
552
+	s.d.StartWithBusybox(c)
553
+
554
+	out, err := s.d.Cmd("volume", "create", "-d", driverName, "--name", "test")
555
+	assert.NilError(c, err, out)
556
+
557
+	out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
558
+	assert.ErrorContains(c, err, "", out)
559
+	assert.Assert(c, strings.Contains(out, "must be unique"))
560
+	// simulate out of band volume deletion on plugin level
561
+	delete(p.vols, "test")
562
+
563
+	// test re-create with same driver
564
+	out, err = s.d.Cmd("volume", "create", "-d", driverName, "--opt", "foo=bar", "--name", "test")
565
+	assert.NilError(c, err, out)
566
+	out, err = s.d.Cmd("volume", "inspect", "test")
567
+	assert.NilError(c, err, out)
568
+
569
+	var vs []types.Volume
570
+	err = json.Unmarshal([]byte(out), &vs)
571
+	assert.NilError(c, err)
572
+	assert.Equal(c, len(vs), 1)
573
+	assert.Equal(c, vs[0].Driver, driverName)
574
+	assert.Assert(c, vs[0].Options != nil)
575
+	assert.Equal(c, vs[0].Options["foo"], "bar")
576
+	assert.Equal(c, vs[0].Driver, driverName)
577
+
578
+	// simulate out of band volume deletion on plugin level
579
+	delete(p.vols, "test")
580
+
581
+	// test create with different driver
582
+	out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
583
+	assert.NilError(c, err, out)
584
+
585
+	out, err = s.d.Cmd("volume", "inspect", "test")
586
+	assert.NilError(c, err, out)
587
+	vs = nil
588
+	err = json.Unmarshal([]byte(out), &vs)
589
+	assert.NilError(c, err)
590
+	assert.Equal(c, len(vs), 1)
591
+	assert.Equal(c, len(vs[0].Options), 0)
592
+	assert.Equal(c, vs[0].Driver, "local")
593
+}
594
+
595
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnMountFail(c *testing.T) {
596
+	s.d.StartWithBusybox(c)
597
+	s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--opt=invalidOption=1", "--name=testumount")
598
+
599
+	out, _ := s.d.Cmd("run", "-v", "testumount:/foo", "busybox", "true")
600
+	assert.Equal(c, s.ec.unmounts, 0, fmt.Sprintf("%s", out))
601
+	out, _ = s.d.Cmd("run", "-w", "/foo", "-v", "testumount:/foo", "busybox", "true")
602
+	assert.Equal(c, s.ec.unmounts, 0, fmt.Sprintf("%s", out))
603
+}
604
+
605
+func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnCp(c *testing.T) {
606
+	s.d.StartWithBusybox(c)
607
+	s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--name=test")
608
+
609
+	out, _ := s.d.Cmd("run", "-d", "--name=test", "-v", "test:/foo", "busybox", "/bin/sh", "-c", "touch /test && top")
610
+	assert.Equal(c, s.ec.mounts, 1, fmt.Sprintf("%s", out))
611
+
612
+	out, _ = s.d.Cmd("cp", "test:/test", "/tmp/test")
613
+	assert.Equal(c, s.ec.mounts, 2, fmt.Sprintf("%s", out))
614
+	assert.Equal(c, s.ec.unmounts, 1, fmt.Sprintf("%s", out))
615
+
616
+	out, _ = s.d.Cmd("kill", "test")
617
+	assert.Equal(c, s.ec.unmounts, 2, fmt.Sprintf("%s", out))
618
+}
0 619
deleted file mode 100644
... ...
@@ -1,625 +0,0 @@
1
-// +build !windows
2
-
3
-package main
4
-
5
-import (
6
-	"encoding/json"
7
-	"fmt"
8
-	"io"
9
-	"io/ioutil"
10
-	"net/http"
11
-	"net/http/httptest"
12
-	"os"
13
-	"os/exec"
14
-	"path/filepath"
15
-	"strings"
16
-	"testing"
17
-	"time"
18
-
19
-	"github.com/docker/docker/api/types"
20
-	"github.com/docker/docker/integration-cli/daemon"
21
-	testdaemon "github.com/docker/docker/internal/test/daemon"
22
-	"github.com/docker/docker/pkg/stringid"
23
-	"github.com/docker/docker/volume"
24
-	"gotest.tools/assert"
25
-)
26
-
27
-const volumePluginName = "test-external-volume-driver"
28
-
29
-func init() {
30
-	/*check.Suite(&DockerExternalVolumeSuite{ds: &DockerSuite{}})*/
31
-}
32
-
33
-type eventCounter struct {
34
-	activations int
35
-	creations   int
36
-	removals    int
37
-	mounts      int
38
-	unmounts    int
39
-	paths       int
40
-	lists       int
41
-	gets        int
42
-	caps        int
43
-}
44
-
45
-type DockerExternalVolumeSuite struct {
46
-	ds *DockerSuite
47
-	d  *daemon.Daemon
48
-	*volumePlugin
49
-}
50
-
51
-func (s *DockerExternalVolumeSuite) SetUpTest(c *testing.T) {
52
-	testRequires(c, testEnv.IsLocalDaemon)
53
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
54
-	s.ec = &eventCounter{}
55
-}
56
-
57
-func (s *DockerExternalVolumeSuite) TearDownTest(c *testing.T) {
58
-	if s.d != nil {
59
-		s.d.Stop(c)
60
-		s.ds.TearDownTest(c)
61
-	}
62
-}
63
-
64
-func (s *DockerExternalVolumeSuite) SetUpSuite(c *testing.T) {
65
-	s.volumePlugin = newVolumePlugin(c, volumePluginName)
66
-}
67
-
68
-type volumePlugin struct {
69
-	ec *eventCounter
70
-	*httptest.Server
71
-	vols map[string]vol
72
-}
73
-
74
-type vol struct {
75
-	Name       string
76
-	Mountpoint string
77
-	Ninja      bool // hack used to trigger a null volume return on `Get`
78
-	Status     map[string]interface{}
79
-	Options    map[string]string
80
-}
81
-
82
-func (p *volumePlugin) Close() {
83
-	p.Server.Close()
84
-}
85
-
86
-func newVolumePlugin(c *testing.T, name string) *volumePlugin {
87
-	mux := http.NewServeMux()
88
-	s := &volumePlugin{Server: httptest.NewServer(mux), ec: &eventCounter{}, vols: make(map[string]vol)}
89
-
90
-	type pluginRequest struct {
91
-		Name string
92
-		Opts map[string]string
93
-		ID   string
94
-	}
95
-
96
-	type pluginResp struct {
97
-		Mountpoint string `json:",omitempty"`
98
-		Err        string `json:",omitempty"`
99
-	}
100
-
101
-	read := func(b io.ReadCloser) (pluginRequest, error) {
102
-		defer b.Close()
103
-		var pr pluginRequest
104
-		err := json.NewDecoder(b).Decode(&pr)
105
-		return pr, err
106
-	}
107
-
108
-	send := func(w http.ResponseWriter, data interface{}) {
109
-		switch t := data.(type) {
110
-		case error:
111
-			http.Error(w, t.Error(), 500)
112
-		case string:
113
-			w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
114
-			fmt.Fprintln(w, t)
115
-		default:
116
-			w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
117
-			json.NewEncoder(w).Encode(&data)
118
-		}
119
-	}
120
-
121
-	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
122
-		s.ec.activations++
123
-		send(w, `{"Implements": ["VolumeDriver"]}`)
124
-	})
125
-
126
-	mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) {
127
-		s.ec.creations++
128
-		pr, err := read(r.Body)
129
-		if err != nil {
130
-			send(w, err)
131
-			return
132
-		}
133
-		_, isNinja := pr.Opts["ninja"]
134
-		status := map[string]interface{}{"Hello": "world"}
135
-		s.vols[pr.Name] = vol{Name: pr.Name, Ninja: isNinja, Status: status, Options: pr.Opts}
136
-		send(w, nil)
137
-	})
138
-
139
-	mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) {
140
-		s.ec.lists++
141
-		vols := make([]vol, 0, len(s.vols))
142
-		for _, v := range s.vols {
143
-			if v.Ninja {
144
-				continue
145
-			}
146
-			vols = append(vols, v)
147
-		}
148
-		send(w, map[string][]vol{"Volumes": vols})
149
-	})
150
-
151
-	mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) {
152
-		s.ec.gets++
153
-		pr, err := read(r.Body)
154
-		if err != nil {
155
-			send(w, err)
156
-			return
157
-		}
158
-
159
-		v, exists := s.vols[pr.Name]
160
-		if !exists {
161
-			send(w, `{"Err": "no such volume"}`)
162
-		}
163
-
164
-		if v.Ninja {
165
-			send(w, map[string]vol{})
166
-			return
167
-		}
168
-
169
-		v.Mountpoint = hostVolumePath(pr.Name)
170
-		send(w, map[string]vol{"Volume": v})
171
-		return
172
-	})
173
-
174
-	mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
175
-		s.ec.removals++
176
-		pr, err := read(r.Body)
177
-		if err != nil {
178
-			send(w, err)
179
-			return
180
-		}
181
-
182
-		v, ok := s.vols[pr.Name]
183
-		if !ok {
184
-			send(w, nil)
185
-			return
186
-		}
187
-
188
-		if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
189
-			send(w, &pluginResp{Err: err.Error()})
190
-			return
191
-		}
192
-		delete(s.vols, v.Name)
193
-		send(w, nil)
194
-	})
195
-
196
-	mux.HandleFunc("/VolumeDriver.Path", func(w http.ResponseWriter, r *http.Request) {
197
-		s.ec.paths++
198
-
199
-		pr, err := read(r.Body)
200
-		if err != nil {
201
-			send(w, err)
202
-			return
203
-		}
204
-		p := hostVolumePath(pr.Name)
205
-		send(w, &pluginResp{Mountpoint: p})
206
-	})
207
-
208
-	mux.HandleFunc("/VolumeDriver.Mount", func(w http.ResponseWriter, r *http.Request) {
209
-		s.ec.mounts++
210
-
211
-		pr, err := read(r.Body)
212
-		if err != nil {
213
-			send(w, err)
214
-			return
215
-		}
216
-
217
-		if v, exists := s.vols[pr.Name]; exists {
218
-			// Use this to simulate a mount failure
219
-			if _, exists := v.Options["invalidOption"]; exists {
220
-				send(w, fmt.Errorf("invalid argument"))
221
-				return
222
-			}
223
-		}
224
-
225
-		p := hostVolumePath(pr.Name)
226
-		if err := os.MkdirAll(p, 0755); err != nil {
227
-			send(w, &pluginResp{Err: err.Error()})
228
-			return
229
-		}
230
-
231
-		if err := ioutil.WriteFile(filepath.Join(p, "test"), []byte(s.Server.URL), 0644); err != nil {
232
-			send(w, err)
233
-			return
234
-		}
235
-
236
-		if err := ioutil.WriteFile(filepath.Join(p, "mountID"), []byte(pr.ID), 0644); err != nil {
237
-			send(w, err)
238
-			return
239
-		}
240
-
241
-		send(w, &pluginResp{Mountpoint: p})
242
-	})
243
-
244
-	mux.HandleFunc("/VolumeDriver.Unmount", func(w http.ResponseWriter, r *http.Request) {
245
-		s.ec.unmounts++
246
-
247
-		_, err := read(r.Body)
248
-		if err != nil {
249
-			send(w, err)
250
-			return
251
-		}
252
-
253
-		send(w, nil)
254
-	})
255
-
256
-	mux.HandleFunc("/VolumeDriver.Capabilities", func(w http.ResponseWriter, r *http.Request) {
257
-		s.ec.caps++
258
-
259
-		_, err := read(r.Body)
260
-		if err != nil {
261
-			send(w, err)
262
-			return
263
-		}
264
-
265
-		send(w, `{"Capabilities": { "Scope": "global" }}`)
266
-	})
267
-
268
-	err := os.MkdirAll("/etc/docker/plugins", 0755)
269
-	assert.NilError(c, err)
270
-
271
-	err = ioutil.WriteFile("/etc/docker/plugins/"+name+".spec", []byte(s.Server.URL), 0644)
272
-	assert.NilError(c, err)
273
-	return s
274
-}
275
-
276
-func (s *DockerExternalVolumeSuite) TearDownSuite(c *testing.T) {
277
-	s.volumePlugin.Close()
278
-
279
-	err := os.RemoveAll("/etc/docker/plugins")
280
-	assert.NilError(c, err)
281
-}
282
-
283
-func (s *DockerExternalVolumeSuite) TestVolumeCLICreateOptionConflict(c *testing.T) {
284
-	dockerCmd(c, "volume", "create", "test")
285
-
286
-	out, _, err := dockerCmdWithError("volume", "create", "test", "--driver", volumePluginName)
287
-	assert.Assert(c, err != nil, "volume create exception name already in use with another driver")
288
-	assert.Assert(c, strings.Contains(out, "must be unique"))
289
-	out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Driver }}", "test")
290
-	_, _, err = dockerCmdWithError("volume", "create", "test", "--driver", strings.TrimSpace(out))
291
-	assert.NilError(c, err)
292
-}
293
-
294
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverNamed(c *testing.T) {
295
-	s.d.StartWithBusybox(c)
296
-
297
-	out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
298
-	assert.NilError(c, err, out)
299
-	assert.Assert(c, strings.Contains(out, s.Server.URL))
300
-	_, err = s.d.Cmd("volume", "rm", "external-volume-test")
301
-	assert.NilError(c, err)
302
-
303
-	p := hostVolumePath("external-volume-test")
304
-	_, err = os.Lstat(p)
305
-	assert.ErrorContains(c, err, "")
306
-	assert.Assert(c, os.IsNotExist(err), fmt.Sprintf("Expected volume path in host to not exist: %s, %v\n", p, err))
307
-
308
-	assert.Equal(c, s.ec.activations, 1)
309
-	assert.Equal(c, s.ec.creations, 1)
310
-	assert.Equal(c, s.ec.removals, 1)
311
-	assert.Equal(c, s.ec.mounts, 1)
312
-	assert.Equal(c, s.ec.unmounts, 1)
313
-}
314
-
315
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnnamed(c *testing.T) {
316
-	s.d.StartWithBusybox(c)
317
-
318
-	out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
319
-	assert.NilError(c, err, out)
320
-	assert.Assert(c, strings.Contains(out, s.Server.URL))
321
-	assert.Equal(c, s.ec.activations, 1)
322
-	assert.Equal(c, s.ec.creations, 1)
323
-	assert.Equal(c, s.ec.removals, 1)
324
-	assert.Equal(c, s.ec.mounts, 1)
325
-	assert.Equal(c, s.ec.unmounts, 1)
326
-}
327
-
328
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverVolumesFrom(c *testing.T) {
329
-	s.d.StartWithBusybox(c)
330
-
331
-	out, err := s.d.Cmd("run", "--name", "vol-test1", "-v", "/foo", "--volume-driver", volumePluginName, "busybox:latest")
332
-	assert.NilError(c, err, out)
333
-
334
-	out, err = s.d.Cmd("run", "--rm", "--volumes-from", "vol-test1", "--name", "vol-test2", "busybox", "ls", "/tmp")
335
-	assert.NilError(c, err, out)
336
-
337
-	out, err = s.d.Cmd("rm", "-fv", "vol-test1")
338
-	assert.NilError(c, err, out)
339
-
340
-	assert.Equal(c, s.ec.activations, 1)
341
-	assert.Equal(c, s.ec.creations, 1)
342
-	assert.Equal(c, s.ec.removals, 1)
343
-	assert.Equal(c, s.ec.mounts, 2)
344
-	assert.Equal(c, s.ec.unmounts, 2)
345
-}
346
-
347
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverDeleteContainer(c *testing.T) {
348
-	s.d.StartWithBusybox(c)
349
-
350
-	out, err := s.d.Cmd("run", "--name", "vol-test1", "-v", "/foo", "--volume-driver", volumePluginName, "busybox:latest")
351
-	assert.NilError(c, err, out)
352
-
353
-	out, err = s.d.Cmd("rm", "-fv", "vol-test1")
354
-	assert.NilError(c, err, out)
355
-
356
-	assert.Equal(c, s.ec.activations, 1)
357
-	assert.Equal(c, s.ec.creations, 1)
358
-	assert.Equal(c, s.ec.removals, 1)
359
-	assert.Equal(c, s.ec.mounts, 1)
360
-	assert.Equal(c, s.ec.unmounts, 1)
361
-}
362
-
363
-func hostVolumePath(name string) string {
364
-	return fmt.Sprintf("/var/lib/docker/volumes/%s", name)
365
-}
366
-
367
-// Make sure a request to use a down driver doesn't block other requests
368
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *testing.T) {
369
-	specPath := "/etc/docker/plugins/down-driver.spec"
370
-	err := ioutil.WriteFile(specPath, []byte("tcp://127.0.0.7:9999"), 0644)
371
-	assert.NilError(c, err)
372
-	defer os.RemoveAll(specPath)
373
-
374
-	chCmd1 := make(chan struct{})
375
-	chCmd2 := make(chan error)
376
-	cmd1 := exec.Command(dockerBinary, "volume", "create", "-d", "down-driver")
377
-	cmd2 := exec.Command(dockerBinary, "volume", "create")
378
-
379
-	assert.Assert(c, cmd1.Start() == nil)
380
-	defer cmd1.Process.Kill()
381
-	time.Sleep(100 * time.Millisecond) // ensure API has been called
382
-	assert.Assert(c, cmd2.Start() == nil)
383
-
384
-	go func() {
385
-		cmd1.Wait()
386
-		close(chCmd1)
387
-	}()
388
-	go func() {
389
-		chCmd2 <- cmd2.Wait()
390
-	}()
391
-
392
-	select {
393
-	case <-chCmd1:
394
-		cmd2.Process.Kill()
395
-		c.Fatalf("volume create with down driver finished unexpectedly")
396
-	case err := <-chCmd2:
397
-		assert.NilError(c, err)
398
-	case <-time.After(5 * time.Second):
399
-		cmd2.Process.Kill()
400
-		c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
401
-	}
402
-}
403
-
404
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverRetryNotImmediatelyExists(c *testing.T) {
405
-	s.d.StartWithBusybox(c)
406
-	driverName := "test-external-volume-driver-retry"
407
-
408
-	errchan := make(chan error)
409
-	started := make(chan struct{})
410
-	go func() {
411
-		close(started)
412
-		if out, err := s.d.Cmd("run", "--rm", "--name", "test-data-retry", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", driverName, "busybox:latest"); err != nil {
413
-			errchan <- fmt.Errorf("%v:\n%s", err, out)
414
-		}
415
-		close(errchan)
416
-	}()
417
-
418
-	<-started
419
-	// wait for a retry to occur, then create spec to allow plugin to register
420
-	time.Sleep(2 * time.Second)
421
-	p := newVolumePlugin(c, driverName)
422
-	defer p.Close()
423
-
424
-	select {
425
-	case err := <-errchan:
426
-		assert.NilError(c, err)
427
-	case <-time.After(8 * time.Second):
428
-		c.Fatal("volume creates fail when plugin not immediately available")
429
-	}
430
-
431
-	_, err := s.d.Cmd("volume", "rm", "external-volume-test")
432
-	assert.NilError(c, err)
433
-
434
-	assert.Equal(c, p.ec.activations, 1)
435
-	assert.Equal(c, p.ec.creations, 1)
436
-	assert.Equal(c, p.ec.removals, 1)
437
-	assert.Equal(c, p.ec.mounts, 1)
438
-	assert.Equal(c, p.ec.unmounts, 1)
439
-}
440
-
441
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverBindExternalVolume(c *testing.T) {
442
-	dockerCmd(c, "volume", "create", "-d", volumePluginName, "foo")
443
-	dockerCmd(c, "run", "-d", "--name", "testing", "-v", "foo:/bar", "busybox", "top")
444
-
445
-	var mounts []struct {
446
-		Name   string
447
-		Driver string
448
-	}
449
-	out := inspectFieldJSON(c, "testing", "Mounts")
450
-	assert.Assert(c, json.NewDecoder(strings.NewReader(out)).Decode(&mounts) == nil)
451
-	assert.Equal(c, len(mounts), 1, fmt.Sprintf("%s", out))
452
-	assert.Equal(c, mounts[0].Name, "foo")
453
-	assert.Equal(c, mounts[0].Driver, volumePluginName)
454
-}
455
-
456
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverList(c *testing.T) {
457
-	dockerCmd(c, "volume", "create", "-d", volumePluginName, "abc3")
458
-	out, _ := dockerCmd(c, "volume", "ls")
459
-	ls := strings.Split(strings.TrimSpace(out), "\n")
460
-	assert.Equal(c, len(ls), 2, fmt.Sprintf("\n%s", out))
461
-
462
-	vol := strings.Fields(ls[len(ls)-1])
463
-	assert.Equal(c, len(vol), 2, fmt.Sprintf("%v", vol))
464
-	assert.Equal(c, vol[0], volumePluginName)
465
-	assert.Equal(c, vol[1], "abc3")
466
-
467
-	assert.Equal(c, s.ec.lists, 1)
468
-}
469
-
470
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGet(c *testing.T) {
471
-	out, _, err := dockerCmdWithError("volume", "inspect", "dummy")
472
-	assert.ErrorContains(c, err, "", out)
473
-	assert.Assert(c, strings.Contains(out, "No such volume"))
474
-	assert.Equal(c, s.ec.gets, 1)
475
-
476
-	dockerCmd(c, "volume", "create", "test", "-d", volumePluginName)
477
-	out, _ = dockerCmd(c, "volume", "inspect", "test")
478
-
479
-	type vol struct {
480
-		Status map[string]string
481
-	}
482
-	var st []vol
483
-
484
-	assert.Assert(c, json.Unmarshal([]byte(out), &st) == nil)
485
-	assert.Equal(c, len(st), 1)
486
-	assert.Equal(c, len(st[0].Status), 1, fmt.Sprintf("%v", st[0]))
487
-	assert.Equal(c, st[0].Status["Hello"], "world", fmt.Sprintf("%v", st[0].Status))
488
-}
489
-
490
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverWithDaemonRestart(c *testing.T) {
491
-	dockerCmd(c, "volume", "create", "-d", volumePluginName, "abc1")
492
-	s.d.Restart(c)
493
-
494
-	dockerCmd(c, "run", "--name=test", "-v", "abc1:/foo", "busybox", "true")
495
-	var mounts []types.MountPoint
496
-	inspectFieldAndUnmarshall(c, "test", "Mounts", &mounts)
497
-	assert.Equal(c, len(mounts), 1)
498
-	assert.Equal(c, mounts[0].Driver, volumePluginName)
499
-}
500
-
501
-// Ensures that the daemon handles when the plugin responds to a `Get` request with a null volume and a null error.
502
-// Prior the daemon would panic in this scenario.
503
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGetEmptyResponse(c *testing.T) {
504
-	s.d.Start(c)
505
-
506
-	out, err := s.d.Cmd("volume", "create", "-d", volumePluginName, "abc2", "--opt", "ninja=1")
507
-	assert.NilError(c, err, out)
508
-
509
-	out, err = s.d.Cmd("volume", "inspect", "abc2")
510
-	assert.ErrorContains(c, err, "", out)
511
-	assert.Assert(c, strings.Contains(out, "No such volume"))
512
-}
513
-
514
-// Ensure only cached paths are used in volume list to prevent N+1 calls to `VolumeDriver.Path`
515
-//
516
-// TODO(@cpuguy83): This test is testing internal implementation. In all the cases here, there may not even be a path
517
-// 	available because the volume is not even mounted. Consider removing this test.
518
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverPathCalls(c *testing.T) {
519
-	s.d.Start(c)
520
-	assert.Equal(c, s.ec.paths, 0)
521
-
522
-	out, err := s.d.Cmd("volume", "create", "test", "--driver=test-external-volume-driver")
523
-	assert.NilError(c, err, out)
524
-	assert.Equal(c, s.ec.paths, 0)
525
-
526
-	out, err = s.d.Cmd("volume", "ls")
527
-	assert.NilError(c, err, out)
528
-	assert.Equal(c, s.ec.paths, 0)
529
-}
530
-
531
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverMountID(c *testing.T) {
532
-	s.d.StartWithBusybox(c)
533
-
534
-	out, err := s.d.Cmd("run", "--rm", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
535
-	assert.NilError(c, err, out)
536
-	assert.Assert(c, strings.TrimSpace(out) != "")
537
-}
538
-
539
-// Check that VolumeDriver.Capabilities gets called, and only called once
540
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverCapabilities(c *testing.T) {
541
-	s.d.Start(c)
542
-	assert.Equal(c, s.ec.caps, 0)
543
-
544
-	for i := 0; i < 3; i++ {
545
-		out, err := s.d.Cmd("volume", "create", "-d", volumePluginName, fmt.Sprintf("test%d", i))
546
-		assert.NilError(c, err, out)
547
-		assert.Equal(c, s.ec.caps, 1)
548
-		out, err = s.d.Cmd("volume", "inspect", "--format={{.Scope}}", fmt.Sprintf("test%d", i))
549
-		assert.NilError(c, err)
550
-		assert.Equal(c, strings.TrimSpace(out), volume.GlobalScope)
551
-	}
552
-}
553
-
554
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverOutOfBandDelete(c *testing.T) {
555
-	driverName := stringid.GenerateRandomID()
556
-	p := newVolumePlugin(c, driverName)
557
-	defer p.Close()
558
-
559
-	s.d.StartWithBusybox(c)
560
-
561
-	out, err := s.d.Cmd("volume", "create", "-d", driverName, "--name", "test")
562
-	assert.NilError(c, err, out)
563
-
564
-	out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
565
-	assert.ErrorContains(c, err, "", out)
566
-	assert.Assert(c, strings.Contains(out, "must be unique"))
567
-	// simulate out of band volume deletion on plugin level
568
-	delete(p.vols, "test")
569
-
570
-	// test re-create with same driver
571
-	out, err = s.d.Cmd("volume", "create", "-d", driverName, "--opt", "foo=bar", "--name", "test")
572
-	assert.NilError(c, err, out)
573
-	out, err = s.d.Cmd("volume", "inspect", "test")
574
-	assert.NilError(c, err, out)
575
-
576
-	var vs []types.Volume
577
-	err = json.Unmarshal([]byte(out), &vs)
578
-	assert.NilError(c, err)
579
-	assert.Equal(c, len(vs), 1)
580
-	assert.Equal(c, vs[0].Driver, driverName)
581
-	assert.Assert(c, vs[0].Options != nil)
582
-	assert.Equal(c, vs[0].Options["foo"], "bar")
583
-	assert.Equal(c, vs[0].Driver, driverName)
584
-
585
-	// simulate out of band volume deletion on plugin level
586
-	delete(p.vols, "test")
587
-
588
-	// test create with different driver
589
-	out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
590
-	assert.NilError(c, err, out)
591
-
592
-	out, err = s.d.Cmd("volume", "inspect", "test")
593
-	assert.NilError(c, err, out)
594
-	vs = nil
595
-	err = json.Unmarshal([]byte(out), &vs)
596
-	assert.NilError(c, err)
597
-	assert.Equal(c, len(vs), 1)
598
-	assert.Equal(c, len(vs[0].Options), 0)
599
-	assert.Equal(c, vs[0].Driver, "local")
600
-}
601
-
602
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnMountFail(c *testing.T) {
603
-	s.d.StartWithBusybox(c)
604
-	s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--opt=invalidOption=1", "--name=testumount")
605
-
606
-	out, _ := s.d.Cmd("run", "-v", "testumount:/foo", "busybox", "true")
607
-	assert.Equal(c, s.ec.unmounts, 0, fmt.Sprintf("%s", out))
608
-	out, _ = s.d.Cmd("run", "-w", "/foo", "-v", "testumount:/foo", "busybox", "true")
609
-	assert.Equal(c, s.ec.unmounts, 0, fmt.Sprintf("%s", out))
610
-}
611
-
612
-func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnCp(c *testing.T) {
613
-	s.d.StartWithBusybox(c)
614
-	s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--name=test")
615
-
616
-	out, _ := s.d.Cmd("run", "-d", "--name=test", "-v", "test:/foo", "busybox", "/bin/sh", "-c", "touch /test && top")
617
-	assert.Equal(c, s.ec.mounts, 1, fmt.Sprintf("%s", out))
618
-
619
-	out, _ = s.d.Cmd("cp", "test:/test", "/tmp/test")
620
-	assert.Equal(c, s.ec.mounts, 2, fmt.Sprintf("%s", out))
621
-	assert.Equal(c, s.ec.unmounts, 1, fmt.Sprintf("%s", out))
622
-
623
-	out, _ = s.d.Cmd("kill", "test")
624
-	assert.Equal(c, s.ec.unmounts, 2, fmt.Sprintf("%s", out))
625
-}
626 1
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+package main
1
+
2
+import (
3
+	"net/http/httptest"
4
+
5
+	"github.com/docker/docker/integration-cli/daemon"
6
+)
7
+
8
+type DockerNetworkSuite struct {
9
+	server *httptest.Server
10
+	ds     *DockerSuite
11
+	d      *daemon.Daemon
12
+}
... ...
@@ -37,16 +37,6 @@ const dummyIPAMDriver = "dummy-ipam-driver"
37 37
 
38 38
 var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest
39 39
 
40
-func init() {
41
-	/*check.Suite(&DockerNetworkSuite{ds: &DockerSuite{}})*/
42
-}
43
-
44
-type DockerNetworkSuite struct {
45
-	server *httptest.Server
46
-	ds     *DockerSuite
47
-	d      *daemon.Daemon
48
-}
49
-
50 40
 func (s *DockerNetworkSuite) SetUpTest(c *testing.T) {
51 41
 	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
52 42
 }
... ...
@@ -3,7 +3,6 @@ package main
3 3
 import (
4 4
 	"fmt"
5 5
 	"os/exec"
6
-	"runtime"
7 6
 	"strings"
8 7
 	"testing"
9 8
 
... ...
@@ -12,14 +11,6 @@ import (
12 12
 	"gotest.tools/assert"
13 13
 )
14 14
 
15
-func init() {
16
-	// FIXME. Temporarily turning this off for Windows as GH16039 was breaking
17
-	// Windows to Linux CI @icecrime
18
-	if runtime.GOOS != "windows" {
19
-		/*check.Suite(newDockerHubPullSuite())*/
20
-	}
21
-}
22
-
23 15
 // DockerHubPullSuite provides an isolated daemon that doesn't have all the
24 16
 // images that are baked into our 'global' test environment daemon (e.g.,
25 17
 // busybox, httpserver, ...).
... ...
@@ -3,16 +3,17 @@ package discovery // import "github.com/docker/docker/pkg/discovery"
3 3
 import (
4 4
 	"testing"
5 5
 
6
+	"github.com/docker/docker/internal/test/suite"
6 7
 	"gotest.tools/assert"
7 8
 )
8 9
 
9 10
 // Hook up gocheck into the "go test" runner.
10
-func Test(t *testing.T) { /*check.TestingT(t)*/ }
11
+func Test(t *testing.T) {
12
+	suite.Run(t, &DiscoverySuite{})
13
+}
11 14
 
12 15
 type DiscoverySuite struct{}
13 16
 
14
-/*check.Suite(&DiscoverySuite{})*/
15
-
16 17
 func (s *DiscoverySuite) TestNewEntry(c *testing.T) {
17 18
 	entry, err := NewEntry("127.0.0.1:2375")
18 19
 	assert.Assert(c, err == nil)
... ...
@@ -5,17 +5,18 @@ import (
5 5
 	"os"
6 6
 	"testing"
7 7
 
8
+	"github.com/docker/docker/internal/test/suite"
8 9
 	"github.com/docker/docker/pkg/discovery"
9 10
 	"gotest.tools/assert"
10 11
 )
11 12
 
12 13
 // Hook up gocheck into the "go test" runner.
13
-func Test(t *testing.T) { /*check.TestingT(t)*/ }
14
+func Test(t *testing.T) {
15
+	suite.Run(t, &DiscoverySuite{})
16
+}
14 17
 
15 18
 type DiscoverySuite struct{}
16 19
 
17
-/*check.Suite(&DiscoverySuite{})*/
18
-
19 20
 func (s *DiscoverySuite) TestInitialize(c *testing.T) {
20 21
 	d := &Discovery{}
21 22
 	d.Initialize("/path/to/file", 1000, 0, nil)
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"testing"
9 9
 	"time"
10 10
 
11
+	"github.com/docker/docker/internal/test/suite"
11 12
 	"github.com/docker/docker/pkg/discovery"
12 13
 	"github.com/docker/libkv"
13 14
 	"github.com/docker/libkv/store"
... ...
@@ -15,12 +16,12 @@ import (
15 15
 )
16 16
 
17 17
 // Hook up gocheck into the "go test" runner.
18
-func Test(t *testing.T) { /*check.TestingT(t)*/ }
18
+func Test(t *testing.T) {
19
+	suite.Run(t, &DiscoverySuite{})
20
+}
19 21
 
20 22
 type DiscoverySuite struct{}
21 23
 
22
-/*check.Suite(&DiscoverySuite{})*/
23
-
24 24
 func (ds *DiscoverySuite) TestInitialize(c *testing.T) {
25 25
 	storeMock := &FakeStore{
26 26
 		Endpoints: []string{"127.0.0.1"},
... ...
@@ -3,17 +3,18 @@ package memory // import "github.com/docker/docker/pkg/discovery/memory"
3 3
 import (
4 4
 	"testing"
5 5
 
6
+	"github.com/docker/docker/internal/test/suite"
6 7
 	"github.com/docker/docker/pkg/discovery"
7 8
 	"gotest.tools/assert"
8 9
 )
9 10
 
10 11
 // Hook up gocheck into the "go test" runner.
11
-func Test(t *testing.T) { /*check.TestingT(t)*/ }
12
+func Test(t *testing.T) {
13
+	suite.Run(t, &discoverySuite{})
14
+}
12 15
 
13 16
 type discoverySuite struct{}
14 17
 
15
-/*check.Suite(&discoverySuite{})*/
16
-
17 18
 func (s *discoverySuite) TestWatch(c *testing.T) {
18 19
 	d := &Discovery{}
19 20
 	d.Initialize("foo", 1000, 0, nil)
... ...
@@ -3,17 +3,18 @@ package nodes // import "github.com/docker/docker/pkg/discovery/nodes"
3 3
 import (
4 4
 	"testing"
5 5
 
6
+	"github.com/docker/docker/internal/test/suite"
6 7
 	"github.com/docker/docker/pkg/discovery"
7 8
 	"gotest.tools/assert"
8 9
 )
9 10
 
10 11
 // Hook up gocheck into the "go test" runner.
11
-func Test(t *testing.T) { /*check.TestingT(t)*/ }
12
+func Test(t *testing.T) {
13
+	suite.Run(t, &DiscoverySuite{})
14
+}
12 15
 
13 16
 type DiscoverySuite struct{}
14 17
 
15
-/*check.Suite(&DiscoverySuite{})*/
16
-
17 18
 func (s *DiscoverySuite) TestInitialize(c *testing.T) {
18 19
 	d := &Discovery{}
19 20
 	d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0, nil)