Skip to content

Commit e428f5b

Browse files
author
Scott Bommarito
authored
Minor fixes to the GET DeleteSymbols endpoint (#6937)
1 parent 935803e commit e428f5b

2 files changed

Lines changed: 109 additions & 53 deletions

File tree

src/NuGetGallery/Controllers/PackagesController.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,9 +1497,25 @@ await _readMeService.GetReadMeMdAsync(package),
14971497
[RequiresAccountConfirmation("delete a symbols package")]
14981498
public virtual ActionResult DeleteSymbols(string id, string version)
14991499
{
1500-
var package = _packageService.FindPackageByIdAndVersion(id, version, SemVerLevelKey.SemVer2);
1500+
Package package = null;
1501+
1502+
// Load all versions of the package.
1503+
var packages = _packageService.FindPackagesById(id);
1504+
if (version != null)
1505+
{
1506+
// Try to find the exact version if it was specified.
1507+
package = packages.SingleOrDefault(p => p.NormalizedVersion == NuGetVersionFormatter.Normalize(version));
1508+
}
1509+
15011510
if (package == null)
15021511
{
1512+
// If the exact version was not found, fall back to the latest version.
1513+
package = _packageService.FilterLatestPackage(packages, SemVerLevelKey.SemVer2, allowPrerelease: true);
1514+
}
1515+
1516+
if (package == null)
1517+
{
1518+
// If the package has no versions, return not found.
15031519
return HttpNotFound();
15041520
}
15051521

@@ -1511,26 +1527,19 @@ public virtual ActionResult DeleteSymbols(string id, string version)
15111527

15121528
var model = new DeletePackageViewModel(package, currentUser, DeleteReasons);
15131529

1514-
// Fetch all the available symbols package for all the versions from the
1515-
// database since the DisplayPackageViewModel(base class for DeletePackageViewModel) does not
1516-
// set the `LatestSymbolsPackage` data on the model(since it is an unnecessary and expensive db
1517-
// query). It is fine to do this here when invoking delete page. Note: this could also potentially
1518-
// cause unbounded(high number) db calls based on the number of versions associated with a package.
1519-
var packageViewModelsForAllAvailableSymbolsPackage = package
1520-
.PackageRegistration
1521-
.Packages
1530+
// Fetch all versions of the package with symbols.
1531+
var versionsWithSymbols = packages
15221532
.Where(p => p.PackageStatusKey != PackageStatus.Deleted)
1523-
.Select(p => p.LatestSymbolPackage())
1524-
.Where(sp => sp != null && sp.StatusKey == PackageStatus.Available)
1525-
.Select(sp => new PackageViewModel(sp.Package));
1533+
.Where(p => (p.LatestSymbolPackage()?.StatusKey ?? PackageStatus.Deleted) == PackageStatus.Available)
1534+
.OrderByDescending(p => new NuGetVersion(p.Version));
15261535

1527-
model.VersionSelectList = new SelectList(
1528-
packageViewModelsForAllAvailableSymbolsPackage
1529-
.Select(pvm => new
1536+
model.VersionSelectList = versionsWithSymbols
1537+
.Select(versionWithSymbols => new SelectListItem
15301538
{
1531-
text = pvm.NuGetVersion.ToFullString() + (pvm.LatestVersionSemVer2 ? " (Latest)" : string.Empty),
1532-
url = Url.DeleteSymbolsPackage(pvm)
1533-
}), "url", "text", Url.DeleteSymbolsPackage(model));
1539+
Text = PackageHelper.GetSelectListText(versionWithSymbols),
1540+
Value = Url.DeleteSymbolsPackage(new TrivialPackageVersionModel(versionWithSymbols)),
1541+
Selected = package == versionWithSymbols
1542+
});
15341543

15351544
return View(model);
15361545
}

tests/NuGetGallery.Facts/Controllers/PackagesControllerFacts.cs

Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,11 +2629,11 @@ protected override Task<ActionResult> GetManageResult(
26292629
}
26302630
}
26312631

2632-
public class TheDeleteSymbolsMethod : TestContainer
2632+
public abstract class TheDeleteSymbolsMethod : TestContainer
26332633
{
2634-
private string _packageId = "CrestedGecko";
2635-
private PackageRegistration _packageRegistration;
2636-
private Package _package;
2634+
protected string _packageId = "CrestedGecko";
2635+
protected PackageRegistration _packageRegistration;
2636+
protected Package _package;
26372637

26382638
public TheDeleteSymbolsMethod()
26392639
{
@@ -2646,6 +2646,7 @@ public TheDeleteSymbolsMethod()
26462646
Key = 2,
26472647
PackageRegistration = _packageRegistration,
26482648
Version = "1.0.0+metadata",
2649+
NormalizedVersion = "1.0.0",
26492650
Listed = true,
26502651
IsLatestSemVer2 = true,
26512652
HasReadMe = false,
@@ -2656,6 +2657,7 @@ public TheDeleteSymbolsMethod()
26562657
Key = 1,
26572658
PackageRegistration = _packageRegistration,
26582659
Version = "1.0.0-alpha",
2660+
NormalizedVersion = "1.0.0-alpha",
26592661
IsLatest = true,
26602662
IsLatestSemVer2 = true,
26612663
Listed = true,
@@ -2672,7 +2674,14 @@ public TheDeleteSymbolsMethod()
26722674
[Fact]
26732675
public void Returns404IfPackageNotFound()
26742676
{
2675-
var controller = CreateController(GetConfigurationService());
2677+
var packageService = new Mock<IPackageService>();
2678+
packageService
2679+
.Setup(x => x.FindPackagesById(_packageRegistration.Id, false))
2680+
.Returns(new Package[0]);
2681+
2682+
var controller = CreateController(
2683+
GetConfigurationService(),
2684+
packageService: packageService);
26762685

26772686
var result = controller.DeleteSymbols(_packageRegistration.Id, _package.Version);
26782687

@@ -2754,8 +2763,8 @@ public void DisplaysFullVersionStringAndUsesNormalizedVersionsInUrlsInSelectList
27542763

27552764
foreach (var pkg in _packageRegistration.Packages)
27562765
{
2757-
var valueField = controller.Url.DeleteSymbolsPackage(model);
2758-
var textField = model.NuGetVersion.ToFullString() + (pkg.IsLatestSemVer2 ? " (Latest)" : string.Empty);
2766+
var valueField = controller.Url.DeleteSymbolsPackage(new TrivialPackageVersionModel(pkg));
2767+
var textField = PackageHelper.GetSelectListText(pkg);
27592768

27602769
var selectListItem = model.VersionSelectList
27612770
.SingleOrDefault(i => string.Equals(i.Text, textField) && string.Equals(i.Value, valueField));
@@ -2766,30 +2775,13 @@ public void DisplaysFullVersionStringAndUsesNormalizedVersionsInUrlsInSelectList
27662775
}
27672776
}
27682777

2769-
[Fact]
2770-
public void WhenPackageRegistrationIsLockedReturnsLockedState()
2778+
[Theory]
2779+
[MemberData(nameof(Owner_Data))]
2780+
public void WhenPackageRegistrationIsLockedReturnsLockedState(User currentUser, User owner)
27712781
{
2772-
// Arrange
2773-
var user = new User("Frodo") { Key = 1 };
2774-
var packageRegistration = new PackageRegistration { Id = "Foo", IsLocked = true };
2775-
packageRegistration.Owners.Add(user);
2776-
2777-
var package = new Package
2778-
{
2779-
Key = 2,
2780-
PackageRegistration = packageRegistration,
2781-
Version = "1.0.0+metadata",
2782-
};
2783-
2784-
var packageService = new Mock<IPackageService>(MockBehavior.Strict);
2785-
packageService.Setup(svc => svc.FindPackageByIdAndVersion("Foo", "1.0.0", SemVerLevelKey.SemVer2, true))
2786-
.Returns(package);
2787-
2788-
var controller = CreateController(GetConfigurationService(), packageService: packageService);
2789-
controller.SetCurrentUser(user);
2782+
_packageRegistration.IsLocked = true;
27902783

2791-
// Act
2792-
var result = controller.DeleteSymbols("Foo", "1.0.0");
2784+
var result = GetDeleteSymbolsResult(currentUser, owner, out var controller);
27932785

27942786
// Assert
27952787
var model = ResultAssert.IsView<DeletePackageViewModel>(result);
@@ -2800,11 +2792,7 @@ private ActionResult GetDeleteSymbolsResult(User currentUser, User owner, out Pa
28002792
{
28012793
_packageRegistration.Owners.Add(owner);
28022794

2803-
var packageService = new Mock<IPackageService>(MockBehavior.Strict);
2804-
packageService
2805-
.Setup(svc => svc.FindPackageByIdAndVersion(_packageId, _package.Version, SemVerLevelKey.SemVer2, true))
2806-
.Returns(_package).Verifiable();
2807-
2795+
var packageService = CreatePackageService();
28082796
controller = CreateController(
28092797
GetConfigurationService(),
28102798
packageService: packageService);
@@ -2814,11 +2802,70 @@ private ActionResult GetDeleteSymbolsResult(User currentUser, User owner, out Pa
28142802
Routes.RegisterRoutes(routeCollection);
28152803
controller.Url = new UrlHelper(controller.ControllerContext.RequestContext, routeCollection);
28162804

2817-
var result = controller.DeleteSymbols(_packageId, _package.Version);
2805+
var result = InvokeDeleteSymbols(controller);
28182806

28192807
packageService.Verify();
28202808
return result;
28212809
}
2810+
2811+
protected abstract Mock<IPackageService> CreatePackageService();
2812+
2813+
protected abstract ActionResult InvokeDeleteSymbols(PackagesController controller);
2814+
}
2815+
2816+
public class TheDeleteSymbolsMethodWithExactVersion : TheDeleteSymbolsMethod
2817+
{
2818+
protected override Mock<IPackageService> CreatePackageService()
2819+
{
2820+
var packageService = new Mock<IPackageService>(MockBehavior.Strict);
2821+
packageService
2822+
.Setup(svc => svc.FindPackagesById(_packageId, false))
2823+
.Returns(_packageRegistration.Packages.ToList())
2824+
.Verifiable();
2825+
2826+
return packageService;
2827+
}
2828+
2829+
protected override ActionResult InvokeDeleteSymbols(PackagesController controller)
2830+
{
2831+
return controller.DeleteSymbols(_packageId, _package.Version);
2832+
}
2833+
}
2834+
2835+
public abstract class TheDeleteSymbolsMethodThatFilters : TheDeleteSymbolsMethod
2836+
{
2837+
protected override Mock<IPackageService> CreatePackageService()
2838+
{
2839+
var packages = _packageRegistration.Packages.ToList();
2840+
var packageService = new Mock<IPackageService>(MockBehavior.Strict);
2841+
packageService
2842+
.Setup(svc => svc.FindPackagesById(_packageId, false))
2843+
.Returns(packages)
2844+
.Verifiable();
2845+
2846+
packageService
2847+
.Setup(svc => svc.FilterLatestPackage(packages, SemVerLevelKey.SemVer2, true))
2848+
.Returns(_package)
2849+
.Verifiable();
2850+
2851+
return packageService;
2852+
}
2853+
}
2854+
2855+
public class TheDeleteSymbolsMethodWithMissingVersion : TheDeleteSymbolsMethodThatFilters
2856+
{
2857+
protected override ActionResult InvokeDeleteSymbols(PackagesController controller)
2858+
{
2859+
return controller.DeleteSymbols(_packageId, "missing");
2860+
}
2861+
}
2862+
2863+
public class TheDeleteSymbolsMethodWithNullVersion : TheDeleteSymbolsMethodThatFilters
2864+
{
2865+
protected override ActionResult InvokeDeleteSymbols(PackagesController controller)
2866+
{
2867+
return controller.DeleteSymbols(_packageId, null);
2868+
}
28222869
}
28232870

28242871
public class TheDeleteSymbolsPackageMethod : TestContainer

0 commit comments

Comments
 (0)