Browse Source

Fix race condition when searching for NuGet packages.

pull/419/head
Matt Ward 11 years ago
parent
commit
5da67914a4
  1. 1
      src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
  2. 2
      src/AddIns/Misc/PackageManagement/Project/Src/AvailablePackagesViewModel.cs
  3. 32
      src/AddIns/Misc/PackageManagement/Project/Src/PackagesForSelectedPageQuery.cs
  4. 8
      src/AddIns/Misc/PackageManagement/Project/Src/PackagesForSelectedPageResult.cs
  5. 57
      src/AddIns/Misc/PackageManagement/Project/Src/PackagesViewModel.cs
  6. 6
      src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeTaskFactory.cs
  7. 3
      src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestablePackagesViewModel.cs
  8. 19
      src/AddIns/Misc/PackageManagement/Test/Src/PackagesViewModelTests.cs

1
src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj

@ -232,6 +232,7 @@ @@ -232,6 +232,7 @@
<Compile Include="Src\PackageManagementServiceProvider.cs" />
<Compile Include="Src\IPackageRepositoryExtensions.cs" />
<Compile Include="Src\PackageRepositoryFactoryEventArgs.cs" />
<Compile Include="Src\PackagesForSelectedPageQuery.cs" />
<Compile Include="Src\ParentPackagesOperationEventArgs.cs" />
<Compile Include="Src\ProjectBuilder.cs" />
<Compile Include="Src\ProjectRootElementExtensions.cs" />

2
src/AddIns/Misc/PackageManagement/Project/Src/AvailablePackagesViewModel.cs

@ -84,7 +84,7 @@ namespace ICSharpCode.PackageManagement @@ -84,7 +84,7 @@ namespace ICSharpCode.PackageManagement
.Where(package => package.IsAbsoluteLatestVersion);
}
return repository
.Search(SearchTerms, IncludePrerelease)
.Search(searchCriteria, IncludePrerelease)
.Where(package => package.IsLatestVersion);
}

32
src/AddIns/Misc/PackageManagement/Project/Src/PackagesForSelectedPageQuery.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using NuGet;
namespace ICSharpCode.PackageManagement
{
public class PackagesForSelectedPageQuery
{
public PackagesForSelectedPageQuery (
PackagesViewModel viewModel,
IEnumerable<IPackage> allPackages,
string searchCriteria)
{
Skip = viewModel.ItemsBeforeFirstPage;
Take = viewModel.PageSize;
AllPackages = allPackages;
SearchCriteria = searchCriteria;
TotalPackages = viewModel.TotalItems;
}
public int Skip { get; private set; }
public int Take { get; private set; }
public string SearchCriteria { get; private set; }
public int TotalPackages { get; set; }
public IEnumerable<IPackage> AllPackages { get; set; }
}
}

8
src/AddIns/Misc/PackageManagement/Project/Src/PackagesForSelectedPageResult.cs

@ -26,15 +26,19 @@ namespace ICSharpCode.PackageManagement @@ -26,15 +26,19 @@ namespace ICSharpCode.PackageManagement
{
public class PackagesForSelectedPageResult
{
public PackagesForSelectedPageResult(IEnumerable<IPackage> packages, int totalPackages)
public PackagesForSelectedPageResult(IEnumerable<IPackage> packages, PackagesForSelectedPageQuery query)
{
this.Packages = packages;
this.TotalPackagesOnPage = packages.Count();
this.TotalPackages = totalPackages;
this.TotalPackages = query.TotalPackages;
this.AllPackages = query.AllPackages;
this.Query = query;
}
public PackagesForSelectedPageQuery Query { get; set; }
public IEnumerable<IPackage> Packages { get; set; }
public int TotalPackagesOnPage { get; set; }
public int TotalPackages { get; set; }
public IEnumerable<IPackage> AllPackages { get; set; }
}
}

57
src/AddIns/Misc/PackageManagement/Project/Src/PackagesViewModel.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.PackageManagement @@ -41,6 +41,7 @@ namespace ICSharpCode.PackageManagement
IEnumerable<IPackage> allPackages;
ITask<PackagesForSelectedPageResult> task;
bool includePrerelease;
PackagesForSelectedPageQuery packagesForSelectedPageQuery;
public PackagesViewModel(
IPackageManagementSolution solution,
@ -153,15 +154,18 @@ namespace ICSharpCode.PackageManagement @@ -153,15 +154,18 @@ namespace ICSharpCode.PackageManagement
void CreateReadPackagesTask()
{
var query = new PackagesForSelectedPageQuery(this, allPackages, GetSearchCriteria());
packagesForSelectedPageQuery = query;
task = taskFactory.CreateTask(
() => GetPackagesForSelectedPageResult(),
() => GetPackagesForSelectedPageResult(query),
OnPackagesReadForSelectedPage);
}
PackagesForSelectedPageResult GetPackagesForSelectedPageResult()
PackagesForSelectedPageResult GetPackagesForSelectedPageResult(PackagesForSelectedPageQuery query)
{
IEnumerable<IPackage> packages = GetPackagesForSelectedPage();
return new PackagesForSelectedPageResult(packages, TotalItems);
IEnumerable<IPackage> packages = GetPackagesForSelectedPage(query);
return new PackagesForSelectedPageResult(packages, query);
}
void OnPackagesReadForSelectedPage(ITask<PackagesForSelectedPageResult> task)
@ -171,12 +175,19 @@ namespace ICSharpCode.PackageManagement @@ -171,12 +175,19 @@ namespace ICSharpCode.PackageManagement
SaveError(task.Exception);
} else if (task.IsCancelled) {
// Ignore
} else if (!IsCurrentQuery(task.Result)) {
// Ignore.
} else {
UpdatePackagesForSelectedPage(task.Result);
}
base.OnPropertyChanged(null);
}
bool IsCurrentQuery(PackagesForSelectedPageResult result)
{
return packagesForSelectedPageQuery == result.Query;
}
void SaveError(AggregateException ex)
{
HasError = true;
@ -194,6 +205,8 @@ namespace ICSharpCode.PackageManagement @@ -194,6 +205,8 @@ namespace ICSharpCode.PackageManagement
{
pages.TotalItems = result.TotalPackages;
pages.TotalItemsOnSelectedPage = result.TotalPackagesOnPage;
TotalItems = result.TotalPackages;
allPackages = result.AllPackages;
UpdatePackageViewModels(result.Packages);
}
@ -203,20 +216,20 @@ namespace ICSharpCode.PackageManagement @@ -203,20 +216,20 @@ namespace ICSharpCode.PackageManagement
base.OnPropertyChanged(null);
}
IEnumerable<IPackage> GetPackagesForSelectedPage()
IEnumerable<IPackage> GetPackagesForSelectedPage(PackagesForSelectedPageQuery query)
{
IEnumerable<IPackage> filteredPackages = GetFilteredPackagesBeforePagingResults();
return GetPackagesForSelectedPage(filteredPackages);
IEnumerable<IPackage> filteredPackages = GetFilteredPackagesBeforePagingResults(query);
return GetPackagesForSelectedPage(filteredPackages, query);
}
IEnumerable<IPackage> GetFilteredPackagesBeforePagingResults()
IEnumerable<IPackage> GetFilteredPackagesBeforePagingResults(PackagesForSelectedPageQuery query)
{
if (allPackages == null) {
IQueryable<IPackage> packages = GetPackagesFromPackageSource();
TotalItems = packages.Count();
allPackages = GetFilteredPackagesBeforePagingResults(packages);
if (query.AllPackages == null) {
IQueryable<IPackage> packages = GetPackagesFromPackageSource(query.SearchCriteria);
query.TotalPackages = packages.Count();
query.AllPackages = GetFilteredPackagesBeforePagingResults(packages);
}
return allPackages;
return query.AllPackages;
}
/// <summary>
@ -224,7 +237,12 @@ namespace ICSharpCode.PackageManagement @@ -224,7 +237,12 @@ namespace ICSharpCode.PackageManagement
/// </summary>
public IQueryable<IPackage> GetPackagesFromPackageSource()
{
IQueryable<IPackage> packages = GetAllPackages(GetSearchCriteria());
return GetPackagesFromPackageSource(GetSearchCriteria());
}
IQueryable<IPackage> GetPackagesFromPackageSource(string searchCriteria)
{
IQueryable<IPackage> packages = GetAllPackages(searchCriteria);
return OrderPackages(packages);
}
@ -242,12 +260,11 @@ namespace ICSharpCode.PackageManagement @@ -242,12 +260,11 @@ namespace ICSharpCode.PackageManagement
return SearchTerms;
}
IEnumerable<IPackage> GetPackagesForSelectedPage(IEnumerable<IPackage> allPackages)
IEnumerable<IPackage> GetPackagesForSelectedPage(IEnumerable<IPackage> allPackages, PackagesForSelectedPageQuery query)
{
int packagesToSkip = pages.ItemsBeforeFirstPage;
return allPackages
.Skip(packagesToSkip)
.Take(pages.PageSize);
.Skip(query.Skip)
.Take(query.Take);
}
/// <summary>
@ -325,6 +342,10 @@ namespace ICSharpCode.PackageManagement @@ -325,6 +342,10 @@ namespace ICSharpCode.PackageManagement
set { pages.PageSize = value; }
}
public int ItemsBeforeFirstPage {
get { return pages.ItemsBeforeFirstPage; }
}
public bool IsPaged {
get { return pages.IsPaged; }
}

6
src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeTaskFactory.cs

@ -51,6 +51,12 @@ namespace PackageManagement.Tests.Helpers @@ -51,6 +51,12 @@ namespace PackageManagement.Tests.Helpers
}
}
public void ExecuteTask(int index)
{
var task = FakeTasksCreated[index] as FakeTask<PackagesForSelectedPageResult>;
task.ExecuteTaskCompletely();
}
public void ClearAllFakeTasks()
{
FakeTasksCreated.Clear();

3
src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestablePackagesViewModel.cs

@ -64,10 +64,11 @@ namespace PackageManagement.Tests.Helpers @@ -64,10 +64,11 @@ namespace PackageManagement.Tests.Helpers
AddFakePackage("Test");
}
public void AddFakePackage(string packageId)
public FakePackage AddFakePackage(string packageId)
{
FakePackage package = CreateFakePackage(packageId);
FakePackages.Add(package);
return package;
}
FakePackage CreateFakePackage(string packageId)

19
src/AddIns/Misc/PackageManagement/Test/Src/PackagesViewModelTests.cs

@ -333,22 +333,20 @@ namespace PackageManagement.Tests @@ -333,22 +333,20 @@ namespace PackageManagement.Tests
}
[Test]
public void ReadPackages_RepositoryHasThreePackagesWhenSelectedPageIsOneAndPageSizeIsTwo_TwoPackageViewModelsCreatedForFirstTwoPackages()
public void ReadPackages_SecondQueryFinishesBeforeFirst_PackagesInViewModelAreForSecondQuery()
{
CreateViewModel();
viewModel.PageSize = 2;
viewModel.SelectedPageNumber = 1;
viewModel.AddThreeFakePackages();
FakePackage package = viewModel.AddFakePackage("MyTest");
viewModel.ReadPackages();
CompleteReadPackagesTask();
viewModel.SearchTerms = "MyTest";
var expectedPackages = new List<FakePackage>();
expectedPackages.Add(viewModel.FakePackages[0]);
expectedPackages.Add(viewModel.FakePackages[1]);
var expectedPackages = new FakePackage [] { package };
ClearReadPackagesTasks();
viewModel.ReadPackages();
CompleteReadPackagesTask();
taskFactory.ExecuteTask(1);
taskFactory.ExecuteTask(0);
ClearReadPackagesTasks();
PackageCollectionAssert.AreEqual(expectedPackages, viewModel.PackageViewModels);
}
@ -1072,7 +1070,8 @@ namespace PackageManagement.Tests @@ -1072,7 +1070,8 @@ namespace PackageManagement.Tests
CreateViewModel();
viewModel.AddSixFakePackages();
viewModel.ReadPackages();
taskFactory.FirstFakeTaskCreated.Result = new PackagesForSelectedPageResult(viewModel.FakePackages, 6);
var query = new PackagesForSelectedPageQuery(viewModel, null, null);
taskFactory.FirstFakeTaskCreated.Result = new PackagesForSelectedPageResult(viewModel.FakePackages, query);
taskFactory.FirstFakeTaskCreated.IsFaulted = true;
CompleteReadPackagesTask();

Loading…
Cancel
Save