github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/url/parse_test.go (about) 1 package url 2 3 import ( 4 "runtime" 5 "testing" 6 7 "github.com/mutagen-io/mutagen/pkg/filesystem" 8 ) 9 10 type parseTestCase struct { 11 raw string 12 kind Kind 13 first bool 14 fail bool 15 expected *URL 16 } 17 18 func (c *parseTestCase) run(t *testing.T) { 19 // Mark this as a helper function to remove it from error traces. 20 t.Helper() 21 22 // Attempt to parse. 23 url, err := Parse(c.raw, c.kind, c.first) 24 if err != nil { 25 if !c.fail { 26 t.Fatal("parsing failed when it should have succeeded:", err) 27 } 28 return 29 } else if c.fail { 30 t.Fatal("parsing should have failed but did not") 31 } 32 33 // Verify kind. 34 if url.Kind != c.expected.Kind { 35 t.Error("kind mismatch:", url.Kind, "!=", c.expected.Kind) 36 } 37 38 // Verify protocol. 39 if url.Protocol != c.expected.Protocol { 40 t.Error("protocol mismatch:", url.Protocol, "!=", c.expected.Protocol) 41 } 42 43 // Verify username. 44 if url.User != c.expected.User { 45 t.Error("username mismatch:", url.User, "!=", c.expected.User) 46 } 47 48 // Verify hostname. 49 if url.Host != c.expected.Host { 50 t.Error("hostname mismatch:", url.Host, "!=", c.expected.Host) 51 } 52 53 // Verify port. 54 if url.Port != c.expected.Port { 55 t.Error("port mismatch:", url.Port, "!=", c.expected.Port) 56 } 57 58 // Verify path. 59 if url.Path != c.expected.Path { 60 t.Error("path mismatch:", url.Path, "!=", c.expected.Path) 61 } 62 63 // Verify environment variables. 64 if len(url.Environment) != len(c.expected.Environment) { 65 t.Error("environment length mismatch:", len(url.Environment), "!=", len(c.expected.Environment)) 66 } else { 67 for ek, ev := range c.expected.Environment { 68 if v, ok := url.Environment[ek]; !ok { 69 t.Error("expected environment variable", ek, "not in URL environment") 70 } else if v != ev { 71 t.Error("environment variable", ek, "value does not match expected:", v, "!=", ev) 72 } 73 } 74 } 75 } 76 77 func TestParseEmptyInvalid(t *testing.T) { 78 test := parseTestCase{ 79 raw: "", 80 fail: true, 81 } 82 test.run(t) 83 } 84 85 func TestParseLocalPathRelative(t *testing.T) { 86 // Compute the normalized form of a relative path. 87 path := "relative/path" 88 normalized, err := filesystem.Normalize(path) 89 if err != nil { 90 t.Fatal("unable to normalize relative path:", err) 91 } 92 93 // Create and run the test case. 94 test := parseTestCase{ 95 raw: path, 96 expected: &URL{ 97 Protocol: Protocol_Local, 98 User: "", 99 Host: "", 100 Port: 0, 101 Path: normalized, 102 }, 103 } 104 test.run(t) 105 } 106 107 func TestParseLocalPathAbsolute(t *testing.T) { 108 // Compute the normalized form of an absolute path. 109 path := "/this/is/a:path" 110 normalized, err := filesystem.Normalize(path) 111 if err != nil { 112 t.Fatal("unable to normalize absolute path:", err) 113 } 114 115 // Create and run the test case. 116 test := parseTestCase{ 117 raw: path, 118 expected: &URL{ 119 Protocol: Protocol_Local, 120 User: "", 121 Host: "", 122 Port: 0, 123 Path: normalized, 124 }, 125 } 126 test.run(t) 127 } 128 129 func TestParseForwardingLocalTCP(t *testing.T) { 130 test := parseTestCase{ 131 raw: "tcp:localhost:5050", 132 kind: Kind_Forwarding, 133 expected: &URL{ 134 Kind: Kind_Forwarding, 135 Protocol: Protocol_Local, 136 User: "", 137 Host: "", 138 Port: 0, 139 Path: "tcp:localhost:5050", 140 }, 141 } 142 test.run(t) 143 } 144 145 func TestParseForwardingLocalUnixRelativeSocket(t *testing.T) { 146 // Compute the normalized form of a relative socket path. 147 path := "relative/path/to/socket.sock" 148 normalized, err := filesystem.Normalize(path) 149 if err != nil { 150 t.Fatal("unable to normalize relative socket path:", err) 151 } 152 153 // Create and run the test case. 154 test := parseTestCase{ 155 raw: "unix:" + path, 156 kind: Kind_Forwarding, 157 expected: &URL{ 158 Kind: Kind_Forwarding, 159 Protocol: Protocol_Local, 160 User: "", 161 Host: "", 162 Port: 0, 163 Path: "unix:" + normalized, 164 }, 165 } 166 test.run(t) 167 } 168 169 func TestParseForwardingLocalUnixAbsoluteSocket(t *testing.T) { 170 // Compute the normalized form of a absolute socket path. 171 path := "/path/to/socket.sock" 172 normalized, err := filesystem.Normalize(path) 173 if err != nil { 174 t.Fatal("unable to normalize absolute socket path:", err) 175 } 176 177 // Create and run the test case. 178 test := parseTestCase{ 179 raw: "unix:" + path, 180 kind: Kind_Forwarding, 181 expected: &URL{ 182 Kind: Kind_Forwarding, 183 Protocol: Protocol_Local, 184 User: "", 185 Host: "", 186 Port: 0, 187 Path: "unix:" + normalized, 188 }, 189 } 190 test.run(t) 191 } 192 193 func TestParseLocalPathWithAtSymbol(t *testing.T) { 194 // Compute the normalized form of the path. 195 path := "/some@path" 196 normalized, err := filesystem.Normalize(path) 197 if err != nil { 198 t.Fatal("unable to normalize path:", err) 199 } 200 201 // Create and run the test case. 202 test := parseTestCase{ 203 raw: path, 204 expected: &URL{ 205 Protocol: Protocol_Local, 206 User: "", 207 Host: "", 208 Port: 0, 209 Path: normalized, 210 }, 211 } 212 test.run(t) 213 } 214 215 func TestParsePOSIXSCPSSHWindowsLocal(t *testing.T) { 216 // Compute the expected URL. 217 raw := "C:/local/path" 218 var expected *URL 219 if runtime.GOOS == "windows" { 220 if normalized, err := filesystem.Normalize(raw); err != nil { 221 t.Fatal("unable to normalize path:", err) 222 } else { 223 expected = &URL{ 224 Path: normalized, 225 } 226 } 227 } else { 228 expected = &URL{ 229 Protocol: Protocol_SSH, 230 Host: "C", 231 Path: "/local/path", 232 } 233 } 234 235 // Create and run the test case. 236 test := &parseTestCase{ 237 raw: raw, 238 expected: expected, 239 } 240 test.run(t) 241 } 242 243 func TestParseSCPSSHEmptyHostnameInvalid(t *testing.T) { 244 test := parseTestCase{ 245 raw: ":path", 246 fail: true, 247 } 248 test.run(t) 249 } 250 251 func TestParseSCPSSHEmptyHostnameAndPathInvalid(t *testing.T) { 252 test := parseTestCase{ 253 raw: ":", 254 fail: true, 255 } 256 test.run(t) 257 } 258 259 func TestParseSCPSSHUsernameEmptyHostnameInvalid(t *testing.T) { 260 test := parseTestCase{ 261 raw: "user@:path", 262 fail: true, 263 } 264 test.run(t) 265 } 266 267 func TestParseSCPSSHUsernameEmptyPathInvalid(t *testing.T) { 268 test := parseTestCase{ 269 raw: "user@host:", 270 fail: true, 271 } 272 test.run(t) 273 } 274 275 func TestParseSCPSSHEmptyUsernameInvalid(t *testing.T) { 276 test := parseTestCase{ 277 raw: "@host:path", 278 fail: true, 279 } 280 test.run(t) 281 } 282 283 func TestParseSCPSSHUsernamePortEmptyPathInvalid(t *testing.T) { 284 test := parseTestCase{ 285 raw: "user@host:5332:", 286 fail: true, 287 } 288 test.run(t) 289 } 290 291 func TestParseSCPSSHHostnameEmptyPathInvalid(t *testing.T) { 292 test := parseTestCase{ 293 raw: "host:", 294 fail: true, 295 } 296 test.run(t) 297 } 298 299 func TestParseSCPSSHUsernameHostnamePathEmptyPortInvalid(t *testing.T) { 300 test := parseTestCase{ 301 raw: "user@host::path", 302 fail: true, 303 } 304 test.run(t) 305 } 306 307 func TestParseSCPSSHHostnamePath(t *testing.T) { 308 test := parseTestCase{ 309 raw: "host:path", 310 expected: &URL{ 311 Protocol: Protocol_SSH, 312 User: "", 313 Host: "host", 314 Port: 0, 315 Path: "path", 316 }, 317 } 318 test.run(t) 319 } 320 321 func TestParseForwardingSCPSSHHostnameTCPEndpoint(t *testing.T) { 322 test := parseTestCase{ 323 raw: "host:tcp4:localhost:5050", 324 kind: Kind_Forwarding, 325 expected: &URL{ 326 Kind: Kind_Forwarding, 327 Protocol: Protocol_SSH, 328 User: "", 329 Host: "host", 330 Port: 0, 331 Path: "tcp4:localhost:5050", 332 }, 333 } 334 test.run(t) 335 } 336 337 func TestParseForwardingSCPSSHHostnameUnixDomainSocketEndpoint(t *testing.T) { 338 test := parseTestCase{ 339 raw: "host:unix:~/socket.sock", 340 kind: Kind_Forwarding, 341 expected: &URL{ 342 Kind: Kind_Forwarding, 343 Protocol: Protocol_SSH, 344 User: "", 345 Host: "host", 346 Port: 0, 347 Path: "unix:~/socket.sock", 348 }, 349 } 350 test.run(t) 351 } 352 353 func TestParseForwardingSCPSSHHostnameNamedPipeEndpoint(t *testing.T) { 354 test := parseTestCase{ 355 raw: `host:npipe:\\.\pipe\pipename`, 356 kind: Kind_Forwarding, 357 expected: &URL{ 358 Kind: Kind_Forwarding, 359 Protocol: Protocol_SSH, 360 User: "", 361 Host: "host", 362 Port: 0, 363 Path: `npipe:\\.\pipe\pipename`, 364 }, 365 } 366 test.run(t) 367 } 368 369 func TestParseSCPSSHUsernameHostnamePath(t *testing.T) { 370 test := parseTestCase{ 371 raw: "user@host:path", 372 expected: &URL{ 373 Protocol: Protocol_SSH, 374 User: "user", 375 Host: "host", 376 Port: 0, 377 Path: "path", 378 }, 379 } 380 test.run(t) 381 } 382 383 func TestParseSCPSSHUsernameHostnamePathWithColonInMiddle(t *testing.T) { 384 test := parseTestCase{ 385 raw: "user@host:pa:th", 386 expected: &URL{ 387 Protocol: Protocol_SSH, 388 User: "user", 389 Host: "host", 390 Port: 0, 391 Path: "pa:th", 392 }, 393 } 394 test.run(t) 395 } 396 397 func TestParseSCPSSHUsernameHostnamePathWithColonAtEnd(t *testing.T) { 398 test := parseTestCase{ 399 raw: "user@host:path:", 400 expected: &URL{ 401 Protocol: Protocol_SSH, 402 User: "user", 403 Host: "host", 404 Port: 0, 405 Path: "path:", 406 }, 407 } 408 test.run(t) 409 } 410 411 func TestParseSCPSSHUsernameHostnameWithAtPath(t *testing.T) { 412 test := parseTestCase{ 413 raw: "user@ho@st:path", 414 expected: &URL{ 415 Protocol: Protocol_SSH, 416 User: "user", 417 Host: "ho@st", 418 Port: 0, 419 Path: "path", 420 }, 421 } 422 test.run(t) 423 } 424 425 func TestParseSCPSSHUsernameHostnamePathWithAt(t *testing.T) { 426 test := parseTestCase{ 427 raw: "user@host:pa@th", 428 expected: &URL{ 429 Protocol: Protocol_SSH, 430 User: "user", 431 Host: "host", 432 Port: 0, 433 Path: "pa@th", 434 }, 435 } 436 test.run(t) 437 } 438 439 func TestParseSCPSSHUsernameHostnamePortPath(t *testing.T) { 440 test := parseTestCase{ 441 raw: "user@host:65535:path", 442 expected: &URL{ 443 Protocol: Protocol_SSH, 444 User: "user", 445 Host: "host", 446 Port: 65535, 447 Path: "path", 448 }, 449 } 450 test.run(t) 451 } 452 453 func TestParseSCPSSHUsernameHostnameZeroPortPath(t *testing.T) { 454 test := parseTestCase{ 455 raw: "user@host:0:path", 456 expected: &URL{ 457 Protocol: Protocol_SSH, 458 User: "user", 459 Host: "host", 460 Port: 0, 461 Path: "path", 462 }, 463 } 464 test.run(t) 465 } 466 467 func TestParseSCPSSHUsernameHostnameDoubleZeroPortPath(t *testing.T) { 468 test := parseTestCase{ 469 raw: "user@host:00:path", 470 expected: &URL{ 471 Protocol: Protocol_SSH, 472 User: "user", 473 Host: "host", 474 Port: 0, 475 Path: "path", 476 }, 477 } 478 test.run(t) 479 } 480 481 func TestParseSCPSSHUsernameHostnameOutOfBoundsPortInvalid(t *testing.T) { 482 test := parseTestCase{ 483 raw: "user@host:65536:path", 484 fail: true, 485 } 486 test.run(t) 487 } 488 489 func TestParseSCPSSHUsernameHostnameHexNumericPath(t *testing.T) { 490 test := parseTestCase{ 491 raw: "user@host:aaa:path", 492 expected: &URL{ 493 Protocol: Protocol_SSH, 494 User: "user", 495 Host: "host", 496 Port: 0, 497 Path: "aaa:path", 498 }, 499 } 500 test.run(t) 501 } 502 503 func TestParseSCPSSHUnicodeUsernameHostnamePath(t *testing.T) { 504 test := parseTestCase{ 505 raw: "üsér@høst:пат", 506 expected: &URL{ 507 Protocol: Protocol_SSH, 508 User: "üsér", 509 Host: "høst", 510 Port: 0, 511 Path: "пат", 512 }, 513 } 514 test.run(t) 515 } 516 517 func TestParseSCPSSHUnicodeUsernameHostnamePortPath(t *testing.T) { 518 test := parseTestCase{ 519 raw: "üsér@høst:23:пат", 520 expected: &URL{ 521 Protocol: Protocol_SSH, 522 User: "üsér", 523 Host: "høst", 524 Port: 23, 525 Path: "пат", 526 }, 527 } 528 test.run(t) 529 } 530 531 func TestParseForwardingDockerWithSourceSpecificVariables(t *testing.T) { 532 test := parseTestCase{ 533 raw: "docker://cøntainer:unix:/some/socket.sock", 534 kind: Kind_Forwarding, 535 first: true, 536 expected: &URL{ 537 Kind: Kind_Forwarding, 538 Protocol: Protocol_Docker, 539 Host: "cøntainer", 540 Path: "unix:/some/socket.sock", 541 Environment: map[string]string{ 542 "DOCKER_HOST": defaultDockerHost, 543 "DOCKER_TLS_VERIFY": defaultDockerTLSVerify, 544 "DOCKER_CONTEXT": sourceSpecificDockerContext, 545 }, 546 }, 547 } 548 test.run(t) 549 } 550 551 func TestParseForwardingDockerWithDestinationSpecificVariables(t *testing.T) { 552 test := parseTestCase{ 553 raw: "docker://cøntainer:tcp6:[::1]:5543", 554 kind: Kind_Forwarding, 555 expected: &URL{ 556 Kind: Kind_Forwarding, 557 Protocol: Protocol_Docker, 558 Host: "cøntainer", 559 Path: "tcp6:[::1]:5543", 560 Environment: map[string]string{ 561 "DOCKER_HOST": defaultDockerHost, 562 "DOCKER_TLS_VERIFY": destinationSpecificDockerTLSVerify, 563 }, 564 }, 565 } 566 test.run(t) 567 } 568 569 func TestParseDockerWithBetaSpecificVariables(t *testing.T) { 570 test := parseTestCase{ 571 raw: "docker://cøntainer/пат/to/the file", 572 fail: false, 573 expected: &URL{ 574 Protocol: Protocol_Docker, 575 Host: "cøntainer", 576 Path: "/пат/to/the file", 577 Environment: map[string]string{ 578 "DOCKER_HOST": defaultDockerHost, 579 "DOCKER_TLS_VERIFY": betaSpecificDockerTLSVerify, 580 }, 581 }, 582 } 583 test.run(t) 584 } 585 586 func TestParseDockerWithWindowsPathAndAlphaSpecificVariables(t *testing.T) { 587 test := parseTestCase{ 588 raw: `docker://cøntainer/C:\пат/to\the file`, 589 first: true, 590 fail: false, 591 expected: &URL{ 592 Protocol: Protocol_Docker, 593 Host: "cøntainer", 594 Path: `C:\пат/to\the file`, 595 Environment: map[string]string{ 596 "DOCKER_HOST": alphaSpecificDockerHost, 597 "DOCKER_TLS_VERIFY": defaultDockerTLSVerify, 598 }, 599 }, 600 } 601 test.run(t) 602 } 603 604 func TestParseDockerWithUsernameHomeRelativePathAndAlphaSpecificVariables(t *testing.T) { 605 test := parseTestCase{ 606 raw: "docker://üsér@cøntainer/~/пат/to/the file", 607 first: true, 608 fail: false, 609 expected: &URL{ 610 Protocol: Protocol_Docker, 611 User: "üsér", 612 Host: "cøntainer", 613 Path: "~/пат/to/the file", 614 Environment: map[string]string{ 615 "DOCKER_HOST": alphaSpecificDockerHost, 616 "DOCKER_TLS_VERIFY": defaultDockerTLSVerify, 617 }, 618 }, 619 } 620 test.run(t) 621 } 622 623 func TestParseDockerWithUsernameUserRelativePathAndAlphaSpecificVariables(t *testing.T) { 624 test := parseTestCase{ 625 raw: "docker://üsér@cøntainer/~otheruser/пат/to/the file", 626 first: true, 627 fail: false, 628 expected: &URL{ 629 Protocol: Protocol_Docker, 630 User: "üsér", 631 Host: "cøntainer", 632 Path: "~otheruser/пат/to/the file", 633 Environment: map[string]string{ 634 "DOCKER_HOST": alphaSpecificDockerHost, 635 "DOCKER_TLS_VERIFY": defaultDockerTLSVerify, 636 }, 637 }, 638 } 639 test.run(t) 640 }