github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/volume/service/store_test.go (about) 1 package service // import "github.com/demonoid81/moby/volume/service" 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "net" 9 "os" 10 "strings" 11 "testing" 12 13 "github.com/demonoid81/moby/volume" 14 volumedrivers "github.com/demonoid81/moby/volume/drivers" 15 "github.com/demonoid81/moby/volume/service/opts" 16 volumetestutils "github.com/demonoid81/moby/volume/testutils" 17 "github.com/google/go-cmp/cmp" 18 "gotest.tools/v3/assert" 19 is "gotest.tools/v3/assert/cmp" 20 ) 21 22 func TestCreate(t *testing.T) { 23 t.Parallel() 24 25 s, cleanup := setupTest(t) 26 defer cleanup() 27 s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake") 28 29 ctx := context.Background() 30 v, err := s.Create(ctx, "fake1", "fake") 31 if err != nil { 32 t.Fatal(err) 33 } 34 if v.Name() != "fake1" { 35 t.Fatalf("Expected fake1 volume, got %v", v) 36 } 37 if l, _, _ := s.Find(ctx, nil); len(l) != 1 { 38 t.Fatalf("Expected 1 volume in the store, got %v: %v", len(l), l) 39 } 40 41 if _, err := s.Create(ctx, "none", "none"); err == nil { 42 t.Fatalf("Expected unknown driver error, got nil") 43 } 44 45 _, err = s.Create(ctx, "fakeerror", "fake", opts.WithCreateOptions(map[string]string{"error": "create error"})) 46 expected := &OpErr{Op: "create", Name: "fakeerror", Err: errors.New("create error")} 47 if err != nil && err.Error() != expected.Error() { 48 t.Fatalf("Expected create fakeError: create error, got %v", err) 49 } 50 } 51 52 func TestRemove(t *testing.T) { 53 t.Parallel() 54 55 s, cleanup := setupTest(t) 56 defer cleanup() 57 58 s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake") 59 s.drivers.Register(volumetestutils.NewFakeDriver("noop"), "noop") 60 61 ctx := context.Background() 62 63 // doing string compare here since this error comes directly from the driver 64 expected := "no such volume" 65 var v volume.Volume = volumetestutils.NoopVolume{} 66 if err := s.Remove(ctx, v); err == nil || !strings.Contains(err.Error(), expected) { 67 t.Fatalf("Expected error %q, got %v", expected, err) 68 } 69 70 v, err := s.Create(ctx, "fake1", "fake", opts.WithCreateReference("fake")) 71 if err != nil { 72 t.Fatal(err) 73 } 74 75 if err := s.Remove(ctx, v); !IsInUse(err) { 76 t.Fatalf("Expected ErrVolumeInUse error, got %v", err) 77 } 78 s.Release(ctx, v.Name(), "fake") 79 if err := s.Remove(ctx, v); err != nil { 80 t.Fatal(err) 81 } 82 if l, _, _ := s.Find(ctx, nil); len(l) != 0 { 83 t.Fatalf("Expected 0 volumes in the store, got %v, %v", len(l), l) 84 } 85 } 86 87 func TestList(t *testing.T) { 88 t.Parallel() 89 90 dir, err := ioutil.TempDir("", "test-list") 91 assert.NilError(t, err) 92 defer os.RemoveAll(dir) 93 94 drivers := volumedrivers.NewStore(nil) 95 drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake") 96 drivers.Register(volumetestutils.NewFakeDriver("fake2"), "fake2") 97 98 s, err := NewStore(dir, drivers) 99 assert.NilError(t, err) 100 101 ctx := context.Background() 102 if _, err := s.Create(ctx, "test", "fake"); err != nil { 103 t.Fatal(err) 104 } 105 if _, err := s.Create(ctx, "test2", "fake2"); err != nil { 106 t.Fatal(err) 107 } 108 109 ls, _, err := s.Find(ctx, nil) 110 if err != nil { 111 t.Fatal(err) 112 } 113 if len(ls) != 2 { 114 t.Fatalf("expected 2 volumes, got: %d", len(ls)) 115 } 116 if err := s.Shutdown(); err != nil { 117 t.Fatal(err) 118 } 119 120 // and again with a new store 121 s, err = NewStore(dir, drivers) 122 if err != nil { 123 t.Fatal(err) 124 } 125 ls, _, err = s.Find(ctx, nil) 126 if err != nil { 127 t.Fatal(err) 128 } 129 if len(ls) != 2 { 130 t.Fatalf("expected 2 volumes, got: %d", len(ls)) 131 } 132 } 133 134 func TestFindByDriver(t *testing.T) { 135 t.Parallel() 136 s, cleanup := setupTest(t) 137 defer cleanup() 138 139 assert.Assert(t, s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")) 140 assert.Assert(t, s.drivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")) 141 142 ctx := context.Background() 143 _, err := s.Create(ctx, "fake1", "fake") 144 assert.NilError(t, err) 145 146 _, err = s.Create(ctx, "fake2", "fake") 147 assert.NilError(t, err) 148 149 _, err = s.Create(ctx, "fake3", "noop") 150 assert.NilError(t, err) 151 152 l, _, err := s.Find(ctx, ByDriver("fake")) 153 assert.NilError(t, err) 154 assert.Equal(t, len(l), 2) 155 156 l, _, err = s.Find(ctx, ByDriver("noop")) 157 assert.NilError(t, err) 158 assert.Equal(t, len(l), 1) 159 160 l, _, err = s.Find(ctx, ByDriver("nosuchdriver")) 161 assert.NilError(t, err) 162 assert.Equal(t, len(l), 0) 163 } 164 165 func TestFindByReferenced(t *testing.T) { 166 t.Parallel() 167 s, cleanup := setupTest(t) 168 defer cleanup() 169 170 s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake") 171 s.drivers.Register(volumetestutils.NewFakeDriver("noop"), "noop") 172 173 ctx := context.Background() 174 if _, err := s.Create(ctx, "fake1", "fake", opts.WithCreateReference("volReference")); err != nil { 175 t.Fatal(err) 176 } 177 if _, err := s.Create(ctx, "fake2", "fake"); err != nil { 178 t.Fatal(err) 179 } 180 181 dangling, _, err := s.Find(ctx, ByReferenced(false)) 182 assert.NilError(t, err) 183 assert.Assert(t, len(dangling) == 1) 184 assert.Check(t, dangling[0].Name() == "fake2") 185 186 used, _, err := s.Find(ctx, ByReferenced(true)) 187 assert.NilError(t, err) 188 assert.Assert(t, len(used) == 1) 189 assert.Check(t, used[0].Name() == "fake1") 190 } 191 192 func TestDerefMultipleOfSameRef(t *testing.T) { 193 t.Parallel() 194 s, cleanup := setupTest(t) 195 defer cleanup() 196 s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake") 197 198 ctx := context.Background() 199 v, err := s.Create(ctx, "fake1", "fake", opts.WithCreateReference("volReference")) 200 if err != nil { 201 t.Fatal(err) 202 } 203 204 if _, err := s.Get(ctx, "fake1", opts.WithGetDriver("fake"), opts.WithGetReference("volReference")); err != nil { 205 t.Fatal(err) 206 } 207 208 s.Release(ctx, v.Name(), "volReference") 209 if err := s.Remove(ctx, v); err != nil { 210 t.Fatal(err) 211 } 212 } 213 214 func TestCreateKeepOptsLabelsWhenExistsRemotely(t *testing.T) { 215 t.Parallel() 216 s, cleanup := setupTest(t) 217 defer cleanup() 218 219 vd := volumetestutils.NewFakeDriver("fake") 220 s.drivers.Register(vd, "fake") 221 222 // Create a volume in the driver directly 223 if _, err := vd.Create("foo", nil); err != nil { 224 t.Fatal(err) 225 } 226 227 ctx := context.Background() 228 v, err := s.Create(ctx, "foo", "fake", opts.WithCreateLabels(map[string]string{"hello": "world"})) 229 if err != nil { 230 t.Fatal(err) 231 } 232 233 switch dv := v.(type) { 234 case volume.DetailedVolume: 235 if dv.Labels()["hello"] != "world" { 236 t.Fatalf("labels don't match") 237 } 238 default: 239 t.Fatalf("got unexpected type: %T", v) 240 } 241 } 242 243 func TestDefererencePluginOnCreateError(t *testing.T) { 244 t.Parallel() 245 246 var ( 247 l net.Listener 248 err error 249 ) 250 251 for i := 32768; l == nil && i < 40000; i++ { 252 l, err = net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", i)) 253 } 254 if l == nil { 255 t.Fatalf("could not create listener: %v", err) 256 } 257 defer l.Close() 258 259 s, cleanup := setupTest(t) 260 defer cleanup() 261 262 d := volumetestutils.NewFakeDriver("TestDefererencePluginOnCreateError") 263 p, err := volumetestutils.MakeFakePlugin(d, l) 264 if err != nil { 265 t.Fatal(err) 266 } 267 268 pg := volumetestutils.NewFakePluginGetter(p) 269 s.drivers = volumedrivers.NewStore(pg) 270 271 ctx := context.Background() 272 // create a good volume so we have a plugin reference 273 _, err = s.Create(ctx, "fake1", d.Name()) 274 if err != nil { 275 t.Fatal(err) 276 } 277 278 // Now create another one expecting an error 279 _, err = s.Create(ctx, "fake2", d.Name(), opts.WithCreateOptions(map[string]string{"error": "some error"})) 280 if err == nil || !strings.Contains(err.Error(), "some error") { 281 t.Fatalf("expected an error on create: %v", err) 282 } 283 284 // There should be only 1 plugin reference 285 if refs := volumetestutils.FakeRefs(p); refs != 1 { 286 t.Fatalf("expected 1 plugin reference, got: %d", refs) 287 } 288 } 289 290 func TestRefDerefRemove(t *testing.T) { 291 t.Parallel() 292 293 driverName := "test-ref-deref-remove" 294 s, cleanup := setupTest(t) 295 defer cleanup() 296 s.drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName) 297 298 ctx := context.Background() 299 v, err := s.Create(ctx, "test", driverName, opts.WithCreateReference("test-ref")) 300 assert.NilError(t, err) 301 302 err = s.Remove(ctx, v) 303 assert.Assert(t, is.ErrorContains(err, "")) 304 assert.Equal(t, errVolumeInUse, err.(*OpErr).Err) 305 306 s.Release(ctx, v.Name(), "test-ref") 307 err = s.Remove(ctx, v) 308 assert.NilError(t, err) 309 } 310 311 func TestGet(t *testing.T) { 312 t.Parallel() 313 314 driverName := "test-get" 315 s, cleanup := setupTest(t) 316 defer cleanup() 317 s.drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName) 318 319 ctx := context.Background() 320 _, err := s.Get(ctx, "not-exist") 321 assert.Assert(t, is.ErrorContains(err, "")) 322 assert.Equal(t, errNoSuchVolume, err.(*OpErr).Err) 323 324 v1, err := s.Create(ctx, "test", driverName, opts.WithCreateLabels(map[string]string{"a": "1"})) 325 assert.NilError(t, err) 326 327 v2, err := s.Get(ctx, "test") 328 assert.NilError(t, err) 329 assert.DeepEqual(t, v1, v2, cmpVolume) 330 331 dv := v2.(volume.DetailedVolume) 332 assert.Equal(t, "1", dv.Labels()["a"]) 333 334 err = s.Remove(ctx, v1) 335 assert.NilError(t, err) 336 } 337 338 func TestGetWithReference(t *testing.T) { 339 t.Parallel() 340 341 driverName := "test-get-with-ref" 342 s, cleanup := setupTest(t) 343 defer cleanup() 344 s.drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName) 345 346 ctx := context.Background() 347 _, err := s.Get(ctx, "not-exist", opts.WithGetDriver(driverName), opts.WithGetReference("test-ref")) 348 assert.Assert(t, is.ErrorContains(err, "")) 349 350 v1, err := s.Create(ctx, "test", driverName, opts.WithCreateLabels(map[string]string{"a": "1"})) 351 assert.NilError(t, err) 352 353 v2, err := s.Get(ctx, "test", opts.WithGetDriver(driverName), opts.WithGetReference("test-ref")) 354 assert.NilError(t, err) 355 assert.DeepEqual(t, v1, v2, cmpVolume) 356 357 err = s.Remove(ctx, v2) 358 assert.Assert(t, is.ErrorContains(err, "")) 359 assert.Equal(t, errVolumeInUse, err.(*OpErr).Err) 360 361 s.Release(ctx, v2.Name(), "test-ref") 362 err = s.Remove(ctx, v2) 363 assert.NilError(t, err) 364 } 365 366 var cmpVolume = cmp.AllowUnexported(volumetestutils.FakeVolume{}, volumeWrapper{}) 367 368 func setupTest(t *testing.T) (*VolumeStore, func()) { 369 t.Helper() 370 371 dirName := strings.Replace(t.Name(), string(os.PathSeparator), "_", -1) 372 dir, err := ioutil.TempDir("", dirName) 373 assert.NilError(t, err) 374 375 cleanup := func() { 376 t.Helper() 377 err := os.RemoveAll(dir) 378 assert.Check(t, err) 379 } 380 381 s, err := NewStore(dir, volumedrivers.NewStore(nil)) 382 assert.Check(t, err) 383 return s, func() { 384 s.Shutdown() 385 cleanup() 386 } 387 } 388 389 func TestFilterFunc(t *testing.T) { 390 testDriver := volumetestutils.NewFakeDriver("test") 391 testVolume, err := testDriver.Create("test", nil) 392 assert.NilError(t, err) 393 testVolume2, err := testDriver.Create("test2", nil) 394 assert.NilError(t, err) 395 testVolume3, err := testDriver.Create("test3", nil) 396 assert.NilError(t, err) 397 398 for _, test := range []struct { 399 vols []volume.Volume 400 fn filterFunc 401 desc string 402 expect []volume.Volume 403 }{ 404 {desc: "test nil list", vols: nil, expect: nil, fn: func(volume.Volume) bool { return true }}, 405 {desc: "test empty list", vols: []volume.Volume{}, expect: []volume.Volume{}, fn: func(volume.Volume) bool { return true }}, 406 {desc: "test filter non-empty to empty", vols: []volume.Volume{testVolume}, expect: []volume.Volume{}, fn: func(volume.Volume) bool { return false }}, 407 {desc: "test nothing to fitler non-empty list", vols: []volume.Volume{testVolume}, expect: []volume.Volume{testVolume}, fn: func(volume.Volume) bool { return true }}, 408 {desc: "test filter some", vols: []volume.Volume{testVolume, testVolume2}, expect: []volume.Volume{testVolume}, fn: func(v volume.Volume) bool { return v.Name() == testVolume.Name() }}, 409 {desc: "test filter middle", vols: []volume.Volume{testVolume, testVolume2, testVolume3}, expect: []volume.Volume{testVolume, testVolume3}, fn: func(v volume.Volume) bool { return v.Name() != testVolume2.Name() }}, 410 {desc: "test filter middle and last", vols: []volume.Volume{testVolume, testVolume2, testVolume3}, expect: []volume.Volume{testVolume}, fn: func(v volume.Volume) bool { return v.Name() != testVolume2.Name() && v.Name() != testVolume3.Name() }}, 411 {desc: "test filter first and last", vols: []volume.Volume{testVolume, testVolume2, testVolume3}, expect: []volume.Volume{testVolume2}, fn: func(v volume.Volume) bool { return v.Name() != testVolume.Name() && v.Name() != testVolume3.Name() }}, 412 } { 413 t.Run(test.desc, func(t *testing.T) { 414 test := test 415 t.Parallel() 416 417 filter(&test.vols, test.fn) 418 assert.DeepEqual(t, test.vols, test.expect, cmpVolume) 419 }) 420 } 421 }