github.com/moby/docker@v26.1.3+incompatible/volume/mounts/lcow_parser_test.go (about) 1 package mounts // import "github.com/docker/docker/volume/mounts" 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/docker/docker/api/types/mount" 8 "gotest.tools/v3/assert" 9 is "gotest.tools/v3/assert/cmp" 10 ) 11 12 func TestLCOWParseMountRaw(t *testing.T) { 13 valid := []string{ 14 `/foo`, 15 `/foo/`, 16 `/foo bar`, 17 `c:\:/foo`, 18 `c:\windows\:/foo`, 19 `c:\windows:/s p a c e`, 20 `c:\windows:/s p a c e:RW`, 21 `c:\program files:/s p a c e i n h o s t d i r`, 22 `0123456789name:/foo`, 23 `MiXeDcAsEnAmE:/foo`, 24 `name:/foo`, 25 `name:/foo:rW`, 26 `name:/foo:RW`, 27 `name:/foo:RO`, 28 `c:/:/forward/slashes/are/good/too`, 29 `c:/:/including with/spaces:ro`, 30 `/Program Files (x86)`, // With capitals and brackets 31 } 32 33 invalid := map[string]string{ 34 ``: "invalid volume specification: ", 35 `.`: "invalid volume specification: ", 36 `c:`: "invalid volume specification: ", 37 `c:\`: "invalid volume specification: ", 38 `../`: "invalid volume specification: ", 39 `c:\:../`: "invalid volume specification: ", 40 `c:\:/foo:xyzzy`: "invalid volume specification: ", 41 `/`: "destination can't be '/'", 42 `/..`: "destination can't be '/'", 43 `c:\notexist:/foo`: `source path does not exist: c:\notexist`, 44 `c:\windows\system32\ntdll.dll:/foo`: `source path must be a directory`, 45 `name<:/foo`: `invalid volume specification`, 46 `name>:/foo`: `invalid volume specification`, 47 `name::/foo`: `invalid volume specification`, 48 `name":/foo`: `invalid volume specification`, 49 `name\:/foo`: `invalid volume specification`, 50 `name*:/foo`: `invalid volume specification`, 51 `name|:/foo`: `invalid volume specification`, 52 `name?:/foo`: `invalid volume specification`, 53 `name/:/foo`: `invalid volume specification`, 54 `/foo:rw`: `invalid volume specification`, 55 `/foo:ro`: `invalid volume specification`, 56 `con:/foo`: `cannot be a reserved word for Windows filenames`, 57 `PRN:/foo`: `cannot be a reserved word for Windows filenames`, 58 `aUx:/foo`: `cannot be a reserved word for Windows filenames`, 59 `nul:/foo`: `cannot be a reserved word for Windows filenames`, 60 `com1:/foo`: `cannot be a reserved word for Windows filenames`, 61 `com2:/foo`: `cannot be a reserved word for Windows filenames`, 62 `com3:/foo`: `cannot be a reserved word for Windows filenames`, 63 `com4:/foo`: `cannot be a reserved word for Windows filenames`, 64 `com5:/foo`: `cannot be a reserved word for Windows filenames`, 65 `com6:/foo`: `cannot be a reserved word for Windows filenames`, 66 `com7:/foo`: `cannot be a reserved word for Windows filenames`, 67 `com8:/foo`: `cannot be a reserved word for Windows filenames`, 68 `com9:/foo`: `cannot be a reserved word for Windows filenames`, 69 `lpt1:/foo`: `cannot be a reserved word for Windows filenames`, 70 `lpt2:/foo`: `cannot be a reserved word for Windows filenames`, 71 `lpt3:/foo`: `cannot be a reserved word for Windows filenames`, 72 `lpt4:/foo`: `cannot be a reserved word for Windows filenames`, 73 `lpt5:/foo`: `cannot be a reserved word for Windows filenames`, 74 `lpt6:/foo`: `cannot be a reserved word for Windows filenames`, 75 `lpt7:/foo`: `cannot be a reserved word for Windows filenames`, 76 `lpt8:/foo`: `cannot be a reserved word for Windows filenames`, 77 `lpt9:/foo`: `cannot be a reserved word for Windows filenames`, 78 `\\.\pipe\foo:/foo`: `Linux containers on Windows do not support named pipe mounts`, 79 } 80 81 parser := NewLCOWParser() 82 if p, ok := parser.(*lcowParser); ok { 83 p.fi = mockFiProvider{} 84 } 85 86 for _, path := range valid { 87 if _, err := parser.ParseMountRaw(path, "local"); err != nil { 88 t.Errorf("ParseMountRaw(`%q`) should succeed: error %q", path, err) 89 } 90 } 91 92 for path, expectedError := range invalid { 93 if mp, err := parser.ParseMountRaw(path, "local"); err == nil { 94 t.Errorf("ParseMountRaw(`%q`) should have failed validation. Err '%v' - MP: %v", path, err, mp) 95 } else { 96 if !strings.Contains(err.Error(), expectedError) { 97 t.Errorf("ParseMountRaw(`%q`) error should contain %q, got %v", path, expectedError, err.Error()) 98 } 99 } 100 } 101 } 102 103 func TestLCOWParseMountRawSplit(t *testing.T) { 104 cases := []struct { 105 bind string 106 driver string 107 expType mount.Type 108 expDest string 109 expSource string 110 expName string 111 expDriver string 112 expRW bool 113 fail bool 114 }{ 115 { 116 bind: `c:\:/foo`, 117 driver: "local", 118 expType: mount.TypeBind, 119 expDest: `/foo`, 120 expSource: `c:\`, 121 expRW: true, 122 }, 123 { 124 bind: `c:\:/foo:ro`, 125 driver: "local", 126 expType: mount.TypeBind, 127 expDest: `/foo`, 128 expSource: `c:\`, 129 }, 130 { 131 bind: `c:\:/foo:rw`, 132 driver: "local", 133 expType: mount.TypeBind, 134 expDest: `/foo`, 135 expSource: `c:\`, 136 expRW: true, 137 }, 138 { 139 bind: `c:\:/foo:foo`, 140 driver: "local", 141 expType: mount.TypeBind, 142 expDest: `/foo`, 143 expSource: `c:\`, 144 fail: true, 145 }, 146 { 147 bind: `name:/foo:rw`, 148 driver: "local", 149 expType: mount.TypeVolume, 150 expDest: `/foo`, 151 expName: `name`, 152 expDriver: "local", 153 expRW: true, 154 }, 155 { 156 bind: `name:/foo`, 157 driver: "local", 158 expType: mount.TypeVolume, 159 expDest: `/foo`, 160 expName: `name`, 161 expDriver: "local", 162 expRW: true, 163 }, 164 { 165 bind: `name:/foo:ro`, 166 driver: "local", 167 expType: mount.TypeVolume, 168 expDest: `/foo`, 169 expName: `name`, 170 expDriver: "local", 171 }, 172 { 173 bind: `name:/`, 174 expType: mount.TypeVolume, 175 expRW: true, 176 fail: true, 177 }, 178 { 179 bind: `driver/name:/`, 180 expType: mount.TypeVolume, 181 expRW: true, 182 fail: true, 183 }, 184 { 185 bind: `\\.\pipe\foo:\\.\pipe\bar`, 186 driver: "local", 187 expType: mount.TypeNamedPipe, 188 expDest: `\\.\pipe\bar`, 189 expSource: `\\.\pipe\foo`, 190 expRW: true, 191 fail: true, 192 }, 193 { 194 bind: `\\.\pipe\foo:/data`, 195 driver: "local", 196 expType: mount.TypeNamedPipe, 197 expRW: true, 198 fail: true, 199 }, 200 { 201 bind: `c:\foo\bar:\\.\pipe\foo`, 202 driver: "local", 203 expType: mount.TypeNamedPipe, 204 expRW: true, 205 fail: true, 206 }, 207 } 208 209 parser := NewLCOWParser() 210 if p, ok := parser.(*lcowParser); ok { 211 p.fi = mockFiProvider{} 212 } 213 214 for _, tc := range cases { 215 tc := tc 216 t.Run(tc.bind, func(t *testing.T) { 217 m, err := parser.ParseMountRaw(tc.bind, tc.driver) 218 if tc.fail { 219 assert.Check(t, is.ErrorContains(err, ""), "expected an error") 220 return 221 } 222 223 assert.NilError(t, err) 224 assert.Check(t, is.Equal(m.Destination, tc.expDest)) 225 assert.Check(t, is.Equal(m.Source, tc.expSource)) 226 assert.Check(t, is.Equal(m.Name, tc.expName)) 227 assert.Check(t, is.Equal(m.Driver, tc.expDriver)) 228 assert.Check(t, is.Equal(m.RW, tc.expRW)) 229 assert.Check(t, is.Equal(m.Type, tc.expType)) 230 }) 231 } 232 }