Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ public void FilterPackages(bool fromQuery = false)
UpdateSubtitle();
PackageCountUpdated?.Invoke();

bool loadingOrPending = Loader.IsLoading || (LoadsOnStart && !Loader.IsLoaded);
bool loadingOrPending = Loader.IsLoading || (LoadsOnStart && Loader.HasPendingInitialLoad);

if (loadingOrPending && FilteredPackages.Count == 0)
{
Expand Down Expand Up @@ -1022,7 +1022,7 @@ public void UpdatePackageCount()
// ─── Subtitle ─────────────────────────────────────────────────────────────
public void UpdateSubtitle()
{
if (Loader.IsLoading || (LoadsOnStart && !Loader.IsLoaded))
if (Loader.IsLoading || (LoadsOnStart && Loader.HasPendingInitialLoad))
{
Subtitle = _stillLoadingSubtitle;
return;
Expand Down
28 changes: 25 additions & 3 deletions src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public abstract class AbstractPackageLoader

public bool LastLoadReportedFailures { get; private set; }

public bool HasPendingInitialLoad => !IsLoaded && !LastLoadReportedFailures;

public DateTime? LastLoadFinishedUtc { get; private set; }

private TaskCompletionSource? _loadCompletion;
Expand Down Expand Up @@ -157,6 +159,8 @@ protected void InvokeFinishedLoadingEvent()
public virtual async Task ReloadPackages()
{
TaskCompletionSource? completion = null;
int current_identifier = 0;
bool finishWasAnnounced = false;
try
{
if (DISABLE_RELOAD)
Expand All @@ -172,7 +176,7 @@ public virtual async Task ReloadPackages()
}

LoadOperationIdentifier = new Random().Next();
int current_identifier = LoadOperationIdentifier;
current_identifier = LoadOperationIdentifier;
completion = new TaskCompletionSource(
TaskCreationOptions.RunContinuationsAsynchronously
);
Expand Down Expand Up @@ -258,14 +262,32 @@ public virtual async Task ReloadPackages()
{
LastLoadFinishedUtc = DateTime.UtcNow;
IsLoaded = true;
finishWasAnnounced = true;
InvokeFinishedLoadingEvent();
}
}
catch (Exception ex)
{
Logger.Error(ex);
LastLoadReportedFailures = true;
IsLoading = false;

if (
!finishWasAnnounced
&& completion is not null
&& LoadOperationIdentifier == current_identifier
)
Comment thread
GabrielDuf marked this conversation as resolved.
{
LastLoadReportedFailures = true;
IsLoading = false;

try
{
InvokeFinishedLoadingEvent();
}
catch (Exception announceEx)
{
Logger.Error(announceEx);
}
}
}
finally
{
Expand Down
85 changes: 85 additions & 0 deletions src/UniGetUI.PackageEngine.Tests/PackageLoaderPipelineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,89 @@ public async Task ReloadPackages_ReportsSettledLoadState_WhenFinishedLoadingIsRa
Assert.False(isLoadingWhenFinished);
Assert.True(isLoadedWhenFinished);
}

[Fact]
public async Task ReloadPackages_SettlesAndAnnouncesCompletion_WhenTheLoadFails()
{
var manager = new PackageManagerBuilder()
.WithInstalledPackages(testManager =>
[
new PackageBuilder()
.WithManager(testManager)
.WithId("Contoso.Tool")
.WithVersion("1.0.0")
.Build(),
])
.Build();
TestPackageLoader? loaderReference = null;
Task? waitTakenDuringLoad = null;
var loader = new TestPackageLoader(
[manager],
isPackageValid: _ =>
{
waitTakenDuringLoad = loaderReference!.WaitForCurrentLoadAsync();
throw new InvalidOperationException("the load blew up");
}
);
loaderReference = loader;
var recorder = new LoaderEventRecorder(loader);

await loader.ReloadPackages();

Assert.Equal(1, recorder.FinishedLoadingCount);
Assert.False(loader.IsLoading);
Assert.True(loader.LastLoadReportedFailures);
Assert.False(loader.HasPendingInitialLoad);
Assert.NotNull(waitTakenDuringLoad);
Assert.True(waitTakenDuringLoad.IsCompleted);
}

[Fact]
public async Task ReloadPackages_AnnouncesCompletionOnce_WhenAFinishedLoadingSubscriberThrows()
{
var manager = new PackageManagerBuilder().Build();
var loader = new TestPackageLoader([manager], loadPackages: _ => []);
var recorder = new LoaderEventRecorder(loader);
loader.FinishedLoading += (_, _) => throw new InvalidOperationException("the subscriber blew up");

await loader.ReloadPackages();

Assert.Equal(1, recorder.FinishedLoadingCount);
Assert.True(loader.IsLoaded);
Assert.NotNull(loader.LastLoadFinishedUtc);
Assert.False(loader.LastLoadReportedFailures);
}

[Fact]
public async Task ReloadPackages_LeavesAQueuedReloadUntouched_WhenAFinishedLoadingSubscriberThrows()
{
using var release = new ManualResetEventSlim(true);
var manager = new PackageManagerBuilder().Build();
var loader = new TestPackageLoader(
[manager],
loadPackages: _ =>
{
release.Wait();
return [];
}
);

Task? queued = null;
loader.FinishedLoading += (_, _) =>
{
if (queued is not null) return;
release.Reset();
queued = loader.ReloadPackages();
};
loader.FinishedLoading += (_, _) => throw new InvalidOperationException("the subscriber blew up");

await loader.ReloadPackages();

Assert.NotNull(queued);
Assert.True(loader.IsLoading);
Assert.False(loader.LastLoadReportedFailures);

release.Set();
await queued;
}
}
Loading