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