From 8a1031c593dc316dfa5ce406657906f5578898ce Mon Sep 17 00:00:00 2001 From: Nikolche Kolev Date: Mon, 20 Apr 2026 14:33:07 -0700 Subject: [PATCH 1/8] Migrate Package Source Mapping ests --- .copilot/skills/apex-migration/SKILL.md | 290 +++++++++++ .github/copilot-instructions.md | 148 ------ test/EndToEnd/tests/PackageNameSpaceTests.ps1 | 471 ------------------ .../NuGetEndToEndTests/IVsServicesTestCase.cs | 56 +++ .../NuGetConsoleTestCase.cs | 185 +++++++ 5 files changed, 531 insertions(+), 619 deletions(-) create mode 100644 .copilot/skills/apex-migration/SKILL.md diff --git a/.copilot/skills/apex-migration/SKILL.md b/.copilot/skills/apex-migration/SKILL.md new file mode 100644 index 00000000000..5c3b9f828fc --- /dev/null +++ b/.copilot/skills/apex-migration/SKILL.md @@ -0,0 +1,290 @@ +--- +name: apex-migration +description: >- + Migrate NuGet PowerShell E2E tests to C# Apex tests. Use this skill whenever the user asks to + migrate, convert, or port a PowerShell end-to-end test from test/EndToEnd/tests/ to an Apex test + in test/NuGet.Tests.Apex/. Also trigger when the user mentions "Apex test", "migrate PS test", + "E2E test migration", "PMC test", or references any PowerShell test function like + Install-PackageTest or Update-PackageTest and wants it rewritten in C#. Even if the user just + says "migrate this test" while looking at a PS E2E file, use this skill. +--- + +# Migrating PowerShell E2E Tests to Apex Tests + +PowerShell E2E tests live in `test/EndToEnd/tests/`. Apex tests live in +`test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/`. The goal is to migrate PS tests +to C# Apex tests that run the **exact same scenario**, then remove the PS test function. + +## Workflow + +1. **Read the PS test** — understand what it does: which project type, which PMC commands, what assertions. +2. **Pick the right Apex file** — match the scenario to an existing test class (see File Placement below). +3. **Translate** — use the mappings in this skill to convert each PS construct to its Apex equivalent. +4. **Verify** — run `get_errors` or build the Apex project to confirm it compiles cleanly. +5. **Remove the PS function** — delete the migrated function from the PS test file. +6. **If already covered** — if an existing Apex test already covers the same scenario, just delete the PS test. No new Apex test needed. +7. **Update this skill** — if you discovered new mappings, gotchas, or corrections, add them to the appropriate section of this file (e.g., new rows in the mapping tables, new bullets in Common gotchas). + +## File placement + +Choose the target file by **interaction surface**, not project type: + +| Interaction surface | Apex file | +|---|---| +| PMC commands (Install-Package, Update-Package, etc.) | `NuGetConsoleTestCase.cs` | +| NuGet UI / Package Manager dialog | `NuGetUITestCase.cs` | +| IVsPackageInstaller / IVsServices API | `IVsServicesTestCase.cs` | +| Sync/binding redirect scenarios | `SyncPackageTestCase.cs` | +| Audit / vulnerability scenarios | `NuGetAuditTests.cs` | +| .NET Core project-creation / restore / source-mapping | `NetCoreProjectTestCase.cs` | + +PMC tests for PackageReference projects still go in `NuGetConsoleTestCase.cs` — the deciding +factor is whether the test exercises the PMC console, not the project's package management style. + +## Template mapping + +| PowerShell function | Apex `ProjectTemplate` | Package management | Verified | +|---|---|---|---| +| `New-ConsoleApplication` | `ProjectTemplate.ConsoleApplication` | packages.config | ✅ | +| `New-ClassLibrary` | `ProjectTemplate.ClassLibrary` | packages.config | ✅ | +| `New-WebSite` | `ProjectTemplate.WebSiteEmpty` | packages.config | ✅ | +| `New-WebApplication` | `ProjectTemplate.WebApplicationEmpty` | packages.config | ❌ | +| `New-WPFApplication` | `ProjectTemplate.WPFApplication` | packages.config | ❌ | +| `New-MvcApplication` | `ProjectTemplate.WebApplicationEmptyMvc` | packages.config | ❌ | +| `New-FSharpLibrary` | `ProjectTemplate.FSharpLibrary` | PackageReference | ❌ | +| `New-NetCoreConsoleApp` | `ProjectTemplate.NetCoreConsoleApp` | PackageReference | ✅ | +| `New-NetStandardClassLib` | `ProjectTemplate.NetStandardClassLib` | PackageReference | ✅ | + +| PowerShell function | Apex equivalent | +|---|---| +| `New-SolutionFolder 'Name'` | `testContext.SolutionService.AddSolutionFolder("Name")` | + +The package management style determines which assertion methods to use — packages.config projects +use `AssertPackageInPackagesConfig`, while PackageReference projects use `AssertPackageInAssetsFile`. + +> **Note:** This table covers the most common PS project factories. Some PS tests use specialized +> factories like `New-ClassLibraryNET46`, `New-BuildIntegratedProj`, `New-UwpPackageRefClassLibrary`, +> or `New-NetCoreConsoleMultipleTargetFrameworksApp`. These don't have a 1:1 `ProjectTemplate` enum +> value — check the Apex `ProjectTemplate` enum and existing tests for the closest match, or create +> a standard template and modify the csproj afterward (e.g., for multi-targeting). + +## Command execution + +| Scenario | Apex API | +|---|---| +| Standard install with `-Version` | `nugetConsole.InstallPackageFromPMC(packageName, packageVersion)` | +| Install with extra flags (`-Source`, `-WhatIf`, `-IgnoreDependencies`) | `nugetConsole.Execute($"Install-Package {packageName} -ProjectName {project.Name} -Source {source}")` | +| Standard uninstall | `nugetConsole.UninstallPackageFromPMC(packageName)` | +| Standard update with `-Version` | `nugetConsole.UpdatePackageFromPMC(packageName, packageVersion)` | +| Update with `-Safe`, `-Reinstall`, etc. | `nugetConsole.Execute($"Update-Package {packageName} -Safe")` | +| Any raw PMC command | `nugetConsole.Execute(command)` | + +**Key rule:** Both `InstallPackageFromPMC()` and `UpdatePackageFromPMC()` always inject `-Version`. +If the original PS test does **not** use `-Version`, use `Execute()` with the raw command string +instead — using the helper changes the semantics. + +**PowerShell session state is accessible.** `nugetConsole.Execute()` runs in a live PMC PowerShell +session. It can execute **any** PowerShell command, not just NuGet commands. This means PS session +state — global variables (`$global:InstallVar`), registered functions +(`Test-Path function:\Get-World`), environment checks — can all be queried and asserted via +`Execute()` + `IsMessageFoundInPMC()`. Do not skip tests just because they assert PS session state. + +## Assertion mapping + +| PowerShell assertion | Apex equivalent | +|---|---| +| `Assert-Package $p PackageName Version` (packages.config) | `CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, version, Logger)` | +| `Assert-Package $p PackageName` (no version, packages.config) | `CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, Logger)` | +| `Assert-Package $p PackageName Version` (PackageReference) | `CommonUtility.AssertPackageInAssetsFile(VisualStudio, testContext.Project, packageName, version, Logger)` | +| `Assert-Throws { ... } $expectedMessage` | `nugetConsole.IsMessageFoundInPMC(expectedMessage)` — PMC errors appear as text, not C# exceptions | +| `Assert-Null (Get-ProjectPackage ...)` / not installed | `CommonUtility.AssertPackageNotInPackagesConfig(VisualStudio, testContext.Project, packageName, Logger)` | +| `Assert-NoPackage $p PackageName Version` (PackageReference) | `CommonUtility.AssertPackageNotInAssetsFile(VisualStudio, testContext.Project, packageName, version, Logger)` | +| `Assert-PackageReference $p PackageName Version` | `CommonUtility.AssertPackageReferenceExists(VisualStudio, testContext.Project, packageName, version, Logger)` | +| `Assert-NoPackageReference $p PackageName` | `CommonUtility.AssertPackageReferenceDoesNotExist(VisualStudio, testContext.Project, packageName, Logger)` | + +## Package sources + +| PowerShell source | Apex equivalent | +|---|---| +| `$context.RepositoryRoot` / `$context.RepositoryPath` | `testContext.PackageSource` — create packages with `CommonUtility.CreatePackageInSourceAsync()` | +| No `-Source` (uses nuget.org) | Create a local package with `CommonUtility.CreatePackageInSourceAsync(testContext.PackageSource, ...)` — never depend on nuget.org | +| Hardcoded invalid sources (`http://example.com`, `ftp://...`) | Use the same hardcoded strings directly | + +### Creating test packages + +For simple packages: +```csharp +await CommonUtility.CreatePackageInSourceAsync(testContext.PackageSource, packageName, packageVersion); +``` + +For packages with dependencies: +```csharp +await CommonUtility.CreateDependenciesPackageInSourceAsync( + testContext.PackageSource, packageName, packageVersion, dependencyName, dependencyVersion); +``` + +For .NET Framework-specific packages: +```csharp +await CommonUtility.CreateNetFrameworkPackageInSourceAsync( + testContext.PackageSource, packageName, packageVersion); +``` + +## NuGet.Config manipulation + +PS tests that use `Get-VSComponentModel` + `ISettings` to modify NuGet config at runtime can be +migrated by pre-configuring `SimpleTestPathContext` before passing it to `ApexTestContext`. + +**Via Settings API** (preferred): +```csharp +using var simpleTestPathContext = new SimpleTestPathContext(); +simpleTestPathContext.Settings.AddSource("PrivateRepo", privatePath); + +using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, + simpleTestPathContext: simpleTestPathContext); +``` + +**Via raw config file** (for settings not covered by the API like `dependencyVersion` or `bindingRedirects`): +```csharp +using var simpleTestPathContext = new SimpleTestPathContext(); +File.WriteAllText(simpleTestPathContext.NuGetConfig, + $@" + + + + + + + + +"); + +using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, + simpleTestPathContext: simpleTestPathContext); +``` + +## Test structure patterns + +### Error-path tests (no package creation needed) — synchronous + +```csharp +[TestMethod] +[Timeout(DefaultTimeout)] +public void DescriptiveTestName_Fails() +{ + using var testContext = new ApexTestContext(VisualStudio, ProjectTemplate.ConsoleApplication, Logger); + + var packageName = "Rules"; + var source = @"c:\temp\data"; + var expectedMessage = $"Unable to find package '{packageName}' at source '{source}'. Source not found."; + + var nugetConsole = GetConsole(testContext.Project); + nugetConsole.Execute($"Install-Package {packageName} -ProjectName {testContext.Project.Name} -Source {source}"); + + Assert.IsTrue( + nugetConsole.IsMessageFoundInPMC(expectedMessage), + $"Expected error message was not found in PMC output. Actual output: {nugetConsole.GetText()}"); +} +``` + +### Success-path tests (need package creation) — async + +```csharp +[TestMethod] +[Timeout(DefaultTimeout)] +public async Task DescriptiveTestNameAsync() +{ + using var testContext = new ApexTestContext(VisualStudio, ProjectTemplate.ConsoleApplication, Logger); + + var packageName = "TestPackage"; + var packageVersion = "1.0.0"; + await CommonUtility.CreatePackageInSourceAsync(testContext.PackageSource, packageName, packageVersion); + + var nugetConsole = GetConsole(testContext.Project); + nugetConsole.InstallPackageFromPMC(packageName, packageVersion); + + CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, packageVersion, Logger); +} +``` + +### Data-driven tests (multiple project templates) + +When the same scenario applies to multiple project types, use `[DataTestMethod]`: +```csharp +[DataTestMethod] +[DataRow(ProjectTemplate.NetCoreConsoleApp)] +[DataRow(ProjectTemplate.NetStandardClassLib)] +[Timeout(DefaultTimeout)] +public async Task InstallPackageForMultipleProjectTypesAsync(ProjectTemplate projectTemplate) +{ + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger); + // ... test body +} +``` + +### Multi-targeted project tests + +To create a multi-targeted project, modify the csproj after project creation: +```csharp +using var testContext = new ApexTestContext(VisualStudio, ProjectTemplate.NetCoreConsoleApp, Logger); +// Modify csproj to multi-target via XDocument: +// change to net8.0;netstandard2.0 +``` + +## Style rules + +- Use `using var` (inline using declaration), not `using (var ...) { }`. +- Place migrated tests before the static helper methods (`GetNetCoreTemplates`, etc.) in the file. +- Method names: `{Action}FromPMC{Scenario}[_Fails|Async]`. Suffix with `_Fails` for error tests, + `Async` for async tests. +- Always include `[Timeout(DefaultTimeout)]`. +- Always include `nugetConsole.GetText()` in assertion failure messages for diagnostics. +- Use `var` for local variables except value tuples (use decomposed names). +- The test class inherits `SharedVisualStudioHostTestClass` which provides `VisualStudio` and `Logger`. +- Get PMC console via `GetConsole(testContext.Project)` helper method in the test class. + +## Tests that should NOT be migrated + +Skip PS tests that: +- Use `Assert-BindingRedirect` — binding redirect tests are already `[SkipTest]` in PS and not + worth migrating. +- Depend on **DTE project hierarchy semantics** (e.g., `Get-ProjectItem` to check tree structure, + parent/child relationships). However, if the PS test only uses `Get-ProjectItem` / + `Get-ProjectItemPath` to verify a **file exists on disk**, migrate it using filesystem assertions + instead: `File.Exists(path)`, XML reads on the project file, or + `CommonUtility.WaitForFileExists()`. + +## After migration checklist + +1. ✅ Remove the migrated function from the PS test file. +2. ✅ If a PS test is already covered by an existing Apex test (duplicate), just delete the PS + test — no new Apex test needed. +3. ✅ Build the Apex project or run `get_errors` to verify it compiles cleanly. +4. ✅ Verify assertion methods match the project's package management style + (packages.config vs PackageReference). + +## Common gotchas + +- **Console width**: PMC output assertions are text-sensitive. The Apex infrastructure forces + console width to 1024 to avoid wrapping issues. +- **Restore timing**: After install/update operations, the Apex infrastructure handles waiting for + restore completion. You generally don't need explicit waits. +- **nuget.org dependency**: PS tests that don't specify `-Source` implicitly use nuget.org. Always + replace this with local package creation via `CreatePackageInSourceAsync` — tests must not depend + on external feeds. +- **`NuGetApexTestService` limitations**: It does NOT expose `ISolutionManager` or VS DTE project + item inspection. Only `IVsPackageInstaller`, `IVsSolutionRestoreStatusProvider`, + `IVsPackageUninstaller`, `IVsPathContextProvider2`, and `IVsUIShell` are available. +- **IVs error-path tests**: `NuGetApexTestService.InstallPackage()` swallows + `InvalidOperationException` and logs it — it does NOT rethrow. For error-path IVs tests, assert + that the package was NOT installed (`AssertPackageNotInPackagesConfig`) rather than trying to + catch exceptions. +- **Feature renaming**: Some PS tests use older feature names (e.g., "PackageNameSpace"). When + migrating, use the current feature name (e.g., "PackageSourceMapping") in test method names and + comments. +- **IVs tests use `EnvDTE.Project`**: IVs API methods like `InstallPackage()` take + `project.UniqueName` (from `EnvDTE.Project`), not a `ProjectTestExtension`. Get it via + `VisualStudio.Dte.Solution.Projects.Item(1)`. +- **`_pathContext` vs `testContext`**: `IVsServicesTestCase` uses a class-level + `SimpleTestPathContext _pathContext` (initialized in constructor), not per-test `ApexTestContext`. + PMC tests in `NuGetConsoleTestCase` use per-test `ApexTestContext`. + diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 4759ce7542b..055e68b4375 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -29,152 +29,4 @@ - **TryCreate/TryGet patterns** — out params need `?`, callers use `!` after the success guard. Out parameters that are guaranteed non-null when the method returns true should be annotated with `[NotNullWhen(true)]`. Don't annotate `[NotNullWhen]` unless it's actually true for all code paths. - **Work in batches** — group related files, fix source, fix cascading, build, repeat. If this means we need multiple pull requests for enabling nullable, that's fine. Don't try to do it all in one go. -## Migrating PowerShell E2E Tests to Apex Tests -### Overview - -PowerShell E2E tests live in `test/EndToEnd/tests/`. Apex tests live in `test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/`. The goal is to migrate PS tests to C# Apex tests that run the **exact same scenario**, then remove the PS test function. - -### Template mapping - -| PowerShell function | Apex `ProjectTemplate` | Package management | Verified | -|---|---|---|---| -| `New-ConsoleApplication` | `ProjectTemplate.ConsoleApplication` | packages.config | ✅ | -| `New-ClassLibrary` | `ProjectTemplate.ClassLibrary` | packages.config | ✅ | -| `New-WebSite` | `ProjectTemplate.WebSiteEmpty` | packages.config | ✅ | -| `New-WebApplication` | `ProjectTemplate.WebApplicationEmpty` | packages.config | ❌ | -| `New-WPFApplication` | `ProjectTemplate.WPFApplication` | packages.config | ❌ | -| `New-MvcApplication` | `ProjectTemplate.WebApplicationEmptyMvc` | packages.config | ❌ | -| `New-FSharpLibrary` | `ProjectTemplate.FSharpLibrary` | PackageReference | ❌ | -| `New-NetCoreConsoleApp` | `ProjectTemplate.NetCoreConsoleApp` | PackageReference | ✅ | -| `New-NetStandardClassLib` | `ProjectTemplate.NetStandardClassLib` | PackageReference | ✅ | - -| PowerShell function | Apex equivalent | -|---|---| -| `New-SolutionFolder 'Name'` | `testContext.SolutionService.AddSolutionFolder("Name")` | - -### Command execution - -| Scenario | Apex API | -|---|---| -| Standard install with `-Version` | `nugetConsole.InstallPackageFromPMC(packageName, packageVersion)` | -| Install with extra flags (`-Source`, `-WhatIf`, `-IgnoreDependencies`) | `nugetConsole.Execute($"Install-Package {packageName} -ProjectName {project.Name} -Source {source}")` | -| Standard uninstall | `nugetConsole.UninstallPackageFromPMC(packageName)` | -| Standard update | `nugetConsole.UpdatePackageFromPMC(packageName, packageVersion)` | -| Any raw PMC command | `nugetConsole.Execute(command)` | - -**Rule:** If the PS test does not use `-Version`, use `Execute()` with the raw command string. `InstallPackageFromPMC()` always adds `-Version`. - -**Important:** `nugetConsole.Execute()` runs in a live PMC PowerShell session. It can execute **any** PowerShell command, not just NuGet commands. This means PS session state — global variables (`$global:InstallVar`), registered functions (`Test-Path function:\Get-World`), environment checks — can all be queried and asserted via `Execute()` + `IsMessageFoundInPMC()`. Do not skip tests just because they assert PS session state. - -### Assertion mapping - -| PowerShell assertion | Apex equivalent | -|---|---| -| `Assert-Package $p PackageName Version` (packages.config project) | `CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, version, Logger)` | -| `Assert-Package $p PackageName` (no version, packages.config) | `CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, Logger)` | -| `Assert-Package $p PackageName Version` (PackageReference project) | `CommonUtility.AssertPackageInAssetsFile(VisualStudio, testContext.Project, packageName, version, Logger)` | -| `Assert-Throws { ... } $expectedMessage` | `nugetConsole.IsMessageFoundInPMC(expectedMessage)` — PMC errors appear as text, not C# exceptions | -| `Assert-Null (Get-ProjectPackage ...)` / package not installed | `CommonUtility.AssertPackageNotInPackagesConfig(VisualStudio, testContext.Project, packageName, Logger)` | - -### Package sources - -| PowerShell source | Apex equivalent | -|---|---| -| `$context.RepositoryRoot` or `$context.RepositoryPath` | `testContext.PackageSource` — create packages with `CommonUtility.CreatePackageInSourceAsync()` | -| No `-Source` (uses nuget.org) | Create a local package with `CommonUtility.CreatePackageInSourceAsync(testContext.PackageSource, ...)` — never depend on nuget.org | -| Hardcoded invalid sources (`http://example.com`, `ftp://...`) | Use the same hardcoded strings directly | - -### NuGet.Config manipulation - -PS tests that use `Get-VSComponentModel` + `ISettings` to modify NuGet config at runtime can be migrated by pre-configuring `SimpleTestPathContext` before passing it to `ApexTestContext`. - -**Via Settings API** (preferred): -```csharp -using var simpleTestPathContext = new SimpleTestPathContext(); -simpleTestPathContext.Settings.AddSource("PrivateRepo", privatePath); -// ... then pass it in: -using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, - simpleTestPathContext: simpleTestPathContext); -``` - -**Via raw config file** (for settings not covered by the API like `dependencyVersion` or `bindingRedirects`): -```csharp -using var simpleTestPathContext = new SimpleTestPathContext(); -File.WriteAllText(simpleTestPathContext.NuGetConfig, - $@" - - - - - - - - -"); - -using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, - simpleTestPathContext: simpleTestPathContext); -``` - -### Test structure patterns - -**Error-path tests** (no package creation needed) — synchronous: -```csharp -[TestMethod] -[Timeout(DefaultTimeout)] -public void DescriptiveTestName_Fails() -{ - using var testContext = new ApexTestContext(VisualStudio, ProjectTemplate.ConsoleApplication, Logger); - - var packageName = "Rules"; - var source = @"c:\temp\data"; - var expectedMessage = $"Unable to find package '{packageName}' at source '{source}'. Source not found."; - - var nugetConsole = GetConsole(testContext.Project); - nugetConsole.Execute($"Install-Package {packageName} -ProjectName {testContext.Project.Name} -Source {source}"); - - Assert.IsTrue( - nugetConsole.IsMessageFoundInPMC(expectedMessage), - $"Expected error message was not found in PMC output. Actual output: {nugetConsole.GetText()}"); -} -``` - -**Success-path tests** (need package creation) — async: -```csharp -[TestMethod] -[Timeout(DefaultTimeout)] -public async Task DescriptiveTestNameAsync(/* or [DataTestMethod] with ProjectTemplate */) -{ - using var testContext = new ApexTestContext(VisualStudio, ProjectTemplate.ConsoleApplication, Logger); - - var packageName = "TestPackage"; - var packageVersion = "1.0.0"; - await CommonUtility.CreatePackageInSourceAsync(testContext.PackageSource, packageName, packageVersion); - - var nugetConsole = GetConsole(testContext.Project); - nugetConsole.InstallPackageFromPMC(packageName, packageVersion); - - CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, packageVersion, Logger); -} -``` - -### Style rules - -- Use `using var` (inline declaration), not `using (var ...) { }`. -- Place migrated tests before the static helper methods (`GetNetCoreTemplates`, etc.) in the file. -- Method names: `{Action}FromPMC{Scenario}[_Fails|Async]`. Suffix with `_Fails` for error tests, `Async` for async tests. -- Always include `[Timeout(DefaultTimeout)]`. -- Include `nugetConsole.GetText()` in assertion failure messages for diagnostics. - -### Tests that should NOT be migrated - -Skip PS tests that: -- Use `Assert-BindingRedirect` — binding redirect tests are already `[SkipTest]` in PS and not worth migrating. -- Use `Get-ProjectItem`, `Get-ProjectItemPath`, or other VS DTE project-item inspection not available in Apex. - -### After migration - -1. Remove the migrated function from the PS test file. -2. If a PS test is already covered by an existing Apex test (duplicate), just delete the PS test — no new Apex test needed. -3. Verify with `get_errors` that the Apex file compiles cleanly. diff --git a/test/EndToEnd/tests/PackageNameSpaceTests.ps1 b/test/EndToEnd/tests/PackageNameSpaceTests.ps1 index 623f3f9c479..11ae04fec0c 100644 --- a/test/EndToEnd/tests/PackageNameSpaceTests.ps1 +++ b/test/EndToEnd/tests/PackageNameSpaceTests.ps1 @@ -117,477 +117,6 @@ function Test-PackageSourceMappingRestore-WithMultipleFeedsWithIdenticalPackages } } -function Test-VsPackageInstallerServices-PackageSourceMappingInstall-WithSingleFeed-Succeed { - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param( - $context - ) - - # Arrange - $repoDirectory = $context.RepositoryRoot - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - -"@ - - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $repoDirectory | Out-File -Encoding "UTF8" $nugetConfigPath - - # $p = New-ConsoleApplication - # Arrange - $p = New-ClassLibrary - - # Act - [API.Test.InternalAPITestHook]::InstallLatestPackageApi("SolutionLevelPkg", $false) - - # Assert - Assert-Package $p SolutionLevelPkg 1.0.0 - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item $nugetConfigPath - } -} - -function Test-VsPackageInstallerServices-PackageSourceMappingInstall-WithSingleFeed-Fails { - param( - $context - ) - - # Arrange - $repoDirectory = $context.RepositoryRoot - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - -"@ - - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $repoDirectory | Out-File -Encoding "UTF8" $nugetConfigPath - - # $p = New-ConsoleApplication - # Arrange - $p = New-ClassLibrary - - # Act & Assert - # Even though SolutionLevelPkg package exist in $repoDirectory since package source mapping filter set SolutionLevelPkg can be restored only from SecretPackages repository so it'll fail. - $exceptionMessage = "Exception calling `"InstallLatestPackageApi`" with `"2`" argument(s): `"Package 'SolutionLevelPkg 1.0.0' is not found in the following primary source(s): '"+ $repoDirectory + "'. Please verify all your online package sources are available (OR) package id, version are specified correctly.`"" - Assert-Throws { [API.Test.InternalAPITestHook]::InstallLatestPackageApi("SolutionLevelPkg", $false) } $exceptionMessage - Assert-NoPackage $p SolutionLevelPkg 1.0.0 - } - finally { - Remove-Item $nugetConfigPath - } -} - -function Test-VsPackageInstallerServices-PackageSourceMappingInstall-WithMultipleFeedsWithIdenticalPackages-RestoresCorrectPackageWithSpecifiedVersion -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - - # Arrange - $repoDirectory = Join-Path $OutputPath "CustomPackages" - $opensourceRepo = Join-Path $repoDirectory "opensourceRepo" - $privateRepo = Join-Path $repoDirectory "privateRepo" - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $opensourceRepo,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $privateRepo "Thisisfromprivaterepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "2.0.0" $privateRepo "Thisisfromprivaterepo2.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "2.0.0" $opensourceRepo "Thisisfromopensourcerepo2.txt" - - # Act - [API.Test.InternalAPITestHook]::InstallPackageApi("Contoso.MVC.ASP", "1.0.0") - - # Assert - $packagesFolder = Join-Path $solutionDirectory "packages" - $contosoNupkgFolder = Join-Path $packagesFolder "Contoso.MVC.ASP.1.0.0" - Assert-PathExists(Join-Path $contosoNupkgFolder "Contoso.MVC.ASP.1.0.0.nupkg") - # Make sure name squatting package from public repo not restored. - $contentFolder = Join-Path $contosoNupkgFolder "content" - Assert-PathExists(Join-Path $contentFolder "Thisisfromprivaterepo1.txt") - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item -Recurse -Force $repoDirectory - Remove-Item $nugetConfigPath - } -} - -function Test-VsPackageInstallerServices-PackageSourceMappingInstall-WithMultipleFeedsWithIdenticalPackages-RestoresCorrectPackageWithLatestVersion -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - - # Arrange - $repoDirectory = Join-Path $OutputPath "CustomPackages" - $opensourceRepo = Join-Path $repoDirectory "opensourceRepo" - $privateRepo = Join-Path $repoDirectory "privateRepo" - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $opensourceRepo,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $privateRepo "Thisisfromprivaterepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "2.0.0" $privateRepo "Thisisfromprivaterepo2.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "2.0.0" $opensourceRepo "Thisisfromopensourcerepo2.txt" - - # Act - [API.Test.InternalAPITestHook]::InstallLatestPackageApi("Contoso.MVC.ASP", $false) - - # Assert - $packagesFolder = Join-Path $solutionDirectory "packages" - $contosoNupkgFolder = Join-Path $packagesFolder "Contoso.MVC.ASP.2.0.0" - Assert-PathExists(Join-Path $contosoNupkgFolder "Contoso.MVC.ASP.2.0.0.nupkg") - # Make sure name squatting package from public repo not restored. - $contentFolder = Join-Path $contosoNupkgFolder "content" - Assert-PathExists(Join-Path $contentFolder "Thisisfromprivaterepo2.txt") - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item -Recurse -Force $repoDirectory - Remove-Item $nugetConfigPath - } -} - -function Test-PC-PackageSourceMappingInstall-Succeed -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - - # Arrange - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - $settingFileContent =@" - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $context.RepositoryRoot | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - - # Act - $p | Install-Package SolutionLevelPkg -Version 1.0 - - # # Assert - Assert-Package $p SolutionLevelPkg 1.0.0 - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - $warninglist = Get-Warnings - Assert-AreEqual 0 $warninglist.Count - } - finally { - Remove-Item $nugetConfigPath - } -} - -function Test-PC-PackageSourceMappingInstall-Fails -{ - param($context) - - # Arrange - $repoDirectory = $context.RepositoryRoot - $privateRepo = Join-Path $repoDirectory "privateRepo" - - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $context.RepositoryRoot,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - - # Act & Assert - # Even though SolutionLevelPkg package exist in $repoDirectory since package source mapping filter set SolutionLevelPkg can be restored only from PrivateRepository repository so it'll fail. - $exceptionMessage = "Package 'SolutionLevelPkg 1.0' is not found in the following primary source(s): '" + $context.RepositoryRoot + "," + $privateRepo + "'. Please verify all your online package sources are available (OR) package id, version are specified correctly." - Assert-Throws { $p | Install-Package SolutionLevelPkg -Version 1.0 } $exceptionMessage - Assert-NoPackage $p SolutionLevelPkg 1.0.0 - } - finally { - Remove-Item $nugetConfigPath - } -} - -function Test-PC-PackageSourceMappingInstall-WithCorrectSourceOption-Succeed -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - - # Arrange - $repoDirectory = Join-Path $OutputPath "CustomPackages" - $opensourceRepo = Join-Path $repoDirectory "opensourceRepo" - $privateRepo = Join-Path $repoDirectory "privateRepo" - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $opensourceRepo,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $privateRepo "Thisisfromprivaterepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo1.txt" - - # Act - $p | Install-Package Contoso.MVC.ASP -Source $privateRepo - - # Assert - Assert-Package $p Contoso.MVC.ASP 1.0.0 - $packagesFolder = Join-Path $solutionDirectory "packages" - $contosoNupkgFolder = Join-Path $packagesFolder "Contoso.MVC.ASP.1.0.0" - Assert-PathExists(Join-Path $contosoNupkgFolder "Contoso.MVC.ASP.1.0.0.nupkg") - # Make sure name squatting package from public repo not restored. - $contentFolder = Join-Path $contosoNupkgFolder "content" - Assert-PathExists(Join-Path $contentFolder "Thisisfromprivaterepo1.txt") - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item -Recurse -Force $repoDirectory - Remove-Item $nugetConfigPath - } -} - -function Test-PC-PackageSourceMappingInstall-WithWrongSourceOption-Fails -{ - param($context) - - # Arrange - $repoDirectory = Join-Path $OutputPath "CustomPackages" - $opensourceRepo = Join-Path $repoDirectory "opensourceRepo" - $privateRepo = Join-Path $repoDirectory "privateRepo" - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $opensourceRepo,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $privateRepo "Thisisfromprivaterepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo1.txt" - - # Act & Assert - $exceptionMessage = "Package 'Contoso.MVC.ASP 1.0.0' is not found in the following primary source(s): '"+ $opensourceRepo + "'. Please verify all your online package sources are available (OR) package id, version are specified correctly." - Assert-Throws { $p | Install-Package Contoso.MVC.ASP -Source $opensourceRepo } $exceptionMessage - Assert-NoPackage $p SolutionLevelPkg 1.0.0 - } - finally { - Remove-Item -Recurse -Force $repoDirectory - Remove-Item $nugetConfigPath - } -} - -function Test-PC-PackageSourceMappingUpdate-WithCorrectSourceOption-Succeed -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - - # Arrange - $repoDirectory = Join-Path $OutputPath "CustomPackages" - $opensourceRepo = Join-Path $repoDirectory "opensourceRepo" - $privateRepo = Join-Path $repoDirectory "privateRepo" - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $opensourceRepo,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $privateRepo "Thisisfromprivaterepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "2.0.0" $privateRepo "Thisisfromprivaterepo2.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo1.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo2.txt" - - # Act - $p | Install-Package Contoso.MVC.ASP -Version 1.0 -Source $privateRepo - Assert-Package $p Contoso.MVC.ASP 1.0.0 - - $p | Update-Package Contoso.MVC.ASP -Version 2.0 -Source $privateRepo - Assert-Package $p Contoso.MVC.ASP 2.0.0 - - # Assert - $packagesFolder = Join-Path $solutionDirectory "packages" - $contosoNupkgFolder = Join-Path $packagesFolder "Contoso.MVC.ASP.2.0.0" - Assert-PathExists(Join-Path $contosoNupkgFolder "Contoso.MVC.ASP.2.0.0.nupkg") - # Make sure name squatting package from public repo not restored. - $contentFolder = Join-Path $contosoNupkgFolder "content" - Assert-PathExists(Join-Path $contentFolder "Thisisfromprivaterepo2.txt") - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item -Recurse -Force $repoDirectory - Remove-Item $nugetConfigPath - } -} - # Create a custom test package function CreateCustomTestPackage { param( diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/IVsServicesTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/IVsServicesTestCase.cs index d7764207d34..9baafc71e49 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/IVsServicesTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/IVsServicesTestCase.cs @@ -202,6 +202,62 @@ public async Task SimpleUpdateFromIVsInstaller_PackageSourceMapping_WithMultiple Assert.IsTrue(File.Exists(uniqueContentFile), $"'{uniqueContentFile}' should exist"); } + [TestMethod] + [Timeout(DefaultTimeout)] + public async Task SimpleInstallFromIVsInstaller_PackageSourceMapping_WithMissingMappedSource_Fails() + { + // Arrange + await CommonUtility.CreatePackageInSourceAsync(_pathContext.PackageSource, TestPackageName, TestPackageVersionV1); + // Map the package pattern to a non-existent source "SecretPackages" — package exists in primary source but mapping won't route there. + _pathContext.Settings.AddPackageSourceMapping("SecretPackages", "Contoso.*", "Test.*"); + + NuGetApexTestService nugetTestService = GetNuGetTestService(); + + SolutionService solutionService = VisualStudio.Get(); + solutionService.CreateEmptySolution("TestSolution", _pathContext.SolutionRoot); + ProjectTestExtension projExt = solutionService.AddProject(ProjectLanguage.CSharp, ProjectTemplate.ClassLibrary, CommonUtility.DefaultTargetFramework, "TestProject"); + solutionService.SaveAll(); + EnvDTE.Project project = VisualStudio.Dte.Solution.Projects.Item(1); + + // Act — InstallPackage swallows InvalidOperationException, so the call returns without throwing. + nugetTestService.InstallPackage(project.UniqueName, TestPackageName); + + // Assert + CommonUtility.AssertPackageNotInPackagesConfig(VisualStudio, projExt, TestPackageName, Logger); + } + + [TestMethod] + [Timeout(DefaultTimeout)] + public async Task SimpleInstallLatestFromIVsInstaller_PackageSourceMapping_WithMultipleFeedsWithIdenticalPackages_InstallsCorrectPackage() + { + // Arrange + string secondarySourcePath = Directory.CreateDirectory(Path.Combine(_pathContext.SolutionRoot, SecondarySourceName)).FullName; + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(secondarySourcePath, TestPackageName, TestPackageVersionV1, "Thisisfromsecondaryrepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(secondarySourcePath, TestPackageName, TestPackageVersionV2, "Thisisfromsecondaryrepo2.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(_pathContext.PackageSource, TestPackageName, TestPackageVersionV1, "Thisisfromprivaterepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(_pathContext.PackageSource, TestPackageName, TestPackageVersionV2, "Thisisfromprivaterepo2.txt"); + _pathContext.Settings.AddSource(SecondarySourceName, secondarySourcePath); + _pathContext.Settings.AddPackageSourceMapping(SecondarySourceName, "External.*", "Others.*"); + _pathContext.Settings.AddPackageSourceMapping(PrimarySourceName, "Contoso.*", "Test.*"); + + NuGetApexTestService nugetTestService = GetNuGetTestService(); + + SolutionService solutionService = VisualStudio.Get(); + solutionService.CreateEmptySolution("TestSolution", _pathContext.SolutionRoot); + ProjectTestExtension projExt = solutionService.AddProject(ProjectLanguage.CSharp, ProjectTemplate.ClassLibrary, CommonUtility.DefaultTargetFramework, "TestProject"); + solutionService.SaveAll(); + EnvDTE.Project project = VisualStudio.Dte.Solution.Projects.Item(1); + + // Act — install latest (no version specified) + nugetTestService.InstallPackage(project.UniqueName, TestPackageName); + + // Assert — latest version (2.0.0) should be installed from the mapped primary source + CommonUtility.AssertPackageInPackagesConfig(VisualStudio, projExt, TestPackageName, Logger); + + string uniqueContentFile = Path.Combine(_pathContext.PackagesV2, TestPackageName + '.' + TestPackageVersionV2, "lib", "net45", "Thisisfromprivaterepo2.txt"); + Assert.IsTrue(File.Exists(uniqueContentFile), $"'{uniqueContentFile}' should exist"); + } + public override void Dispose() { _pathContext.Dispose(); diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index f1b0e36a4e0..c1575002197 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -488,6 +488,191 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithMultipleFeedsWithI } } + [DataTestMethod] + [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] + [Timeout(DefaultTimeout)] + public void InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_Fails(ProjectTemplate projectTemplate) + { + // Arrange + using var simpleTestPathContext = new SimpleTestPathContext(); + var solutionDirectory = simpleTestPathContext.SolutionRoot; + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + Directory.CreateDirectory(privateRepositoryPath); + + var packageName = "SolutionLevelPkg"; + var packageVersion = "1.0.0"; + + // Package exists in PackageSource but mapping routes SolutionLevelPkg to PrivateRepository where it doesn't exist. + CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" + + + + + + + + + + + +"); + + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); + var nugetConsole = GetConsole(testContext.Project); + + // Act + nugetConsole.InstallPackageFromPMC(packageName, packageVersion); + + // Assert + CommonUtility.AssertPackageNotInPackagesConfig(VisualStudio, testContext.Project, packageName, Logger); + } + + [DataTestMethod] + [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] + [Timeout(DefaultTimeout)] + public async Task InstallPackageForPC_PackageSourceMapping_WithCorrectSourceOption_InstallsCorrectPackage(ProjectTemplate projectTemplate) + { + // Arrange + using var simpleTestPathContext = new SimpleTestPathContext(); + var solutionDirectory = simpleTestPathContext.SolutionRoot; + + var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); + Directory.CreateDirectory(opensourceRepositoryPath); + + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + Directory.CreateDirectory(privateRepositoryPath); + + var packageName = "Contoso.MVC.ASP"; + var packageVersion = "1.0.0"; + + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion, "Thisisfromprivaterepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); + + CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" + + + + + + + + + + + +"); + + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); + var nugetConsole = GetConsole(testContext.Project); + + // Act + nugetConsole.InstallPackageFromPMC(packageName, packageVersion, privateRepositoryPath); + + // Assert + CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, packageVersion, Logger); + + var packagesDirectory = Path.Combine(solutionDirectory, "packages"); + var uniqueContentFile = Path.Combine(packagesDirectory, packageName + '.' + packageVersion, "lib", "net45", "Thisisfromprivaterepo1.txt"); + Assert.IsTrue(File.Exists(uniqueContentFile), $"'{uniqueContentFile}' should exist"); + } + + [DataTestMethod] + [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] + [Timeout(DefaultTimeout)] + public void InstallPackageForPC_PackageSourceMapping_WithWrongSourceOption_Fails(ProjectTemplate projectTemplate) + { + // Arrange + using var simpleTestPathContext = new SimpleTestPathContext(); + var solutionDirectory = simpleTestPathContext.SolutionRoot; + + var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); + Directory.CreateDirectory(opensourceRepositoryPath); + + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + Directory.CreateDirectory(privateRepositoryPath); + + var packageName = "Contoso.MVC.ASP"; + var packageVersion = "1.0.0"; + + CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" + + + + + + + + + + + +"); + + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); + var nugetConsole = GetConsole(testContext.Project); + + // Act — Install from the opensourceRepo where the package doesn't match the source mapping + nugetConsole.InstallPackageFromPMC(packageName, packageVersion, opensourceRepositoryPath); + + // Assert + CommonUtility.AssertPackageNotInPackagesConfig(VisualStudio, testContext.Project, packageName, Logger); + } + + [DataTestMethod] + [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] + [Timeout(DefaultTimeout)] + public async Task UpdatePackageForPC_PackageSourceMapping_WithCorrectSourceOption_UpdatesCorrectPackage(ProjectTemplate projectTemplate) + { + // Arrange + using var simpleTestPathContext = new SimpleTestPathContext(); + var solutionDirectory = simpleTestPathContext.SolutionRoot; + + var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); + Directory.CreateDirectory(opensourceRepositoryPath); + + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + Directory.CreateDirectory(privateRepositoryPath); + + var packageName = "Contoso.MVC.ASP"; + var packageVersion1 = "1.0.0"; + var packageVersion2 = "2.0.0"; + + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion1, "Thisisfromprivaterepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion2, "Thisisfromprivaterepo2.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion1, "Thisisfromopensourcerepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion2, "Thisisfromopensourcerepo2.txt"); + + CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" + + + + + + + + + + + +"); + + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); + var nugetConsole = GetConsole(testContext.Project); + + // Act + nugetConsole.InstallPackageFromPMC(packageName, packageVersion1, privateRepositoryPath); + CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, packageVersion1, Logger); + + nugetConsole.UpdatePackageFromPMC(packageName, packageVersion2, privateRepositoryPath); + + // Assert + CommonUtility.AssertPackageInPackagesConfig(VisualStudio, testContext.Project, packageName, packageVersion2, Logger); + + var packagesDirectory = Path.Combine(solutionDirectory, "packages"); + var uniqueContentFile = Path.Combine(packagesDirectory, packageName + '.' + packageVersion2, "lib", "net45", "Thisisfromprivaterepo2.txt"); + Assert.IsTrue(File.Exists(uniqueContentFile), $"'{uniqueContentFile}' should exist"); + } + [Ignore("https://github.com/NuGet/Home/issues/12899")] [DataTestMethod] [DataRow(ProjectTemplate.ClassLibrary, false)] From 7c7d8ed19db5c82f0884eb45799111bc96738dac Mon Sep 17 00:00:00 2001 From: Nikolche Kolev Date: Mon, 20 Apr 2026 17:48:38 -0700 Subject: [PATCH 2/8] Use SimpleTestPathContext Settings API instead of raw config files Replaced CreateConfigurationFile with Settings.AddSource() and Settings.AddPackageSourceMapping() in 4 PMC source mapping tests to preserve SimpleTestPathContext defaults (globalPackagesFolder, etc.). Also reuse the default 'source' feed as the opensource repo where possible. Updated apex-migration skill with config gotcha learning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .copilot/skills/apex-migration/SKILL.md | 5 ++ .../NuGetConsoleTestCase.cs | 73 ++++--------------- 2 files changed, 19 insertions(+), 59 deletions(-) diff --git a/.copilot/skills/apex-migration/SKILL.md b/.copilot/skills/apex-migration/SKILL.md index 5c3b9f828fc..f57411d17e4 100644 --- a/.copilot/skills/apex-migration/SKILL.md +++ b/.copilot/skills/apex-migration/SKILL.md @@ -287,4 +287,9 @@ Skip PS tests that: - **`_pathContext` vs `testContext`**: `IVsServicesTestCase` uses a class-level `SimpleTestPathContext _pathContext` (initialized in constructor), not per-test `ApexTestContext`. PMC tests in `NuGetConsoleTestCase` use per-test `ApexTestContext`. +- **Never overwrite `SimpleTestPathContext`'s NuGet.config**: Using `CreateConfigurationFile` to + write a full config replaces defaults like `globalPackagesFolder`, `fallbackPackageFolders`, and + `httpCacheFolder` — causing packages to pollute the user's real global packages folder. Instead + use `simpleTestPathContext.Settings.AddSource()` and `AddPackageSourceMapping()` to layer config + on top of the defaults. diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index c1575002197..da68747bc42 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -495,27 +495,15 @@ public void InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_Fails(P { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - var solutionDirectory = simpleTestPathContext.SolutionRoot; - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + var privateRepositoryPath = Path.Combine(simpleTestPathContext.SolutionRoot, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); var packageName = "SolutionLevelPkg"; var packageVersion = "1.0.0"; - // Package exists in PackageSource but mapping routes SolutionLevelPkg to PrivateRepository where it doesn't exist. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - -"); + // Package exists in default source but mapping routes Solution* to PrivateRepository where it doesn't exist. + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Solution*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); @@ -536,31 +524,18 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithCorrectSourceOpti using var simpleTestPathContext = new SimpleTestPathContext(); var solutionDirectory = simpleTestPathContext.SolutionRoot; - var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); - Directory.CreateDirectory(opensourceRepositoryPath); - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); var packageName = "Contoso.MVC.ASP"; var packageVersion = "1.0.0"; + // Opensource package in default "source", private package in PrivateRepository + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion, "Thisisfromprivaterepo1.txt"); - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.MVC.*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); @@ -594,19 +569,9 @@ public void InstallPackageForPC_PackageSourceMapping_WithWrongSourceOption_Fails var packageName = "Contoso.MVC.ASP"; var packageVersion = "1.0.0"; - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("OpensourceRepository", opensourceRepositoryPath); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.MVC.*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); @@ -642,19 +607,9 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithCorrectSourceOptio await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion1, "Thisisfromopensourcerepo1.txt"); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion2, "Thisisfromopensourcerepo2.txt"); - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("OpensourceRepository", opensourceRepositoryPath); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.MVC.*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); From edaf988c02599df67ea31be9562004c0d52ac5c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:31:47 +0000 Subject: [PATCH 3/8] Stabilize two PMC package source mapping Apex tests Agent-Logs-Url: https://github.com/NuGet/NuGet.Client/sessions/69387abc-7df5-4ffa-ba29-f76c06e50ea5 Co-authored-by: nkolev92 <2878341+nkolev92@users.noreply.github.com> --- .../NuGetConsoleTestCase.cs | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index da68747bc42..4f0b225d931 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -491,19 +491,32 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithMultipleFeedsWithI [DataTestMethod] [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] [Timeout(DefaultTimeout)] - public void InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_Fails(ProjectTemplate projectTemplate) + public async Task InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_Fails(ProjectTemplate projectTemplate) { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - var privateRepositoryPath = Path.Combine(simpleTestPathContext.SolutionRoot, "PrivateRepository"); + var solutionDirectory = simpleTestPathContext.SolutionRoot; + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); var packageName = "SolutionLevelPkg"; var packageVersion = "1.0.0"; - // Package exists in default source but mapping routes Solution* to PrivateRepository where it doesn't exist. - simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); - simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Solution*"); + await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion); + + CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" + + + + + + + + + + + +"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); @@ -524,18 +537,31 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithCorrectSourceOpti using var simpleTestPathContext = new SimpleTestPathContext(); var solutionDirectory = simpleTestPathContext.SolutionRoot; + var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); + Directory.CreateDirectory(opensourceRepositoryPath); + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); var packageName = "Contoso.MVC.ASP"; var packageVersion = "1.0.0"; - // Opensource package in default "source", private package in PrivateRepository - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion, "Thisisfromprivaterepo1.txt"); - simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); - simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.MVC.*"); + CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" + + + + + + + + + + + +"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); From 9664654e981431e7a8f2ee776941b8178a75a0b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:34:08 +0000 Subject: [PATCH 4/8] Add fast-fail package creation assertion in wrong-mapped-feed test Agent-Logs-Url: https://github.com/NuGet/NuGet.Client/sessions/69387abc-7df5-4ffa-ba29-f76c06e50ea5 Co-authored-by: nkolev92 <2878341+nkolev92@users.noreply.github.com> --- .../NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index 4f0b225d931..8a020a58ef1 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -503,6 +503,7 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_F var packageVersion = "1.0.0"; await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion); + Assert.IsTrue(File.Exists(Path.Combine(simpleTestPathContext.PackageSource, $"{packageName}.{packageVersion}.nupkg"))); CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" From 23887cf14f6dd310ea73dd892d88c11a962eca5e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:51:49 +0000 Subject: [PATCH 5/8] Revert migrated PMC tests back to Settings-based source mapping config Agent-Logs-Url: https://github.com/NuGet/NuGet.Client/sessions/b7f564ae-9619-463a-9be9-20409e7b0ecf Co-authored-by: nkolev92 <2878341+nkolev92@users.noreply.github.com> --- .../NuGetConsoleTestCase.cs | 40 +++---------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index 8a020a58ef1..c0afe158fe3 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -495,8 +495,7 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_F { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - var solutionDirectory = simpleTestPathContext.SolutionRoot; - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + var privateRepositoryPath = Path.Combine(simpleTestPathContext.SolutionRoot, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); var packageName = "SolutionLevelPkg"; @@ -504,20 +503,8 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_F await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion); Assert.IsTrue(File.Exists(Path.Combine(simpleTestPathContext.PackageSource, $"{packageName}.{packageVersion}.nupkg"))); - - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Solution*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); @@ -538,31 +525,16 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithCorrectSourceOpti using var simpleTestPathContext = new SimpleTestPathContext(); var solutionDirectory = simpleTestPathContext.SolutionRoot; - var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); - Directory.CreateDirectory(opensourceRepositoryPath); - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); var packageName = "Contoso.MVC.ASP"; var packageVersion = "1.0.0"; - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion, "Thisisfromopensourcerepo1.txt"); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion, "Thisisfromprivaterepo1.txt"); - - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.MVC.*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); From ef5255f76b863849132caa5ae264fdd7be8125f6 Mon Sep 17 00:00:00 2001 From: Nikolche Kolev Date: Wed, 22 Apr 2026 19:08:11 -0700 Subject: [PATCH 6/8] cleanup --- .../NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index c0afe158fe3..f7a141c2c91 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -498,7 +498,7 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithWrongMappedFeed_F var privateRepositoryPath = Path.Combine(simpleTestPathContext.SolutionRoot, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); - var packageName = "SolutionLevelPkg"; + var packageName = "Pkg"; var packageVersion = "1.0.0"; await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion); From 7cdc3b9803e76d12371a57e6ed97cec40e865ac6 Mon Sep 17 00:00:00 2001 From: Nikolche Kolev Date: Thu, 23 Apr 2026 15:33:45 -0700 Subject: [PATCH 7/8] remove buggy tests --- .../NuGetConsoleTestCase.cs | 180 +++--------------- 1 file changed, 30 insertions(+), 150 deletions(-) diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index f7a141c2c91..320111d6b52 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -279,30 +279,12 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithSingleFeed(Projec { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - string solutionDirectory = simpleTestPathContext.SolutionRoot; - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); - Directory.CreateDirectory(privateRepositoryPath); var packageName = "Contoso.A"; var packageVersion = "1.0.0"; - await CommonUtility.CreatePackageInSourceAsync(privateRepositoryPath, packageName, packageVersion); - - //Create nuget.config with Package source mapping filtering rules. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - - -"); + await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "Contoso.*", "Test.*"); using (var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext)) { @@ -323,32 +305,14 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithSingleFeed(Project { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - string solutionDirectory = simpleTestPathContext.SolutionRoot; - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); - Directory.CreateDirectory(privateRepositoryPath); var packageName = "Contoso.A"; var packageVersion1 = "1.0.0"; var packageVersion2 = "2.0.0"; - await CommonUtility.CreatePackageInSourceAsync(privateRepositoryPath, packageName, packageVersion1); - await CommonUtility.CreatePackageInSourceAsync(privateRepositoryPath, packageName, packageVersion2); - - //Create nuget.config with Package source mapping filtering rules. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - - -"); + await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion1); + await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion2); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "Contoso.*", "Test.*"); using (var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext)) { @@ -375,11 +339,8 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithMultipleFeedsWith var packageVersion1 = "1.0.0"; var packageVersion2 = "2.0.0"; - var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); - Directory.CreateDirectory(opensourceRepositoryPath); - - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion1, "Thisisfromopensourcerepo1.txt"); - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion2, "Thisisfromopensourcerepo2.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion1, "Thisisfromopensourcerepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion2, "Thisisfromopensourcerepo2.txt"); var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); @@ -387,26 +348,9 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithMultipleFeedsWith await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion1, "Thisisfromprivaterepo1.txt"); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion2, "Thisisfromprivaterepo2.txt"); - //Create nuget.config with Package source mapping filtering rules. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "External.*", "Others.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.*", "Test.*"); using (var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext)) { @@ -420,7 +364,7 @@ public async Task InstallPackageForPC_PackageSourceMapping_WithMultipleFeedsWith var packagesDirectory = Path.Combine(solutionDirectory, "packages"); var uniqueContentFile = Path.Combine(packagesDirectory, packageName + '.' + packageVersion1, "lib", "net45", "Thisisfromprivaterepo1.txt"); - // Make sure name squatting package not restored from opensource repository. + // Make sure name squatting package not restored from opensource repository. Assert.IsTrue(File.Exists(uniqueContentFile)); } } @@ -437,11 +381,8 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithMultipleFeedsWithI var packageVersion1 = "1.0.0"; var packageVersion2 = "2.0.0"; - var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); - Directory.CreateDirectory(opensourceRepositoryPath); - - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion1, "Thisisfromopensourcerepo1.txt"); - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion2, "Thisisfromopensourcerepo2.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion1, "Thisisfromopensourcerepo1.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion2, "Thisisfromopensourcerepo2.txt"); var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); @@ -449,26 +390,9 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithMultipleFeedsWithI await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion1, "Thisisfromprivaterepo1.txt"); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion2, "Thisisfromprivaterepo2.txt"); - //Create nuget.config with Package source mapping filtering rules. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "External.*", "Others.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.*", "Test.*"); using (var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext)) { @@ -483,7 +407,7 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithMultipleFeedsWithI var packagesDirectory = Path.Combine(solutionDirectory, "packages"); var uniqueContentFile = Path.Combine(packagesDirectory, packageName + '.' + packageVersion2, "lib", "net45", "Thisisfromprivaterepo2.txt"); - // Make sure name squatting package not restored from opensource repository. + // Make sure name squatting package not restored from opensource repository. Assert.IsTrue(File.Exists(uniqueContentFile)); } } @@ -674,42 +598,20 @@ public async Task InstallPackageForPR_PackageNamespace_WithMultipleFeedsWithIden { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - string solutionDirectory = simpleTestPathContext.SolutionRoot; var packageName = "Contoso.A"; var packageVersion1 = "1.0.0"; - var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); - Directory.CreateDirectory(opensourceRepositoryPath); - - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion1); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion1); - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + var privateRepositoryPath = Path.Combine(simpleTestPathContext.SolutionRoot, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion1); - //Create nuget.config with Package namespace filtering rules. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.Config"), $@" - - - - - - - - - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "External.*", "Others.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.*", "Test.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("nuget", "Microsoft.*", "NetStandard*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: true, simpleTestPathContext: simpleTestPathContext); var nugetConsole = GetConsole(testContext.Project); @@ -731,45 +633,23 @@ public async Task UpdatePackageForPR_PackageNamespace_WithMultipleFeedsWithIdent { // Arrange using var simpleTestPathContext = new SimpleTestPathContext(); - string solutionDirectory = simpleTestPathContext.SolutionRoot; var packageName = "Contoso.A"; var packageVersion1 = "1.0.0"; var packageVersion2 = "2.0.0"; - var opensourceRepositoryPath = Path.Combine(solutionDirectory, "OpensourceRepository"); - Directory.CreateDirectory(opensourceRepositoryPath); - - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion1); - await CommonUtility.CreateNetFrameworkPackageInSourceAsync(opensourceRepositoryPath, packageName, packageVersion2); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion1); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion2); - var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + var privateRepositoryPath = Path.Combine(simpleTestPathContext.SolutionRoot, "PrivateRepository"); Directory.CreateDirectory(privateRepositoryPath); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion1); await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion2); - //Create nuget.config with Package namespace filtering rules. - CommonUtility.CreateConfigurationFile(Path.Combine(solutionDirectory, "NuGet.config"), $@" - - - - - - - - - - - - - - - - - - - -"); + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "External.*", "Others.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.*", "Test.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("nuget", "Microsoft.*", "NetStandard*"); using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: true, simpleTestPathContext: simpleTestPathContext); var solutionService = VisualStudio.Get(); From a5af501c268b5cebd0f262e93af5cf41496b32b0 Mon Sep 17 00:00:00 2001 From: Nikolche Kolev Date: Thu, 23 Apr 2026 17:29:44 -0700 Subject: [PATCH 8/8] Migrate PackageNameSpaceTests and fix source mapping tests to use SimpleTestPathContext - Migrate 2 PS PackageNameSpaceTests (restore with source mapping) to Apex - Fix 6 NuGetConsoleTestCase tests to use SimpleTestPathContext APIs instead of CreateConfigurationFile - Remove migrated PS functions and CreateCustomTestPackage helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/EndToEnd/tests/PackageNameSpaceTests.ps1 | 172 ------------------ .../NuGetConsoleTestCase.cs | 75 ++++++++ 2 files changed, 75 insertions(+), 172 deletions(-) diff --git a/test/EndToEnd/tests/PackageNameSpaceTests.ps1 b/test/EndToEnd/tests/PackageNameSpaceTests.ps1 index 11ae04fec0c..8b137891791 100644 --- a/test/EndToEnd/tests/PackageNameSpaceTests.ps1 +++ b/test/EndToEnd/tests/PackageNameSpaceTests.ps1 @@ -1,173 +1 @@ -function Test-PackageSourceMappingRestore-WithSingleFeed -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - # Arrange - $repoDirectory = $context.RepositoryRoot - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - -"@ - - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $repoDirectory | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - # Write a file to disk, but do not add it to project - ' - - ' | out-file $packagesConfigPath - - # Act - Build-Solution - - # Assert - $packagesFolder = Join-Path $solutionDirectory "packages" - $solutionLevelPkgNupkgFolder = Join-Path $packagesFolder "SolutionLevelPkg.1.0.0" - Assert-PathExists(Join-Path $solutionLevelPkgNupkgFolder "SolutionLevelPkg.1.0.0.nupkg") - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item $nugetConfigPath - } -} - -function Test-PackageSourceMappingRestore-WithMultipleFeedsWithIdenticalPackages-RestoresCorrectPackage -{ - [SkipTest('https://github.com/NuGet/Home/issues/12185')] - param($context) - - # Arrange - $repoDirectory = Join-Path $OutputPath "CustomPackages" - $opensourceRepo = Join-Path $repoDirectory "opensourceRepo" - $privateRepo = Join-Path $repoDirectory "privateRepo" - $nugetConfigPath = Join-Path $OutputPath 'nuget.config' - - $settingFileContent =@" - - - - - - - - - - - - - -"@ - try { - # We have to create config file before creating solution, otherwise it's not effective for new solutions. - $settingFileContent -f $opensourceRepo,$privateRepo | Out-File -Encoding "UTF8" $nugetConfigPath - - $p = New-ConsoleApplication - - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $packagesConfigPath = Join-Path $projectDirectoryPath 'packages.config' - $projectDirectoryPath = $p.Properties.Item("FullPath").Value - $solutionDirectory = Split-Path -Path $projectDirectoryPath -Parent - # Write a file to disk, but do not add it to project - ' - - ' | out-file $packagesConfigPath - - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $privateRepo "Thisisfromprivaterepo.txt" - CreateCustomTestPackage "Contoso.MVC.ASP" "1.0.0" $opensourceRepo "Thisisfromopensourcerepo.txt" - - # Act - Build-Solution - - # Assert - $packagesFolder = Join-Path $solutionDirectory "packages" - $contosoNupkgFolder = Join-Path $packagesFolder "Contoso.MVC.ASP.1.0.0" - Assert-PathExists(Join-Path $contosoNupkgFolder "Contoso.MVC.ASP.1.0.0.nupkg") - # Make sure name squatting package from public repo not restored. - $contentFolder = Join-Path $contosoNupkgFolder "content" - Assert-PathExists(Join-Path $contentFolder "Thisisfromprivaterepo.txt") - - $errorlist = Get-Errors - Assert-AreEqual 0 $errorlist.Count - } - finally { - Remove-Item -Recurse -Force $repoDirectory - Remove-Item $nugetConfigPath - } -} - -# Create a custom test package -function CreateCustomTestPackage { - param( - [string]$id, - [string]$version, - [string]$outputDirectory, - [string]$requestAdditionalContent - ) - - $builder = New-Object NuGet.Packaging.PackageBuilder - $builder.Authors.Add("test_author") - $builder.Id = $id - $builder.Version = [NuGet.Versioning.NuGetVersion]::Parse($version) - $builder.Description = "description" - - # add one content file - $tempFile = [IO.Path]::GetTempFileName() - "temp1" >> $tempFile - $packageFile = New-Object NuGet.Packaging.PhysicalPackageFile - $packageFile.SourcePath = $tempFile - $packageFile.TargetPath = "content\$id-test1.txt" - $builder.Files.Add($packageFile) - - if($requestAdditionalContent) - { - # add one content file - $tempFile2 = [IO.Path]::GetTempFileName() - "temp2" >> $tempFile2 - $packageFile = New-Object NuGet.Packaging.PhysicalPackageFile - $packageFile.SourcePath = $tempFile2 - $packageFile.TargetPath = "content\$requestAdditionalContent" - $builder.Files.Add($packageFile) - } - - if(-not(Test-Path $outputDirectory)) - { - New-Item -Path $outputDirectory -ItemType Directory - } - - $outputFileName = Join-Path $outputDirectory "$id.$version.nupkg" - $outputStream = New-Object IO.FileStream($outputFileName, [System.IO.FileMode]::Create) - try { - $builder.Save($outputStream) - } - finally - { - $outputStream.Dispose() - Remove-Item $tempFile - if($tempFile2) - { - Remove-Item $tempFile2 - } - } -} diff --git a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs index 320111d6b52..187b125909d 100644 --- a/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs +++ b/test/NuGet.Tests.Apex/NuGet.Tests.Apex/NuGetEndToEndTests/NuGetConsoleTestCase.cs @@ -412,6 +412,81 @@ public async Task UpdatePackageForPC_PackageSourceMapping_WithMultipleFeedsWithI } } + [DataTestMethod] + [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] + [Timeout(DefaultTimeout)] + public async Task RestorePackageForPC_PackageSourceMapping_WithSingleFeed(ProjectTemplate projectTemplate) + { + // Arrange + using var simpleTestPathContext = new SimpleTestPathContext(); + + var packageName = "SolutionLevelPkg"; + var packageVersion = "1.0.0"; + + await CommonUtility.CreatePackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "Soluti*"); + + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); + + var projectDirectory = Path.GetDirectoryName(testContext.Project.FullPath); + var packagesConfigPath = Path.Combine(projectDirectory, "packages.config"); + File.WriteAllText(packagesConfigPath, +@" + +"); + + // Act + testContext.SolutionService.Build(); + + // Assert + var packagesDirectory = Path.Combine(simpleTestPathContext.SolutionRoot, "packages"); + var nupkgPath = Path.Combine(packagesDirectory, $"{packageName}.{packageVersion}", $"{packageName}.{packageVersion}.nupkg"); + Assert.IsTrue(File.Exists(nupkgPath), $"'{nupkgPath}' should exist"); + } + + [DataTestMethod] + [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] + [Timeout(DefaultTimeout)] + public async Task RestorePackageForPC_PackageSourceMapping_WithMultipleFeedsWithIdenticalPackages_RestoresCorrectPackage(ProjectTemplate projectTemplate) + { + // Arrange + using var simpleTestPathContext = new SimpleTestPathContext(); + string solutionDirectory = simpleTestPathContext.SolutionRoot; + + var packageName = "Contoso.MVC.ASP"; + var packageVersion = "1.0.0"; + + var privateRepositoryPath = Path.Combine(solutionDirectory, "PrivateRepository"); + Directory.CreateDirectory(privateRepositoryPath); + + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(simpleTestPathContext.PackageSource, packageName, packageVersion, "Thisisfromopensourcerepo.txt"); + await CommonUtility.CreateNetFrameworkPackageInSourceAsync(privateRepositoryPath, packageName, packageVersion, "Thisisfromprivaterepo.txt"); + + simpleTestPathContext.Settings.AddSource("PrivateRepository", privateRepositoryPath); + simpleTestPathContext.Settings.AddPackageSourceMapping("source", "Others.*"); + simpleTestPathContext.Settings.AddPackageSourceMapping("PrivateRepository", "Contoso.MVC.*"); + + using var testContext = new ApexTestContext(VisualStudio, projectTemplate, Logger, noAutoRestore: false, addNetStandardFeeds: false, simpleTestPathContext: simpleTestPathContext); + + var projectDirectory = Path.GetDirectoryName(testContext.Project.FullPath); + var packagesConfigPath = Path.Combine(projectDirectory, "packages.config"); + File.WriteAllText(packagesConfigPath, +@" + +"); + + // Act + testContext.SolutionService.Build(); + + // Assert + var packagesDirectory = Path.Combine(solutionDirectory, "packages"); + var packageFolder = Path.Combine(packagesDirectory, $"{packageName}.{packageVersion}"); + Assert.IsTrue(File.Exists(Path.Combine(packageFolder, $"{packageName}.{packageVersion}.nupkg")), "Package nupkg should exist"); + // Make sure name squatting package not restored from opensource repository. + var uniqueContentFile = Path.Combine(packageFolder, "lib", "net45", "Thisisfromprivaterepo.txt"); + Assert.IsTrue(File.Exists(uniqueContentFile), $"'{uniqueContentFile}' should exist"); + } + [DataTestMethod] [DynamicData(nameof(GetPackagesConfigTemplates), DynamicDataSourceType.Method)] [Timeout(DefaultTimeout)]