github.com/gunjan5/docker@v1.8.2/opts/opts_test.go (about) 1 package opts 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 "testing" 8 ) 9 10 func TestValidateIPAddress(t *testing.T) { 11 if ret, err := ValidateIPAddress(`1.2.3.4`); err != nil || ret == "" { 12 t.Fatalf("ValidateIPAddress(`1.2.3.4`) got %s %s", ret, err) 13 } 14 15 if ret, err := ValidateIPAddress(`127.0.0.1`); err != nil || ret == "" { 16 t.Fatalf("ValidateIPAddress(`127.0.0.1`) got %s %s", ret, err) 17 } 18 19 if ret, err := ValidateIPAddress(`::1`); err != nil || ret == "" { 20 t.Fatalf("ValidateIPAddress(`::1`) got %s %s", ret, err) 21 } 22 23 if ret, err := ValidateIPAddress(`127`); err == nil || ret != "" { 24 t.Fatalf("ValidateIPAddress(`127`) got %s %s", ret, err) 25 } 26 27 if ret, err := ValidateIPAddress(`random invalid string`); err == nil || ret != "" { 28 t.Fatalf("ValidateIPAddress(`random invalid string`) got %s %s", ret, err) 29 } 30 31 } 32 33 func TestMapOpts(t *testing.T) { 34 tmpMap := make(map[string]string) 35 o := NewMapOpts(tmpMap, logOptsValidator) 36 o.Set("max-size=1") 37 if o.String() != "map[max-size:1]" { 38 t.Errorf("%s != [map[max-size:1]", o.String()) 39 } 40 41 o.Set("max-file=2") 42 if len(tmpMap) != 2 { 43 t.Errorf("map length %d != 2", len(tmpMap)) 44 } 45 46 if tmpMap["max-file"] != "2" { 47 t.Errorf("max-file = %s != 2", tmpMap["max-file"]) 48 } 49 50 if tmpMap["max-size"] != "1" { 51 t.Errorf("max-size = %s != 1", tmpMap["max-size"]) 52 } 53 if o.Set("dummy-val=3") == nil { 54 t.Errorf("validator is not being called") 55 } 56 } 57 58 func TestValidateMACAddress(t *testing.T) { 59 if _, err := ValidateMACAddress(`92:d0:c6:0a:29:33`); err != nil { 60 t.Fatalf("ValidateMACAddress(`92:d0:c6:0a:29:33`) got %s", err) 61 } 62 63 if _, err := ValidateMACAddress(`92:d0:c6:0a:33`); err == nil { 64 t.Fatalf("ValidateMACAddress(`92:d0:c6:0a:33`) succeeded; expected failure on invalid MAC") 65 } 66 67 if _, err := ValidateMACAddress(`random invalid string`); err == nil { 68 t.Fatalf("ValidateMACAddress(`random invalid string`) succeeded; expected failure on invalid MAC") 69 } 70 } 71 72 func TestListOptsWithoutValidator(t *testing.T) { 73 o := NewListOpts(nil) 74 o.Set("foo") 75 if o.String() != "[foo]" { 76 t.Errorf("%s != [foo]", o.String()) 77 } 78 o.Set("bar") 79 if o.Len() != 2 { 80 t.Errorf("%d != 2", o.Len()) 81 } 82 o.Set("bar") 83 if o.Len() != 3 { 84 t.Errorf("%d != 3", o.Len()) 85 } 86 if !o.Get("bar") { 87 t.Error("o.Get(\"bar\") == false") 88 } 89 if o.Get("baz") { 90 t.Error("o.Get(\"baz\") == true") 91 } 92 o.Delete("foo") 93 if o.String() != "[bar bar]" { 94 t.Errorf("%s != [bar bar]", o.String()) 95 } 96 listOpts := o.GetAll() 97 if len(listOpts) != 2 || listOpts[0] != "bar" || listOpts[1] != "bar" { 98 t.Errorf("Expected [[bar bar]], got [%v]", listOpts) 99 } 100 mapListOpts := o.GetMap() 101 if len(mapListOpts) != 1 { 102 t.Errorf("Expected [map[bar:{}]], got [%v]", mapListOpts) 103 } 104 105 } 106 107 func TestListOptsWithValidator(t *testing.T) { 108 // Re-using logOptsvalidator (used by MapOpts) 109 o := NewListOpts(logOptsValidator) 110 o.Set("foo") 111 if o.String() != "[]" { 112 t.Errorf("%s != []", o.String()) 113 } 114 o.Set("foo=bar") 115 if o.String() != "[]" { 116 t.Errorf("%s != []", o.String()) 117 } 118 o.Set("max-file=2") 119 if o.Len() != 1 { 120 t.Errorf("%d != 1", o.Len()) 121 } 122 if !o.Get("max-file=2") { 123 t.Error("o.Get(\"max-file=2\") == false") 124 } 125 if o.Get("baz") { 126 t.Error("o.Get(\"baz\") == true") 127 } 128 o.Delete("max-file=2") 129 if o.String() != "[]" { 130 t.Errorf("%s != []", o.String()) 131 } 132 } 133 134 func TestValidateDNSSearch(t *testing.T) { 135 valid := []string{ 136 `.`, 137 `a`, 138 `a.`, 139 `1.foo`, 140 `17.foo`, 141 `foo.bar`, 142 `foo.bar.baz`, 143 `foo.bar.`, 144 `foo.bar.baz`, 145 `foo1.bar2`, 146 `foo1.bar2.baz`, 147 `1foo.2bar.`, 148 `1foo.2bar.baz`, 149 `foo-1.bar-2`, 150 `foo-1.bar-2.baz`, 151 `foo-1.bar-2.`, 152 `foo-1.bar-2.baz`, 153 `1-foo.2-bar`, 154 `1-foo.2-bar.baz`, 155 `1-foo.2-bar.`, 156 `1-foo.2-bar.baz`, 157 } 158 159 invalid := []string{ 160 ``, 161 ` `, 162 ` `, 163 `17`, 164 `17.`, 165 `.17`, 166 `17-.`, 167 `17-.foo`, 168 `.foo`, 169 `foo-.bar`, 170 `-foo.bar`, 171 `foo.bar-`, 172 `foo.bar-.baz`, 173 `foo.-bar`, 174 `foo.-bar.baz`, 175 `foo.bar.baz.this.should.fail.on.long.name.beause.it.is.longer.thanisshouldbethis.should.fail.on.long.name.beause.it.is.longer.thanisshouldbethis.should.fail.on.long.name.beause.it.is.longer.thanisshouldbethis.should.fail.on.long.name.beause.it.is.longer.thanisshouldbe`, 176 } 177 178 for _, domain := range valid { 179 if ret, err := ValidateDNSSearch(domain); err != nil || ret == "" { 180 t.Fatalf("ValidateDNSSearch(`"+domain+"`) got %s %s", ret, err) 181 } 182 } 183 184 for _, domain := range invalid { 185 if ret, err := ValidateDNSSearch(domain); err == nil || ret != "" { 186 t.Fatalf("ValidateDNSSearch(`"+domain+"`) got %s %s", ret, err) 187 } 188 } 189 } 190 191 func TestValidateExtraHosts(t *testing.T) { 192 valid := []string{ 193 `myhost:192.168.0.1`, 194 `thathost:10.0.2.1`, 195 `anipv6host:2003:ab34:e::1`, 196 `ipv6local:::1`, 197 } 198 199 invalid := map[string]string{ 200 `myhost:192.notanipaddress.1`: `invalid IP`, 201 `thathost-nosemicolon10.0.0.1`: `bad format`, 202 `anipv6host:::::1`: `invalid IP`, 203 `ipv6local:::0::`: `invalid IP`, 204 } 205 206 for _, extrahost := range valid { 207 if _, err := ValidateExtraHost(extrahost); err != nil { 208 t.Fatalf("ValidateExtraHost(`"+extrahost+"`) should succeed: error %v", err) 209 } 210 } 211 212 for extraHost, expectedError := range invalid { 213 if _, err := ValidateExtraHost(extraHost); err == nil { 214 t.Fatalf("ValidateExtraHost(`%q`) should have failed validation", extraHost) 215 } else { 216 if !strings.Contains(err.Error(), expectedError) { 217 t.Fatalf("ValidateExtraHost(`%q`) error should contain %q", extraHost, expectedError) 218 } 219 } 220 } 221 } 222 223 func TestValidateAttach(t *testing.T) { 224 valid := []string{ 225 "stdin", 226 "stdout", 227 "stderr", 228 "STDIN", 229 "STDOUT", 230 "STDERR", 231 } 232 if _, err := ValidateAttach("invalid"); err == nil { 233 t.Fatalf("Expected error with [valid streams are STDIN, STDOUT and STDERR], got nothing") 234 } 235 236 for _, attach := range valid { 237 value, err := ValidateAttach(attach) 238 if err != nil { 239 t.Fatal(err) 240 } 241 if value != strings.ToLower(attach) { 242 t.Fatalf("Expected [%v], got [%v]", attach, value) 243 } 244 } 245 } 246 247 func TestValidateLink(t *testing.T) { 248 valid := []string{ 249 "name", 250 "dcdfbe62ecd0:alias", 251 "7a67485460b7642516a4ad82ecefe7f57d0c4916f530561b71a50a3f9c4e33da", 252 "angry_torvalds:linus", 253 } 254 invalid := map[string]string{ 255 "": "empty string specified for links", 256 "too:much:of:it": "bad format for links: too:much:of:it", 257 } 258 259 for _, link := range valid { 260 if _, err := ValidateLink(link); err != nil { 261 t.Fatalf("ValidateLink(`%q`) should succeed: error %q", link, err) 262 } 263 } 264 265 for link, expectedError := range invalid { 266 if _, err := ValidateLink(link); err == nil { 267 t.Fatalf("ValidateLink(`%q`) should have failed validation", link) 268 } else { 269 if !strings.Contains(err.Error(), expectedError) { 270 t.Fatalf("ValidateLink(`%q`) error should contain %q", link, expectedError) 271 } 272 } 273 } 274 } 275 276 func TestValidatePath(t *testing.T) { 277 valid := []string{ 278 "/home", 279 "/home:/home", 280 "/home:/something/else", 281 "/with space", 282 "/home:/with space", 283 "relative:/absolute-path", 284 "hostPath:/containerPath:ro", 285 "/hostPath:/containerPath:rw", 286 "/rw:/ro", 287 "/path:rw", 288 "/path:ro", 289 "/rw:rw", 290 } 291 invalid := map[string]string{ 292 "": "bad format for volumes: ", 293 "./": "./ is not an absolute path", 294 "../": "../ is not an absolute path", 295 "/:../": "../ is not an absolute path", 296 "/:path": "path is not an absolute path", 297 ":": "bad format for volumes: :", 298 "/tmp:": " is not an absolute path", 299 ":test": "bad format for volumes: :test", 300 ":/test": "bad format for volumes: :/test", 301 "tmp:": " is not an absolute path", 302 ":test:": "bad format for volumes: :test:", 303 "::": "bad format for volumes: ::", 304 ":::": "bad format for volumes: :::", 305 "/tmp:::": "bad format for volumes: /tmp:::", 306 ":/tmp::": "bad format for volumes: :/tmp::", 307 "path:ro": "path is not an absolute path", 308 "/path:/path:sw": "bad mount mode specified : sw", 309 "/path:/path:rwz": "bad mount mode specified : rwz", 310 } 311 312 for _, path := range valid { 313 if _, err := ValidatePath(path); err != nil { 314 t.Fatalf("ValidatePath(`%q`) should succeed: error %q", path, err) 315 } 316 } 317 318 for path, expectedError := range invalid { 319 if _, err := ValidatePath(path); err == nil { 320 t.Fatalf("ValidatePath(`%q`) should have failed validation", path) 321 } else { 322 if err.Error() != expectedError { 323 t.Fatalf("ValidatePath(`%q`) error should contain %q, got %q", path, expectedError, err.Error()) 324 } 325 } 326 } 327 } 328 func TestValidateDevice(t *testing.T) { 329 valid := []string{ 330 "/home", 331 "/home:/home", 332 "/home:/something/else", 333 "/with space", 334 "/home:/with space", 335 "relative:/absolute-path", 336 "hostPath:/containerPath:ro", 337 "/hostPath:/containerPath:rw", 338 "/hostPath:/containerPath:mrw", 339 } 340 invalid := map[string]string{ 341 "": "bad format for volumes: ", 342 "./": "./ is not an absolute path", 343 "../": "../ is not an absolute path", 344 "/:../": "../ is not an absolute path", 345 "/:path": "path is not an absolute path", 346 ":": "bad format for volumes: :", 347 "/tmp:": " is not an absolute path", 348 ":test": "bad format for volumes: :test", 349 ":/test": "bad format for volumes: :/test", 350 "tmp:": " is not an absolute path", 351 ":test:": "bad format for volumes: :test:", 352 "::": "bad format for volumes: ::", 353 ":::": "bad format for volumes: :::", 354 "/tmp:::": "bad format for volumes: /tmp:::", 355 ":/tmp::": "bad format for volumes: :/tmp::", 356 "path:ro": "ro is not an absolute path", 357 } 358 359 for _, path := range valid { 360 if _, err := ValidateDevice(path); err != nil { 361 t.Fatalf("ValidateDevice(`%q`) should succeed: error %q", path, err) 362 } 363 } 364 365 for path, expectedError := range invalid { 366 if _, err := ValidateDevice(path); err == nil { 367 t.Fatalf("ValidateDevice(`%q`) should have failed validation", path) 368 } else { 369 if err.Error() != expectedError { 370 t.Fatalf("ValidateDevice(`%q`) error should contain %q, got %q", path, expectedError, err.Error()) 371 } 372 } 373 } 374 } 375 376 func TestValidateEnv(t *testing.T) { 377 invalids := map[string]string{ 378 "some spaces": "poorly formatted environment: variable 'some spaces' is not a valid environment variable", 379 "asd!qwe": "poorly formatted environment: variable 'asd!qwe' is not a valid environment variable", 380 "1asd": "poorly formatted environment: variable '1asd' is not a valid environment variable", 381 "123": "poorly formatted environment: variable '123' is not a valid environment variable", 382 } 383 valids := map[string]string{ 384 "a": "a", 385 "something": "something", 386 "_=a": "_=a", 387 "env1=value1": "env1=value1", 388 "_env1=value1": "_env1=value1", 389 "env2=value2=value3": "env2=value2=value3", 390 "env3=abc!qwe": "env3=abc!qwe", 391 "env_4=value 4": "env_4=value 4", 392 "PATH": fmt.Sprintf("PATH=%v", os.Getenv("PATH")), 393 "PATH=something": "PATH=something", 394 } 395 for value, expectedError := range invalids { 396 _, err := ValidateEnv(value) 397 if err == nil { 398 t.Fatalf("Expected ErrBadEnvVariable, got nothing") 399 } 400 if _, ok := err.(ErrBadEnvVariable); !ok { 401 t.Fatalf("Expected ErrBadEnvVariable, got [%s]", err) 402 } 403 if err.Error() != expectedError { 404 t.Fatalf("Expected ErrBadEnvVariable with message [%s], got [%s]", expectedError, err.Error()) 405 } 406 } 407 for value, expected := range valids { 408 actual, err := ValidateEnv(value) 409 if err != nil { 410 t.Fatal(err) 411 } 412 if actual != expected { 413 t.Fatalf("Expected [%v], got [%v]", expected, actual) 414 } 415 } 416 } 417 418 func TestValidateLabel(t *testing.T) { 419 if _, err := ValidateLabel("label"); err == nil || err.Error() != "bad attribute format: label" { 420 t.Fatalf("Expected an error [bad attribute format: label], go %v", err) 421 } 422 if actual, err := ValidateLabel("key1=value1"); err != nil || actual != "key1=value1" { 423 t.Fatalf("Expected [key1=value1], got [%v,%v]", actual, err) 424 } 425 // Validate it's working with more than one = 426 if actual, err := ValidateLabel("key1=value1=value2"); err != nil { 427 t.Fatalf("Expected [key1=value1=value2], got [%v,%v]", actual, err) 428 } 429 // Validate it's working with one more 430 if actual, err := ValidateLabel("key1=value1=value2=value3"); err != nil { 431 t.Fatalf("Expected [key1=value1=value2=value2], got [%v,%v]", actual, err) 432 } 433 } 434 435 func TestValidateHost(t *testing.T) { 436 invalid := map[string]string{ 437 "anything": "Invalid bind address format: anything", 438 "something with spaces": "Invalid bind address format: something with spaces", 439 "://": "Invalid bind address format: ://", 440 "unknown://": "Invalid bind address format: unknown://", 441 "tcp://": "Invalid proto, expected tcp: ", 442 "tcp://:port": "Invalid bind address format: :port", 443 "tcp://invalid": "Invalid bind address format: invalid", 444 "tcp://invalid:port": "Invalid bind address format: invalid:port", 445 } 446 valid := map[string]string{ 447 "fd://": "fd://", 448 "fd://something": "fd://something", 449 "tcp://:2375": "tcp://127.0.0.1:2375", // default ip address 450 "tcp://:2376": "tcp://127.0.0.1:2376", // default ip address 451 "tcp://0.0.0.0:8080": "tcp://0.0.0.0:8080", 452 "tcp://192.168.0.0:12000": "tcp://192.168.0.0:12000", 453 "tcp://192.168:8080": "tcp://192.168:8080", 454 "tcp://0.0.0.0:1234567890": "tcp://0.0.0.0:1234567890", // yeah it's valid :P 455 "tcp://docker.com:2375": "tcp://docker.com:2375", 456 "unix://": "unix:///var/run/docker.sock", // default unix:// value 457 "unix://path/to/socket": "unix://path/to/socket", 458 } 459 460 for value, errorMessage := range invalid { 461 if _, err := ValidateHost(value); err == nil || err.Error() != errorMessage { 462 t.Fatalf("Expected an error for %v with [%v], got [%v]", value, errorMessage, err) 463 } 464 } 465 for value, expected := range valid { 466 if actual, err := ValidateHost(value); err != nil || actual != expected { 467 t.Fatalf("Expected for %v [%v], got [%v, %v]", value, expected, actual, err) 468 } 469 } 470 } 471 472 func logOptsValidator(val string) (string, error) { 473 allowedKeys := map[string]string{"max-size": "1", "max-file": "2"} 474 vals := strings.Split(val, "=") 475 if allowedKeys[vals[0]] != "" { 476 return val, nil 477 } 478 return "", fmt.Errorf("invalid key %s", vals[0]) 479 }