Test and get the nuget via the NuGet v3 protocol

This commit is contained in:
Paul Schneider 2026-07-05 23:33:48 +01:00
commit 4e4d7f0fd7
3 changed files with 84 additions and 6 deletions

View file

@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Isn.Abstract;
using isnd.Entities;
@ -10,13 +11,28 @@ namespace isnd.Controllers
public partial class PackagesController
{
// Web get the paquet
[HttpGet("~/" + Constants.APIPrefix + ApiConfig.GetPackage + "/{id}/{lower}/{idf}-{lowerf}."
// NuGet v3 flat-container versions index.
[HttpGet("~/" + Constants.APIPrefix + ApiConfig.GetPackage + "/{id}/" + ApiConfig.IndexDotJson)]
public IActionResult GetPackageVersionsById(
[FromRoute][SafeName][Required] string id)
{
var versions = dbContext.PackageVersions
.Where(v => v.PackageId.ToLower() == id.ToLower())
.Select(v => v.FullString)
.Distinct()
.OrderBy(v => v)
.ToArray();
return Ok(new { versions });
}
// NuGet v3 flat-container package download by filename, e.g. id.version.nupkg.
[HttpGet("~/" + Constants.APIPrefix + ApiConfig.GetPackage + "/{id}/{lower}/{filename}."
+ Constants.PaquetFileEstension)]
public IActionResult GetPackage(
public IActionResult GetPackageByFilename(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute] string idf, [FromRoute] string lowerf)
[FromRoute][SafeName][Required] string filename)
{
var pkgpath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}-{lower}." + Constants.PaquetFileEstension
@ -32,6 +48,8 @@ namespace isnd.Controllers
}
// Web get spec
[HttpGet("~/" + Constants.APIPrefix + Constants.SpecFileEstension + "/{id}/{lower}/{idf}.{lowerf}."
+ Constants.SpecFileEstension)]
[HttpGet("~/" + Constants.APIPrefix + Constants.SpecFileEstension + "/{id}/{lower}/{idf}-{lowerf}."
+ Constants.SpecFileEstension)]
public IActionResult GetNuspec(

View file

@ -50,7 +50,8 @@ namespace isnd.Services
},
// under dev, only leash in release mode
new Resource(extUrl + ApiConfig.GetPackage, "PackageBaseAddress/3.0.0")
// NuGet clients expect a trailing slash on PackageBaseAddress to resolve relative paths.
new Resource(extUrl + ApiConfig.GetPackage + "/", "PackageBaseAddress/3.0.0")
{
Comment = @"Package Base Address service - Base URL of where NuGet packages are stored, in the format https://<host>/nupkg/{id-lower}/{version-lower}/{id-lower}.{version-lower}.nupkg"
},

View file

@ -17,9 +17,11 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NuGet.Common;
using NuGet.Configuration;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
using Xunit;
namespace isnd.host.tests
@ -168,6 +170,63 @@ namespace isnd.host.tests
await AssertAutocompleteContainsPushedVersionAsync(DummyPackageId, DummyPackageVersion);
}
[Fact]
public async Task NuGetV3ProtocolCanDownloadDummyPackage()
{
var apiKeyValue = $"dummy-key-{Guid.NewGuid():N}";
var packagePath = GetDummyArtifactPath();
Assert.True(File.Exists(packagePath), $"Missing dummy artifact at {packagePath}");
using (var serviceScope = server.Host.Services.CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var userId = $"dummy-user-{Guid.NewGuid():N}";
await ResetDummyPackageStateAsync(serviceScope.ServiceProvider, dbContext);
dbContext.Users.Add(new ApplicationUser
{
Id = userId,
UserName = userId,
NormalizedUserName = userId.ToUpperInvariant(),
Email = $"{userId}@tests.local",
NormalizedEmail = $"{userId}@tests.local".ToUpperInvariant(),
EmailConfirmed = true
});
dbContext.ApiKeys.Add(new ApiKey
{
Id = apiKeyValue,
UserId = userId,
Name = "dummy-key",
CreationDate = DateTime.UtcNow,
ValidityPeriodInDays = 30
});
await dbContext.SaveChangesAsync();
}
await PushPackageAsync(packagePath, apiKeyValue);
var indexUrl = GetServerBaseUrl() + "/" + Constants.APIPrefix + "index.json";
var repository = Repository.Factory.GetCoreV3(indexUrl);
var findPackageById = await repository.GetResourceAsync<FindPackageByIdResource>();
Assert.NotNull(findPackageById);
await using var nupkgStream = new MemoryStream();
using var cache = new SourceCacheContext();
var copied = await findPackageById.CopyNupkgToStreamAsync(
DummyPackageId,
NuGetVersion.Parse(DummyPackageVersion),
nupkgStream,
cache,
NullLogger.Instance,
CancellationToken.None);
Assert.True(copied, "NuGet v3 client could not download the package from the feed.");
Assert.True(nupkgStream.Length > 0, "Downloaded package stream is empty.");
}
[Fact]
public void TestRegistrationV3Resource()
{