github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/volume/local/local_test.go (about) 1 package local // import "github.com/demonoid81/moby/volume/local" 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "reflect" 8 "runtime" 9 "strings" 10 "testing" 11 12 "github.com/demonoid81/moby/pkg/idtools" 13 "github.com/moby/sys/mountinfo" 14 "gotest.tools/v3/skip" 15 ) 16 17 func TestGetAddress(t *testing.T) { 18 cases := map[string]string{ 19 "addr=11.11.11.1": "11.11.11.1", 20 " ": "", 21 "addr=": "", 22 "addr=2001:db8::68": "2001:db8::68", 23 } 24 for name, success := range cases { 25 v := getAddress(name) 26 if v != success { 27 t.Errorf("Test case failed for %s actual: %s expected : %s", name, v, success) 28 } 29 } 30 31 } 32 33 func TestRemove(t *testing.T) { 34 skip.If(t, runtime.GOOS == "windows", "FIXME: investigate why this test fails on CI") 35 rootDir, err := ioutil.TempDir("", "local-volume-test") 36 if err != nil { 37 t.Fatal(err) 38 } 39 defer os.RemoveAll(rootDir) 40 41 r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 42 if err != nil { 43 t.Fatal(err) 44 } 45 46 vol, err := r.Create("testing", nil) 47 if err != nil { 48 t.Fatal(err) 49 } 50 51 if err := r.Remove(vol); err != nil { 52 t.Fatal(err) 53 } 54 55 vol, err = r.Create("testing2", nil) 56 if err != nil { 57 t.Fatal(err) 58 } 59 if err := os.RemoveAll(vol.Path()); err != nil { 60 t.Fatal(err) 61 } 62 63 if err := r.Remove(vol); err != nil { 64 t.Fatal(err) 65 } 66 67 if _, err := os.Stat(vol.Path()); err != nil && !os.IsNotExist(err) { 68 t.Fatal("volume dir not removed") 69 } 70 71 if l, _ := r.List(); len(l) != 0 { 72 t.Fatal("expected there to be no volumes") 73 } 74 } 75 76 func TestInitializeWithVolumes(t *testing.T) { 77 rootDir, err := ioutil.TempDir("", "local-volume-test") 78 if err != nil { 79 t.Fatal(err) 80 } 81 defer os.RemoveAll(rootDir) 82 83 r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 84 if err != nil { 85 t.Fatal(err) 86 } 87 88 vol, err := r.Create("testing", nil) 89 if err != nil { 90 t.Fatal(err) 91 } 92 93 r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 v, err := r.Get(vol.Name()) 99 if err != nil { 100 t.Fatal(err) 101 } 102 103 if v.Path() != vol.Path() { 104 t.Fatal("expected to re-initialize root with existing volumes") 105 } 106 } 107 108 func TestCreate(t *testing.T) { 109 rootDir, err := ioutil.TempDir("", "local-volume-test") 110 if err != nil { 111 t.Fatal(err) 112 } 113 defer os.RemoveAll(rootDir) 114 115 r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 116 if err != nil { 117 t.Fatal(err) 118 } 119 120 cases := map[string]bool{ 121 "name": true, 122 "name-with-dash": true, 123 "name_with_underscore": true, 124 "name/with/slash": false, 125 "name/with/../../slash": false, 126 "./name": false, 127 "../name": false, 128 "./": false, 129 "../": false, 130 "~": false, 131 ".": false, 132 "..": false, 133 "...": false, 134 } 135 136 for name, success := range cases { 137 v, err := r.Create(name, nil) 138 if success { 139 if err != nil { 140 t.Fatal(err) 141 } 142 if v.Name() != name { 143 t.Fatalf("Expected volume with name %s, got %s", name, v.Name()) 144 } 145 } else { 146 if err == nil { 147 t.Fatalf("Expected error creating volume with name %s, got nil", name) 148 } 149 } 150 } 151 152 _, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 153 if err != nil { 154 t.Fatal(err) 155 } 156 } 157 158 func TestValidateName(t *testing.T) { 159 r := &Root{} 160 names := map[string]bool{ 161 "x": false, 162 "/testvol": false, 163 "thing.d": true, 164 "hello-world": true, 165 "./hello": false, 166 ".hello": false, 167 } 168 169 for vol, expected := range names { 170 err := r.validateName(vol) 171 if expected && err != nil { 172 t.Fatalf("expected %s to be valid got %v", vol, err) 173 } 174 if !expected && err == nil { 175 t.Fatalf("expected %s to be invalid", vol) 176 } 177 } 178 } 179 180 func TestCreateWithOpts(t *testing.T) { 181 skip.If(t, runtime.GOOS == "windows") 182 skip.If(t, os.Getuid() != 0, "requires mounts") 183 rootDir, err := ioutil.TempDir("", "local-volume-test") 184 if err != nil { 185 t.Fatal(err) 186 } 187 defer os.RemoveAll(rootDir) 188 189 r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 190 if err != nil { 191 t.Fatal(err) 192 } 193 194 if _, err := r.Create("test", map[string]string{"invalidopt": "notsupported"}); err == nil { 195 t.Fatal("expected invalid opt to cause error") 196 } 197 198 vol, err := r.Create("test", map[string]string{"device": "tmpfs", "type": "tmpfs", "o": "size=1m,uid=1000"}) 199 if err != nil { 200 t.Fatal(err) 201 } 202 v := vol.(*localVolume) 203 204 dir, err := v.Mount("1234") 205 if err != nil { 206 t.Fatal(err) 207 } 208 defer func() { 209 if err := v.Unmount("1234"); err != nil { 210 t.Fatal(err) 211 } 212 }() 213 214 mountInfos, err := mountinfo.GetMounts(mountinfo.SingleEntryFilter(dir)) 215 if err != nil { 216 t.Fatal(err) 217 } 218 if len(mountInfos) != 1 { 219 t.Fatalf("expected 1 mount, found %d: %+v", len(mountInfos), mountInfos) 220 } 221 222 info := mountInfos[0] 223 t.Logf("%+v", info) 224 if info.Fstype != "tmpfs" { 225 t.Fatalf("expected tmpfs mount, got %q", info.Fstype) 226 } 227 if info.Source != "tmpfs" { 228 t.Fatalf("expected tmpfs mount, got %q", info.Source) 229 } 230 if !strings.Contains(info.VfsOpts, "uid=1000") { 231 t.Fatalf("expected mount info to have uid=1000: %q", info.VfsOpts) 232 } 233 if !strings.Contains(info.VfsOpts, "size=1024k") { 234 t.Fatalf("expected mount info to have size=1024k: %q", info.VfsOpts) 235 } 236 237 if v.active.count != 1 { 238 t.Fatalf("Expected active mount count to be 1, got %d", v.active.count) 239 } 240 241 // test double mount 242 if _, err := v.Mount("1234"); err != nil { 243 t.Fatal(err) 244 } 245 if v.active.count != 2 { 246 t.Fatalf("Expected active mount count to be 2, got %d", v.active.count) 247 } 248 249 if err := v.Unmount("1234"); err != nil { 250 t.Fatal(err) 251 } 252 if v.active.count != 1 { 253 t.Fatalf("Expected active mount count to be 1, got %d", v.active.count) 254 } 255 256 mounted, err := mountinfo.Mounted(v.path) 257 if err != nil { 258 t.Fatal(err) 259 } 260 if !mounted { 261 t.Fatal("expected mount to still be active") 262 } 263 264 r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0}) 265 if err != nil { 266 t.Fatal(err) 267 } 268 269 v2, exists := r.volumes["test"] 270 if !exists { 271 t.Fatal("missing volume on restart") 272 } 273 274 if !reflect.DeepEqual(v.opts, v2.opts) { 275 t.Fatal("missing volume options on restart") 276 } 277 } 278 279 func TestRelaodNoOpts(t *testing.T) { 280 rootDir, err := ioutil.TempDir("", "volume-test-reload-no-opts") 281 if err != nil { 282 t.Fatal(err) 283 } 284 defer os.RemoveAll(rootDir) 285 286 r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 287 if err != nil { 288 t.Fatal(err) 289 } 290 291 if _, err := r.Create("test1", nil); err != nil { 292 t.Fatal(err) 293 } 294 if _, err := r.Create("test2", nil); err != nil { 295 t.Fatal(err) 296 } 297 // make sure a file with `null` (.e.g. empty opts map from older daemon) is ok 298 if err := ioutil.WriteFile(filepath.Join(rootDir, "test2"), []byte("null"), 0600); err != nil { 299 t.Fatal(err) 300 } 301 302 if _, err := r.Create("test3", nil); err != nil { 303 t.Fatal(err) 304 } 305 // make sure an empty opts file doesn't break us too 306 if err := ioutil.WriteFile(filepath.Join(rootDir, "test3"), nil, 0600); err != nil { 307 t.Fatal(err) 308 } 309 310 if _, err := r.Create("test4", map[string]string{}); err != nil { 311 t.Fatal(err) 312 } 313 314 r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()}) 315 if err != nil { 316 t.Fatal(err) 317 } 318 319 for _, name := range []string{"test1", "test2", "test3", "test4"} { 320 v, err := r.Get(name) 321 if err != nil { 322 t.Fatal(err) 323 } 324 lv, ok := v.(*localVolume) 325 if !ok { 326 t.Fatalf("expected *localVolume got: %v", reflect.TypeOf(v)) 327 } 328 if lv.opts != nil { 329 t.Fatalf("expected opts to be nil, got: %v", lv.opts) 330 } 331 if _, err := lv.Mount("1234"); err != nil { 332 t.Fatal(err) 333 } 334 } 335 }