|
8 | 8 | using System.Threading; |
9 | 9 | using System.Threading.Tasks; |
10 | 10 | using FluentAssertions; |
| 11 | +using global::Test.Utility; |
11 | 12 | using Moq; |
12 | 13 | using NuGet.CommandLine.XPlat; |
13 | 14 | using NuGet.CommandLine.XPlat.Commands.Package; |
@@ -426,4 +427,174 @@ [new PackageSource(context.PackageSource)], |
426 | 427 | File.Exists(Path.Combine(context.WorkingDirectory, $"{id.ToLowerInvariant()}.{v}.nupkg")) |
427 | 428 | .Should().BeFalse("Package does not exist in sources"); |
428 | 429 | } |
| 430 | + |
| 431 | + public static IEnumerable<object[]> Cases() |
| 432 | + { |
| 433 | + // Parameters: |
| 434 | + // A-packages, B-packages, sourceMappings, sourcesArgs, downloadId, downloadVersion, |
| 435 | + // allowInsecureConnections, expectSuccess, expectedInstalled |
| 436 | + |
| 437 | + // --source specified, mapping ignored, package only in A -> success |
| 438 | + yield return new object[] |
| 439 | + { |
| 440 | + new List<(string,string)> { ("Contoso.Lib", "1.0.0") }, // A |
| 441 | + new List<(string,string)>(), // B |
| 442 | + new List<(string,string)> { ("B", "Contoso.*") }, // mapping ignored |
| 443 | + new List<string> { "A" }, // --source A |
| 444 | + "Contoso.Lib", "1.0.0", // downloadId, downloadVersion |
| 445 | + true, // allow insecure |
| 446 | + true, // expect success |
| 447 | + ("Contoso.Lib", "1.0.0") // expectedInstalled |
| 448 | + }; |
| 449 | + |
| 450 | + // no --source, mapping -> B, package only in B -> success |
| 451 | + yield return new object[] |
| 452 | + { |
| 453 | + new List<(string,string)>(), // A |
| 454 | + new List<(string,string)> { ("Contoso.Mapped", "2.0.0") }, // B |
| 455 | + new List<(string,string)> { ("B", "Contoso.*") }, // mapping -> B |
| 456 | + null, // no --source |
| 457 | + "Contoso.Mapped", "2.0.0", // downloadId, downloadVersion |
| 458 | + true, // allow insecure |
| 459 | + true, // expect success |
| 460 | + ("Contoso.Mapped", "2.0.0") // expectedInstalled |
| 461 | + }; |
| 462 | + |
| 463 | + // no --source, mapping -> A, package only in B -> fail |
| 464 | + yield return new object[] |
| 465 | + { |
| 466 | + new List<(string,string)>(), // A |
| 467 | + new List<(string,string)> { ("Contoso.Mapped", "2.0.0") }, |
| 468 | + new List<(string,string)> { ("A", "Contoso.*") }, // mapped to A |
| 469 | + null, |
| 470 | + "Contoso.Mapped", "2.0.0", |
| 471 | + true, |
| 472 | + false, |
| 473 | + null! |
| 474 | + }; |
| 475 | + |
| 476 | + // --source specified, no source mapping with an insecure source |
| 477 | + yield return new object[] |
| 478 | + { |
| 479 | + new List<(string,string)> { ("Contoso.Lib", "1.0.0") }, // A |
| 480 | + new List<(string,string)>(), |
| 481 | + new List<(string,string)> { ("A", "Contoso.*") }, |
| 482 | + new List<string> { "A" }, // --source |
| 483 | + "Contoso.Lib", "1.0.0", |
| 484 | + false, // allow insecure connections false / not set to true |
| 485 | + false, |
| 486 | + null! |
| 487 | + }; |
| 488 | + |
| 489 | + // no --source, mapping -> B, allow insecure not enabled -> fail |
| 490 | + yield return new object[] |
| 491 | + { |
| 492 | + new List<(string,string)>(), // A |
| 493 | + new List<(string,string)> { ("Contoso.Mapped", "1.0.0") }, |
| 494 | + new List<(string,string)> { ("B", "Contoso.*") }, |
| 495 | + null, |
| 496 | + "Contoso.Mapped", "1.0.0", |
| 497 | + false, // allow insecure connections false / not set to true |
| 498 | + false, |
| 499 | + null! |
| 500 | + }; |
| 501 | + } |
| 502 | + |
| 503 | + [Theory] |
| 504 | + [MemberData(nameof(Cases))] |
| 505 | + public async Task RunAsync_WithSourceMapping_ListDriven_UsingCleanSetup( |
| 506 | + IReadOnlyList<(string id, string version)> sourceAPackages, |
| 507 | + IReadOnlyList<(string id, string version)> sourceBPackages, |
| 508 | + IReadOnlyList<(string source, string pattern)> sourceMappings, |
| 509 | + IReadOnlyList<string> sourcesArgs, |
| 510 | + string downloadId, |
| 511 | + string downloadVersion, |
| 512 | + bool allowInsecureConnections, |
| 513 | + bool expectSuccess, |
| 514 | + (string id, string version)? expectedInstalled) |
| 515 | + { |
| 516 | + // Arrange |
| 517 | + using var context = new SimpleTestPathContext(); |
| 518 | + string srcADirectory = Path.Combine(context.PackageSource, "SourceA"); |
| 519 | + string srcBDirectory = Path.Combine(context.PackageSource, "SourceB"); |
| 520 | + |
| 521 | + using var serverA = new FileSystemBackedV3MockServer(srcADirectory); |
| 522 | + using var serverB = new FileSystemBackedV3MockServer(srcBDirectory); |
| 523 | + |
| 524 | + foreach (var (id, ver) in sourceAPackages) |
| 525 | + { |
| 526 | + await SimpleTestPackageUtility.CreateFullPackageAsync(srcADirectory, id, ver); |
| 527 | + } |
| 528 | + |
| 529 | + foreach (var (id, ver) in sourceBPackages) |
| 530 | + { |
| 531 | + await SimpleTestPackageUtility.CreateFullPackageAsync(srcBDirectory, id, ver); |
| 532 | + } |
| 533 | + |
| 534 | + serverA.Start(); |
| 535 | + serverB.Start(); |
| 536 | + |
| 537 | + // sources |
| 538 | + context.Settings.AddSource("A", serverA.ServiceIndexUri); |
| 539 | + context.Settings.AddSource("B", serverB.ServiceIndexUri); |
| 540 | + |
| 541 | + // mapping |
| 542 | + foreach (var (src, pattern) in sourceMappings) |
| 543 | + { |
| 544 | + context.Settings.AddPackageSourceMapping(src, pattern); |
| 545 | + } |
| 546 | + |
| 547 | + var settings = Settings.LoadSettingsGivenConfigPaths([context.Settings.ConfigPath]); |
| 548 | + |
| 549 | + var packageSources = new List<PackageSource> |
| 550 | + { |
| 551 | + new(serverA.ServiceIndexUri, "A"), |
| 552 | + new(serverB.ServiceIndexUri, "B") |
| 553 | + }; |
| 554 | + |
| 555 | + // args |
| 556 | + var args = new PackageDownloadArgs |
| 557 | + { |
| 558 | + Packages = |
| 559 | + [ |
| 560 | + new PackageWithNuGetVersion |
| 561 | + { |
| 562 | + Id = downloadId, |
| 563 | + NuGetVersion = downloadVersion is null ? null : NuGetVersion.Parse(downloadVersion) |
| 564 | + } |
| 565 | + ], |
| 566 | + OutputDirectory = context.WorkingDirectory, |
| 567 | + AllowInsecureConnections = allowInsecureConnections, |
| 568 | + Sources = sourcesArgs == null ? [] : sourcesArgs.ToList() |
| 569 | + }; |
| 570 | + |
| 571 | + var logger = new Mock<ILoggerWithColor>(MockBehavior.Loose); |
| 572 | + |
| 573 | + // Act |
| 574 | + var exit = await PackageDownloadRunner.RunAsync( |
| 575 | + args, |
| 576 | + logger.Object, |
| 577 | + packageSources, |
| 578 | + settings, |
| 579 | + CancellationToken.None); |
| 580 | + |
| 581 | + serverA.Stop(); |
| 582 | + serverB.Stop(); |
| 583 | + |
| 584 | + // Assert |
| 585 | + if (expectSuccess) |
| 586 | + { |
| 587 | + exit.Should().Be(PackageDownloadRunner.ExitCodeSuccess); |
| 588 | + expectedInstalled.Should().NotBeNull(); |
| 589 | + |
| 590 | + var (expId, expVer) = expectedInstalled!.Value; |
| 591 | + var installDir = Path.Combine(context.WorkingDirectory, expId.ToLowerInvariant(), expVer); |
| 592 | + Directory.Exists(installDir).Should().BeTrue(); |
| 593 | + File.Exists(Path.Combine(installDir, $"{expId.ToLowerInvariant()}.{expVer}.nupkg")).Should().BeTrue(); |
| 594 | + } |
| 595 | + else |
| 596 | + { |
| 597 | + exit.Should().Be(PackageDownloadRunner.ExitCodeError); |
| 598 | + } |
| 599 | + } |
429 | 600 | } |
0 commit comments