Skip to content

Commit

Permalink
Recommender feed and regular search merging should be ignore case for…
Browse files Browse the repository at this point in the history
… ids (#6126)
  • Loading branch information
nkolev92 authored Oct 30, 2024
1 parent 2e9c4ec commit d216c44
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public RecommenderPackageFeed(
PackageCollection transitivePackages,
IReadOnlyCollection<string> targetFrameworks,
IPackageMetadataProvider metadataProvider,
Common.ILogger logger)
ILogger logger)
{
if (sourceRepositories == null)
{
Expand All @@ -68,10 +68,10 @@ public RecommenderPackageFeed(
_logger = logger ?? throw new ArgumentNullException(nameof(logger));

// The recommender package feed should only created when one of the sources is nuget.org.
if (sourceRepositories.Any(item => UriUtility.IsNuGetOrg(item.PackageSource.Source)))
{
_sourceRepository = sourceRepositories.First(item => UriUtility.IsNuGetOrg(item.PackageSource.Source));
_sourceRepository = sourceRepositories.FirstOrDefault(item => UriUtility.IsNuGetOrg(item.PackageSource.Source));

if (_sourceRepository != null)
{
_installedPackages = installedPackages.Select(item => item.Id).ToList();
_transitivePackages = transitivePackages.Select(item => item.Id).ToList();

Expand Down Expand Up @@ -158,7 +158,6 @@ private async Task<SearchResult<IPackageSearchMetadata>> RecommendPackagesAsync(
int index = 0;
List<PackageIdentity> recommendPackages = new List<PackageIdentity>();
MetadataResource _metadataResource = await _sourceRepository.GetResourceAsync<MetadataResource>(cancellationToken);
PackageMetadataResource _packageMetadataResource = await _sourceRepository.GetResourceAsync<PackageMetadataResource>(cancellationToken);
while (index < recommendIds.Count && recommendPackages.Count < MaxRecommended)
{
Versioning.NuGetVersion ver = await _metadataResource.GetLatestVersion(recommendIds[index], includePrerelease: false, includeUnlisted: false, NullSourceCacheContext.Instance, Common.NullLogger.Instance, cancellationToken);
Expand Down Expand Up @@ -221,12 +220,12 @@ private IdentityIdEqualityComparer()

public bool Equals(IPackageSearchMetadata x, IPackageSearchMetadata y)
{
return x.Identity.Id.Equals(y.Identity.Id);
return StringComparer.OrdinalIgnoreCase.Equals(x.Identity.Id, y.Identity.Id);
}

public int GetHashCode(IPackageSearchMetadata obj)
{
return obj.Identity.Id.GetHashCode();
return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Identity.Id);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ namespace NuGet.PackageManagement.VisualStudio.Test
{
public static class FeedTestUtils
{
internal static INuGetResourceProvider CreateTestResourceProvider(PackageMetadataResource _metadataResource)
internal static INuGetResourceProvider CreateTestResourceProvider<T>(T resource)
{
var provider = Mock.Of<INuGetResourceProvider>();
Mock.Get(provider)
.Setup(x => x.TryCreate(It.IsAny<SourceRepository>(), It.IsAny<CancellationToken>()))
.Returns(() => Task.FromResult(Tuple.Create(true, (INuGetResource)_metadataResource)));
.Returns(() => Task.FromResult(Tuple.Create(true, (INuGetResource)resource)));
Mock.Get(provider)
.Setup(x => x.ResourceType)
.Returns(typeof(PackageMetadataResource));
.Returns(typeof(T));

return provider;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,33 @@
using NuGet.Versioning;
using System.Threading;
using System.Threading.Tasks;
using NuGet.Configuration;
using Microsoft.VisualStudio.Sdk.TestFramework;
using Microsoft.DataAI.NuGetRecommender.Contracts;
using NuGet.Common;
using NuGet.VisualStudio.Internal.Contracts;
using FluentAssertions;

namespace NuGet.PackageManagement.VisualStudio.Test
{
public class RecommenderPackageFeedTests
[Collection(MockedVS.Collection)]
public class RecommenderPackageFeedTests : MockedVSCollectionTests
{
private readonly TestLogger _logger;
private readonly SourceRepository _sourceRepository;
private readonly IPackageMetadataProvider _packageMetadataProvider;
private readonly Mock<IVsNuGetPackageRecommender> _mockRecommender;

public RecommenderPackageFeedTests(GlobalServiceProvider globalServiceProvider, ITestOutputHelper testOutputHelper)
: base(globalServiceProvider)

public RecommenderPackageFeedTests(ITestOutputHelper testOutputHelper)
{
_mockRecommender = new Mock<IVsNuGetPackageRecommender>();
_mockRecommender.Setup(x => x.GetVersionInfo()).Returns(() => new Dictionary<string, string>
{
{ "Model", "1" },
{ "Vsix", "1" }
});
globalServiceProvider.AddService(typeof(SVsNuGetRecommenderService), _mockRecommender.Object);
_logger = new TestLogger(testOutputHelper);

var _metadataResource = Mock.Of<PackageMetadataResource>();
INuGetResourceProvider provider = FeedTestUtils.CreateTestResourceProvider(_metadataResource);
var packageSource = new Configuration.PackageSource("http://fake-source");
_sourceRepository = new SourceRepository(source: packageSource, providers: new[] { provider });

_packageMetadataProvider = new MultiSourcePackageMetadataProvider(sourceRepositories: [_sourceRepository], optionalLocalRepository: null, optionalGlobalLocalRepositories: null, logger: _logger);
}

[Fact]
Expand Down Expand Up @@ -125,14 +133,17 @@ public void Constructor_WithNullArgument_ThrowsArgumentNullException()
public async Task SearchAsync_WhenNoRecommendedPackages_ReturnsPackagesFromDecoratedFeedAsync()
{
// Arrange
var sourceRepository = new SourceRepository(new PackageSource("http://fake-source"), [FeedTestUtils.CreateTestResourceProvider(Mock.Of<PackageMetadataResource>())]);
var packageMetadataProvider = new MultiSourcePackageMetadataProvider(sourceRepositories: [sourceRepository], optionalLocalRepository: null, optionalGlobalLocalRepositories: null, logger: _logger);

var decoratedFeed = new Mock<IPackageFeed>();
var feed = new RecommenderPackageFeed(
decoratedFeed.Object,
sourceRepositories: [_sourceRepository],
sourceRepositories: [sourceRepository],
installedPackages: new PackageCollection([]),
transitivePackages: new PackageCollection([]),
targetFrameworks: [string.Empty],
metadataProvider: _packageMetadataProvider,
metadataProvider: packageMetadataProvider,
logger: _logger);

var expectedPackages = new List<IPackageSearchMetadata>()
Expand Down Expand Up @@ -160,5 +171,69 @@ public async Task SearchAsync_WhenNoRecommendedPackages_ReturnsPackagesFromDecor
// Assert
Assert.Equal(expectedPackages, actualPackages.Items);
}

[Theory]
[InlineData("packageB")]
[InlineData("packageb")]
public async Task SearchAsync_WithRecommenderPackages_MergesMetadata(string recommendedPackage)
{
// Arrange
var metadataResource = new Mock<MetadataResource>();
metadataResource.Setup(e => e.GetLatestVersions(It.IsAny<IEnumerable<string>>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<SourceCacheContext>(), It.IsAny<ILogger>(), It.IsAny<CancellationToken>()))
.ReturnsAsync([new KeyValuePair<string, NuGetVersion>("packageb", new NuGetVersion(2, 0, 0))]);

var packageMetadataResource = Mock.Of<PackageMetadataResource>();

var sourceRepository = new SourceRepository(new PackageSource(NuGetConstants.V3FeedUrl), [FeedTestUtils.CreateTestResourceProvider(metadataResource.Object), FeedTestUtils.CreateTestResourceProvider(packageMetadataResource)]);
var packageMetadataProvider = new MultiSourcePackageMetadataProvider(sourceRepositories: [sourceRepository], optionalLocalRepository: null, optionalGlobalLocalRepositories: null, logger: _logger);

var decoratedFeed = new Mock<IPackageFeed>();
var feed = new RecommenderPackageFeed(
decoratedFeed.Object,
sourceRepositories: [sourceRepository],
installedPackages: new PackageCollection([]),
transitivePackages: new PackageCollection([]),
targetFrameworks: [string.Empty],
metadataProvider: packageMetadataProvider,
logger: _logger);


var packageA = PackageSearchMetadataBuilder
.FromIdentity(new PackageIdentity("packageA", new NuGetVersion("1.0.0")))
.Build();

var packageB = PackageSearchMetadataBuilder
.FromIdentity(new PackageIdentity("packageB", new NuGetVersion("2.0.0")))
.Build();

var packageC = PackageSearchMetadataBuilder
.FromIdentity(new PackageIdentity("packageC", new NuGetVersion("3.0.0")))
.Build();

var expectedPackages = new List<IPackageSearchMetadata>()
{
new RecommendedPackageSearchMetadata(PackageSearchMetadataBuilder
.FromIdentity(new PackageIdentity(recommendedPackage, new NuGetVersion("2.0.0")))
.Build(),
("1", "1")),
packageA,
packageC,
};

_mockRecommender.Setup(e => e.GetRecommendedPackageIdsAsync(It.IsAny<IEnumerable<string>>(), It.IsAny<IEnumerable<string>>(), It.IsAny<IEnumerable<string>>(), It.IsAny<CancellationToken>()))
.ReturnsAsync([recommendedPackage]);

decoratedFeed.Setup(f => f.SearchAsync(
It.IsAny<string>(),
It.IsAny<SearchFilter>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(new SearchResult<IPackageSearchMetadata> { Items = [packageA, packageB, packageC] });

// Act
var actualPackages = await feed.SearchAsync(string.Empty, new SearchFilter(includePrerelease: false), It.IsAny<CancellationToken>());

// Assert
actualPackages.Items.Should().BeEquivalentTo(expectedPackages);
}
}
}

0 comments on commit d216c44

Please sign in to comment.