| package volume |
| |
| import ( |
| "runtime" |
| "strings" |
| "testing" |
| ) |
| |
| func TestParseMountSpec(t *testing.T) { |
| var ( |
| valid []string |
| invalid map[string]string |
| ) |
| |
| if runtime.GOOS == "windows" { |
| valid = []string{ |
| `d:\`, |
| `d:`, |
| `d:\path`, |
| `d:\path with space`, |
| // TODO Windows post TP5 - readonly support `d:\pathandmode:ro`, |
| `c:\:d:\`, |
| `c:\windows\:d:`, |
| `c:\windows:d:\s p a c e`, |
| `c:\windows:d:\s p a c e:RW`, |
| `c:\program files:d:\s p a c e i n h o s t d i r`, |
| `0123456789name:d:`, |
| `MiXeDcAsEnAmE:d:`, |
| `name:D:`, |
| `name:D::rW`, |
| `name:D::RW`, |
| // TODO Windows post TP5 - readonly support `name:D::RO`, |
| `c:/:d:/forward/slashes/are/good/too`, |
| // TODO Windows post TP5 - readonly support `c:/:d:/including with/spaces:ro`, |
| `c:\Windows`, // With capital |
| `c:\Program Files (x86)`, // With capitals and brackets |
| } |
| invalid = map[string]string{ |
| ``: "Invalid volume specification: ", |
| `.`: "Invalid volume specification: ", |
| `..\`: "Invalid volume specification: ", |
| `c:\:..\`: "Invalid volume specification: ", |
| `c:\:d:\:xyzzy`: "Invalid volume specification: ", |
| `c:`: "cannot be c:", |
| `c:\`: `cannot be c:\`, |
| `c:\notexist:d:`: `The system cannot find the file specified`, |
| `c:\windows\system32\ntdll.dll:d:`: `Source 'c:\windows\system32\ntdll.dll' is not a directory`, |
| `name<:d:`: `Invalid volume specification`, |
| `name>:d:`: `Invalid volume specification`, |
| `name::d:`: `Invalid volume specification`, |
| `name":d:`: `Invalid volume specification`, |
| `name\:d:`: `Invalid volume specification`, |
| `name*:d:`: `Invalid volume specification`, |
| `name|:d:`: `Invalid volume specification`, |
| `name?:d:`: `Invalid volume specification`, |
| `name/:d:`: `Invalid volume specification`, |
| `d:\pathandmode:rw`: `Invalid volume specification`, |
| `con:d:`: `cannot be a reserved word for Windows filenames`, |
| `PRN:d:`: `cannot be a reserved word for Windows filenames`, |
| `aUx:d:`: `cannot be a reserved word for Windows filenames`, |
| `nul:d:`: `cannot be a reserved word for Windows filenames`, |
| `com1:d:`: `cannot be a reserved word for Windows filenames`, |
| `com2:d:`: `cannot be a reserved word for Windows filenames`, |
| `com3:d:`: `cannot be a reserved word for Windows filenames`, |
| `com4:d:`: `cannot be a reserved word for Windows filenames`, |
| `com5:d:`: `cannot be a reserved word for Windows filenames`, |
| `com6:d:`: `cannot be a reserved word for Windows filenames`, |
| `com7:d:`: `cannot be a reserved word for Windows filenames`, |
| `com8:d:`: `cannot be a reserved word for Windows filenames`, |
| `com9:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt1:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt2:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt3:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt4:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt5:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt6:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt7:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt8:d:`: `cannot be a reserved word for Windows filenames`, |
| `lpt9:d:`: `cannot be a reserved word for Windows filenames`, |
| } |
| |
| } else { |
| valid = []string{ |
| "/home", |
| "/home:/home", |
| "/home:/something/else", |
| "/with space", |
| "/home:/with space", |
| "relative:/absolute-path", |
| "hostPath:/containerPath:ro", |
| "/hostPath:/containerPath:rw", |
| "/rw:/ro", |
| } |
| invalid = map[string]string{ |
| "": "Invalid volume specification", |
| "./": "Invalid volume destination", |
| "../": "Invalid volume destination", |
| "/:../": "Invalid volume destination", |
| "/:path": "Invalid volume destination", |
| ":": "Invalid volume specification", |
| "/tmp:": "Invalid volume destination", |
| ":test": "Invalid volume specification", |
| ":/test": "Invalid volume specification", |
| "tmp:": "Invalid volume destination", |
| ":test:": "Invalid volume specification", |
| "::": "Invalid volume specification", |
| ":::": "Invalid volume specification", |
| "/tmp:::": "Invalid volume specification", |
| ":/tmp::": "Invalid volume specification", |
| "/path:rw": "Invalid volume specification", |
| "/path:ro": "Invalid volume specification", |
| "/rw:rw": "Invalid volume specification", |
| "path:ro": "Invalid volume specification", |
| "/path:/path:sw": `invalid mode: sw`, |
| "/path:/path:rwz": `invalid mode: rwz`, |
| } |
| } |
| |
| for _, path := range valid { |
| if _, err := ParseMountSpec(path, "local"); err != nil { |
| t.Fatalf("ParseMountSpec(`%q`) should succeed: error %q", path, err) |
| } |
| } |
| |
| for path, expectedError := range invalid { |
| if _, err := ParseMountSpec(path, "local"); err == nil { |
| t.Fatalf("ParseMountSpec(`%q`) should have failed validation. Err %v", path, err) |
| } else { |
| if !strings.Contains(err.Error(), expectedError) { |
| t.Fatalf("ParseMountSpec(`%q`) error should contain %q, got %v", path, expectedError, err.Error()) |
| } |
| } |
| } |
| } |
| |
| // testParseMountSpec is a structure used by TestParseMountSpecSplit for |
| // specifying test cases for the ParseMountSpec() function. |
| type testParseMountSpec struct { |
| bind string |
| driver string |
| expDest string |
| expSource string |
| expName string |
| expDriver string |
| expRW bool |
| fail bool |
| } |
| |
| func TestParseMountSpecSplit(t *testing.T) { |
| var cases []testParseMountSpec |
| if runtime.GOOS == "windows" { |
| cases = []testParseMountSpec{ |
| {`c:\:d:`, "local", `d:`, `c:\`, ``, "", true, false}, |
| {`c:\:d:\`, "local", `d:\`, `c:\`, ``, "", true, false}, |
| // TODO Windows post TP5 - Add readonly support {`c:\:d:\:ro`, "local", `d:\`, `c:\`, ``, "", false, false}, |
| {`c:\:d:\:rw`, "local", `d:\`, `c:\`, ``, "", true, false}, |
| {`c:\:d:\:foo`, "local", `d:\`, `c:\`, ``, "", false, true}, |
| {`name:d::rw`, "local", `d:`, ``, `name`, "local", true, false}, |
| {`name:d:`, "local", `d:`, ``, `name`, "local", true, false}, |
| // TODO Windows post TP5 - Add readonly support {`name:d::ro`, "local", `d:`, ``, `name`, "local", false, false}, |
| {`name:c:`, "", ``, ``, ``, "", true, true}, |
| {`driver/name:c:`, "", ``, ``, ``, "", true, true}, |
| } |
| } else { |
| cases = []testParseMountSpec{ |
| {"/tmp:/tmp1", "", "/tmp1", "/tmp", "", "", true, false}, |
| {"/tmp:/tmp2:ro", "", "/tmp2", "/tmp", "", "", false, false}, |
| {"/tmp:/tmp3:rw", "", "/tmp3", "/tmp", "", "", true, false}, |
| {"/tmp:/tmp4:foo", "", "", "", "", "", false, true}, |
| {"name:/named1", "", "/named1", "", "name", "", true, false}, |
| {"name:/named2", "external", "/named2", "", "name", "external", true, false}, |
| {"name:/named3:ro", "local", "/named3", "", "name", "local", false, false}, |
| {"local/name:/tmp:rw", "", "/tmp", "", "local/name", "", true, false}, |
| {"/tmp:tmp", "", "", "", "", "", true, true}, |
| } |
| } |
| |
| for _, c := range cases { |
| m, err := ParseMountSpec(c.bind, c.driver) |
| if c.fail { |
| if err == nil { |
| t.Fatalf("Expected error, was nil, for spec %s\n", c.bind) |
| } |
| continue |
| } |
| |
| if m == nil || err != nil { |
| t.Fatalf("ParseMountSpec failed for spec %s driver %s error %v\n", c.bind, c.driver, err.Error()) |
| continue |
| } |
| |
| if m.Destination != c.expDest { |
| t.Fatalf("Expected destination %s, was %s, for spec %s\n", c.expDest, m.Destination, c.bind) |
| } |
| |
| if m.Source != c.expSource { |
| t.Fatalf("Expected source %s, was %s, for spec %s\n", c.expSource, m.Source, c.bind) |
| } |
| |
| if m.Name != c.expName { |
| t.Fatalf("Expected name %s, was %s for spec %s\n", c.expName, m.Name, c.bind) |
| } |
| |
| if m.Driver != c.expDriver { |
| t.Fatalf("Expected driver %s, was %s, for spec %s\n", c.expDriver, m.Driver, c.bind) |
| } |
| |
| if m.RW != c.expRW { |
| t.Fatalf("Expected RW %v, was %v for spec %s\n", c.expRW, m.RW, c.bind) |
| } |
| } |
| } |