feat(launcher): implement verified atomic updates

This commit is contained in:
Erik 2026-08-14 22:09:34 +02:00
parent 2198a0cc8e
commit 2d2a5b5046
34 changed files with 6755 additions and 61 deletions

View file

@ -2,6 +2,7 @@ using AcDream.Launcher.Core.Launching;
using AcDream.Launcher.Core.Orchestration;
using AcDream.Launcher.Core.Profiles;
using AcDream.Launcher.Core.Status;
using AcDream.Launcher.Core.Updates;
using AcDream.Platform;
namespace AcDream.Launcher.Core.Tests.Orchestration;
@ -34,6 +35,26 @@ public sealed class LauncherOrchestratorTests : IDisposable
}
}
[Fact]
public async Task RunningHostHoldsSharedUpdateLeaseUntilProcessTerminalState()
{
var supervisors = new FakeSupervisorFactory();
var barrier = new UpdateSessionBarrier(_paths.DataDirectory);
using LauncherOrchestrator orchestrator = CreateOrchestrator(
supervisorFactory: supervisors,
updateSessionBarrier: barrier);
_ = await orchestrator.LaunchAsync(
"Local ACE",
"testaccount",
"+Acdream",
LaunchMode.Gui);
Assert.Throws<LauncherUpdateException>(barrier.AcquireExclusive);
Assert.Single(supervisors.Created).Exit(0);
using UpdateSessionBarrier.ExclusiveLease update = barrier.AcquireExclusive();
}
[Fact]
public void SnapshotProjectsTheFullHierarchyWithoutTheCredential()
{
@ -527,7 +548,8 @@ public sealed class LauncherOrchestratorTests : IDisposable
ILauncherSessionConfigService? configService = null,
ILauncherProcessSupervisorFactory? supervisorFactory = null,
IStatusEventSourceFactory? statusSourceFactory = null,
LauncherExecutableSet? executables = null)
LauncherExecutableSet? executables = null,
UpdateSessionBarrier? updateSessionBarrier = null)
{
string profilePath = Path.Combine(
_paths.ConfigDirectory,
@ -563,7 +585,8 @@ public sealed class LauncherOrchestratorTests : IDisposable
configService,
supervisorFactory ?? new FakeSupervisorFactory(),
statusSourceFactory ?? new QueueStatusSourceFactory(),
() => $"s{Interlocked.Increment(ref nextSession)}");
() => $"s{Interlocked.Increment(ref nextSession)}",
updateSessionBarrier: updateSessionBarrier);
orchestrator.LoadProfiles();
return orchestrator;
}