File: NuGet\NuGetConfigurationTests.cs
Web Access
Project: src\tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj (Aspire.Cli.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Cli.NuGet;
using Aspire.Cli.Packaging;
using Aspire.Cli.Tests.TestServices;
using Microsoft.Extensions.Logging.Abstractions;
 
namespace Aspire.Cli.Tests.NuGet;
 
public class NuGetConfigurationTests
{
    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void BuildStableAppHostConfiguration_PreservesExistingPublicAliasAndDisabledState(bool isEnabled)
    {
        var settings = CreateSettings(
        [
            new("company", ["*"]),
            new("aspire-test", ["Aspire*"]),
            new("aspire-test-0", ["Aspire*"])
        ]);
        settings = settings with
        {
            Sources =
            [
                new("company", "company", true, false, false),
                new("aspire-test", "daily", true, false, false),
                new("aspire-test-0", NuGetSourceIdentity.Compute(PackageSources.NuGetOrg, settings.SourceIdentityKey), isEnabled, true, false)
            ],
            DisabledPackageSourceKeys = isEnabled ? [] : ["aspire-test-0"]
        };
        var channel = PackageChannel.CreateExplicitChannel(
            "stable", PackageChannelQuality.Stable,
            [new("*", "https://company.example/v3/index.json")],
            new FakeNuGetPackageCache(), new TestFeatures(), NullLogger.Instance);
 
        var configuration = NuGetConfigurationBuilder.BuildStableAppHostConfiguration(settings, "test", channel);
 
        var overlay = Assert.IsType<NuGetConfigOverlay>(configuration.Overlay);
        Assert.Empty(overlay.Sources);
        Assert.Equal(["aspire-test"], overlay.RetiredSourceKeys);
        Assert.Equal(isEnabled ? ["aspire-test"] : ["aspire-test-0", "aspire-test"], overlay.DisabledPackageSourceKeys);
        Assert.Collection(overlay.PackageSourceMappings,
            mapping =>
            {
                Assert.Equal("company", mapping.SourceKey);
                Assert.Equal(["*"], mapping.Patterns);
            },
            mapping =>
            {
                Assert.Equal("aspire-test-0", mapping.SourceKey);
                Assert.Equal(["Aspire*"], mapping.Patterns);
            });
    }
 
    [Theory]
    [InlineData("aspire-test", false)]
    [InlineData("legacy-hive", true)]
    [InlineData("ASPIRE-DAILY", false)]
    [InlineData("aspire-staging", false)]
    [InlineData("aspire-pr-19763", false)]
    [InlineData("aspire-apphost-0123456789abcdef", false)]
    [InlineData("aspire-apphost-0123456789abcdef-0", false)]
    public void BuildStableAppHostConfiguration_PreservesUnrelatedMappingsOnChannelSource(string sourceKey, bool isCliManaged)
    {
        var settings = CreateSettings(
        [
            new("company", ["Aspire.Hosting.Redis", "Company.*"]),
            new(sourceKey, ["Aspire*", "Private.*"])
        ]) with
        {
            Sources =
            [
                new("company", "company", true, true, true),
                new(sourceKey, "channel", true, true, false) { IsCliManaged = isCliManaged }
            ]
        };
        var channel = PackageChannel.CreateExplicitChannel(
            "stable", PackageChannelQuality.Stable, [new("*", PackageSources.NuGetOrg)],
            new FakeNuGetPackageCache(), new TestFeatures(), NullLogger.Instance);
 
        var configuration = NuGetConfigurationBuilder.BuildStableAppHostConfiguration(settings, "test", channel);
 
        var overlay = Assert.IsType<NuGetConfigOverlay>(configuration.Overlay);
        Assert.Empty(overlay.Sources);
        Assert.Empty(overlay.RetiredSourceKeys);
        Assert.False(overlay.ClearDisabledPackageSources);
        Assert.Collection(overlay.PackageSourceMappings,
            mapping =>
            {
                Assert.Equal("company", mapping.SourceKey);
                Assert.Equal(["Aspire.Hosting.Redis", "Company.*"], mapping.Patterns);
            },
            mapping =>
            {
                Assert.Equal(sourceKey, mapping.SourceKey);
                Assert.Equal(["Private.*"], mapping.Patterns);
            });
    }
 
    [Fact]
    public void BuildStableAppHostConfiguration_DoesNotAddFallbackWhenOnlyChannelSourceExists()
    {
        var settings = CreateSettings([new("aspire-test", ["Aspire*"])]) with
        {
            Sources = [new("aspire-test", "daily", true, false, false)]
        };
        var channel = PackageChannel.CreateExplicitChannel(
            "stable", PackageChannelQuality.Stable, [new("*", PackageSources.NuGetOrg)],
            new FakeNuGetPackageCache(), new TestFeatures(), NullLogger.Instance);
 
        var configuration = NuGetConfigurationBuilder.BuildStableAppHostConfiguration(settings, "test", channel);
 
        var overlay = Assert.IsType<NuGetConfigOverlay>(configuration.Overlay);
        Assert.Empty(overlay.Sources);
        Assert.Empty(overlay.PackageSourceMappings);
        Assert.Equal(["aspire-test"], overlay.RetiredSourceKeys);
        Assert.Equal(["aspire-test"], overlay.DisabledPackageSourceKeys);
        Assert.True(overlay.ClearPackageSourceMappings);
    }
 
    [Fact]
    public void HasSourcePolicyChanges_AmbientPolicyIsUnchanged()
    {
        var configuration = new NuGetConfiguration(CreateSettings([]), [], overlay: null);
 
        Assert.False(configuration.HasSourcePolicyChanges);
    }
 
    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void HasSourcePolicyChanges_MappingOrderAndCaseAreIgnored(bool clearMappings)
    {
        var settings = CreateSettings(
        [
            new("company", ["Aspire*", "Company.*"]),
            new("public", ["*"])
        ]);
        var overlay = new NuGetConfigOverlay(
            [], [new("PUBLIC", ["*"]), new("COMPANY", ["company.*", "ASPIRE*"])], false, [], null)
        {
            ClearPackageSourceMappings = clearMappings
        };
 
        Assert.False(new NuGetConfiguration(settings, [], overlay).HasSourcePolicyChanges);
    }
 
    [Theory]
    [InlineData("company", "Other.*")]
    [InlineData("other", "Aspire*")]
    public void HasSourcePolicyChanges_ChangedMappingIsDetected(string sourceKey, string pattern)
    {
        var settings = CreateSettings([new("company", ["Aspire*"])]);
        var overlay = new NuGetConfigOverlay([], [new(sourceKey, [pattern])], false, [], null);
 
        Assert.True(new NuGetConfiguration(settings, [], overlay).HasSourcePolicyChanges);
    }
 
    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void HasSourcePolicyChanges_EmptyMappingOnlyChangesPolicyWhenCleared(bool clearMappings)
    {
        var settings = CreateSettings([new("company", ["Aspire*"])]);
        var overlay = new NuGetConfigOverlay([], [], false, [], null)
        {
            ClearPackageSourceMappings = clearMappings
        };
 
        Assert.Equal(clearMappings, new NuGetConfiguration(settings, [], overlay).HasSourcePolicyChanges);
    }
 
    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void HasSourcePolicyChanges_DisabledSourcesAreComparedByEffectiveState(bool reenableSource)
    {
        var settings = CreateSettings([]) with
        {
            Sources = [new("company", "identity", false, false, false)],
            DisabledPackageSourceKeys = ["company"]
        };
        var overlay = new NuGetConfigOverlay([], [], true, reenableSource ? [] : ["COMPANY"], null);
 
        Assert.Equal(reenableSource, new NuGetConfiguration(settings, [], overlay).HasSourcePolicyChanges);
    }
 
    [Fact]
    public void HasSourcePolicyChanges_NewSourceIsDetected()
    {
        var overlay = new NuGetConfigOverlay([("new", "https://feed.example/v3/index.json")], [], false, [], null);
 
        Assert.True(new NuGetConfiguration(CreateSettings([]), [], overlay).HasSourcePolicyChanges);
    }
 
    [Theory]
    [InlineData(false)]
    [InlineData(true)]
    public void HasSourcePolicyChanges_RetiredSourceOnlyChangesPolicyWhenStillEnabled(bool isEnabled)
    {
        var overlay = new NuGetConfigOverlay([], [], false, [], null) { RetiredSourceKeys = ["old"] };
        var settings = CreateSettings([]) with
        {
            Sources = [new("old", "identity", isEnabled, false, false)]
        };
 
        Assert.Equal(isEnabled, new NuGetConfiguration(settings, [], overlay).HasSourcePolicyChanges);
    }
 
    [Fact]
    public void HasSourcePolicyChanges_CacheFolderIsNotASourcePolicyChange()
    {
        var overlay = new NuGetConfigOverlay([], [], false, [], ".packages");
 
        Assert.False(new NuGetConfiguration(CreateSettings([]), [], overlay).HasSourcePolicyChanges);
    }
 
    private static NuGetSettingsInfo CreateSettings(IReadOnlyList<NuGetPackageSourceMapping> mappings)
        => new([], "ambient", [], [], mappings, [], [], new byte[NuGetSourceIdentity.KeySizeInBytes]);
}