diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryEnvironment.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryEnvironment.cs new file mode 100644 index 00000000000..dc55b8c4bc9 --- /dev/null +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryEnvironment.cs @@ -0,0 +1,23 @@ +namespace NuGetUpdater.Core.Test; + +public class TemporaryEnvironment : IDisposable +{ + private readonly List<(string Name, string? Value)> _originalVariables = new(); + + public TemporaryEnvironment((string Name, string Value)[] variables) + { + foreach (var (name, value) in variables) + { + _originalVariables.Add((name, Environment.GetEnvironmentVariable(name))); + Environment.SetEnvironmentVariable(name, value); + } + } + + public void Dispose() + { + foreach (var (name, value) in _originalVariables) + { + Environment.SetEnvironmentVariable(name, value); + } + } +} diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs index 6217f51f6a6..993c79f9b5d 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs @@ -1,6 +1,9 @@ using System.Collections.Immutable; +using System.Text; using System.Text.Json; +using NuGet; + using NuGetUpdater.Core.Updater; using Xunit; @@ -1663,67 +1666,173 @@ await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1", [Fact] public async Task PackageCanBeUpdatedWhenAnotherInstalledPackageHasBeenDelisted() { - // updating one package (Newtonsoft.Json) when another installed package (FSharp.Core/5.0.3-beta.21369.4) has been delisted - await TestUpdateForProject("Newtonsoft.Json", "7.0.1", "13.0.1", + // updating one package (Some.Package) when another installed package (Delisted.Package/5.0.0) has been delisted + // this test can't be faked with a local package source and requires an HTTP endpoint; the important part is + // the `"listed": false` in the registration index + static (int, byte[]) TestHttpHandler(string uriString) + { + var uri = new Uri(uriString, UriKind.Absolute); + var baseUrl = $"{uri.Scheme}://{uri.Host}:{uri.Port}"; + return uri.PathAndQuery switch + { + "/index.json" => (200, Encoding.UTF8.GetBytes($$""" + { + "version": "3.0.0", + "resources": [ + { + "@id": "{{baseUrl}}/download", + "@type": "PackageBaseAddress/3.0.0" + }, + { + "@id": "{{baseUrl}}/query", + "@type": "SearchQueryService" + }, + { + "@id": "{{baseUrl}}/registrations", + "@type": "RegistrationsBaseUrl" + } + ] + } + """)), + "/registrations/delisted.package/index.json" => (200, Encoding.UTF8.GetBytes($$""" + { + "count": 1, + "items": [ + { + "lower": "5.0.0", + "upper": "5.0.0", + "items": [ + { + "catalogEntry": { + "id": "Delisted.Package", + "listed": false, + "version": "5.0.0" + }, + "packageContent": "{{baseUrl}}/download/delisted.package/5.0.0/delisted.package.5.0.0.nupkg", + } + ] + } + ] + } + """)), + "/registrations/some.package/index.json" => (200, Encoding.UTF8.GetBytes($$""" + { + "count": 1, + "items": [ + { + "lower": "1.0.0", + "upper": "2.0.0", + "items": [ + { + "catalogEntry": { + "id": "Some.Package", + "listed": true, + "version": "1.0.0" + }, + "packageContent": "{{baseUrl}}/download/some.package/1.0.0/some.package.1.0.0.nupkg", + }, + { + "catalogEntry": { + "id": "Some.Package", + "listed": true, + "version": "2.0.0" + }, + "packageContent": "{{baseUrl}}/download/some.package/2.0.0/some.package.2.0.0.nupkg", + } + ] + } + ] + } + """)), + "/download/delisted.package/5.0.0/delisted.package.5.0.0.nupkg" => + (200, MockNuGetPackage.CreateSimplePackage("Delisted.Package", "5.0.0", "net45").GetZipStream().ReadAllBytes()), + "/download/some.package/1.0.0/some.package.1.0.0.nupkg" => + (200, MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net45").GetZipStream().ReadAllBytes()), + "/download/some.package/2.0.0/some.package.2.0.0.nupkg" => + (200, MockNuGetPackage.CreateSimplePackage("Some.Package", "2.0.0", "net45").GetZipStream().ReadAllBytes()), + _ => (404, Encoding.UTF8.GetBytes("{}")), // everything is missing + }; + } + using var cache = new TemporaryDirectory(); + using var env = new TemporaryEnvironment([ + ("NUGET_PACKAGES", Path.Join(cache.DirectoryPath, "NUGET_PACKAGES")), + ("NUGET_HTTP_CACHE_PATH", Path.Join(cache.DirectoryPath, "NUGET_HTTP_CACHE_PATH")), + ("NUGET_SCRATCH", Path.Join(cache.DirectoryPath, "NUGET_SCRATCH")), + ("NUGET_PLUGINS_CACHE_PATH", Path.Join(cache.DirectoryPath, "NUGET_PLUGINS_CACHE_PATH")), + ]); + using var http = TestHttpServer.CreateTestServer(TestHttpHandler); + await TestUpdateForProject("Some.Package", "1.0.0", "2.0.0", // existing projectContents: """ - - - - v4.6.2 - - - - - - - packages\FSharp.Core.5.0.3-beta.21369.4\lib\netstandard2.0\FSharp.Core.dll - True - - - packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True - - - - - """, + + + + v4.6.2 + + + + + + + packages\Delisted.Package.5.0.0\lib\net45\Delisted.Package.dll + True + + + packages\Some.Package.1.0.0\lib\net45\Some.Package.dll + True + + + + + """, packagesConfigContents: """ - - - - - """, + + + + + """, + additionalFiles: + [ + ("NuGet.Config", $""" + + + + + + + """) + ], // expected expectedProjectContents: """ - - - - v4.6.2 - - - - - - - packages\FSharp.Core.5.0.3-beta.21369.4\lib\netstandard2.0\FSharp.Core.dll - True - - - packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - True - - - - - """, + + + + v4.6.2 + + + + + + + packages\Delisted.Package.5.0.0\lib\net45\Delisted.Package.dll + True + + + packages\Some.Package.2.0.0\lib\net45\Some.Package.dll + True + + + + + """, expectedPackagesConfigContents: """ - - - - - - """); + + + + + + """ + ); } [Fact]