mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-09-13 06:07:30 -04:00
The rollback restored files, announced 'Libation restored your previous install files', and deleted the pending marker without ever reading back what it had written. It also could not tell the difference between an overlay that had not started, where putting the backup back returns the install to one version, and an overlay that got partway, where the backup covers a dozen names out of the few hundred in the folder and cannot. Grade the outcome instead. Verify each restored file against its backup, and use the manifest files that did match the upgrade package as the signal that the overlay had begun. Report which files could not be restored, and keep restoring the rest rather than abandoning them at the first failure. Libation has to close either way, since the files underneath it just changed, so the wording and the offer now follow the grade: back on the previous version asks to restart, a mixed install asks but says a fresh install would be better, and a restore that could not finish only offers OK. A relaunched process never offers again, so a pending marker we failed to delete cannot become a loop. Co-authored-by: rmcrackan <rmcrackan@gmail.com>
119 lines
3.4 KiB
C#
119 lines
3.4 KiB
C#
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace LibationFileManager.Tests;
|
|
|
|
/// <summary>
|
|
/// The restart offered after a rollback. A process that restarts itself is worth being careful with, so the
|
|
/// decision is tested here and only the Process.Start call itself goes untested.
|
|
/// </summary>
|
|
[TestClass]
|
|
[DoNotParallelize]
|
|
public class InstallRelauncherTests
|
|
{
|
|
private readonly List<string> started = [];
|
|
private Func<string, bool> originalStarter = null!;
|
|
|
|
[TestInitialize]
|
|
public void Initialize()
|
|
{
|
|
originalStarter = InstallRelauncher.StartProcess;
|
|
InstallRelauncher.StartProcess = executable =>
|
|
{
|
|
started.Add(executable);
|
|
return true;
|
|
};
|
|
}
|
|
|
|
[TestCleanup]
|
|
public void Cleanup()
|
|
{
|
|
InstallRelauncher.StartProcess = originalStarter;
|
|
Environment.SetEnvironmentVariable(InstallRelauncher.RelaunchedEnvironmentVariable, null);
|
|
StartupLog.ResetForTests();
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TryRelaunch_starts_this_same_executable()
|
|
{
|
|
Assert.IsTrue(InstallRelauncher.TryRelaunch());
|
|
|
|
Assert.AreEqual(1, started.Count);
|
|
Assert.AreEqual(Environment.ProcessPath, started[0]);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void A_launcher_that_fails_is_reported_rather_than_thrown()
|
|
{
|
|
InstallRelauncher.StartProcess = _ => throw new InvalidOperationException("no can do");
|
|
|
|
Assert.IsFalse(InstallRelauncher.TryRelaunch());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void A_launcher_that_declines_is_reported_as_not_started()
|
|
{
|
|
InstallRelauncher.StartProcess = _ => false;
|
|
|
|
Assert.IsFalse(InstallRelauncher.TryRelaunch());
|
|
}
|
|
|
|
// A rollback deletes the pending marker first, so it normally cannot repeat. But that delete swallows
|
|
// its own failure, and a marker that survives would mean every launch rolls back and offers a restart
|
|
// again. The child carries a marker of its own so the chain stops at one.
|
|
[TestMethod]
|
|
public void A_process_started_by_a_relaunch_knows_it()
|
|
{
|
|
Assert.IsFalse(InstallRelauncher.WasRelaunched);
|
|
|
|
Environment.SetEnvironmentVariable(InstallRelauncher.RelaunchedEnvironmentVariable, "1");
|
|
|
|
Assert.IsTrue(InstallRelauncher.WasRelaunched);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void The_restart_is_offered_for_an_install_that_was_fully_restored()
|
|
{
|
|
Assert.IsTrue(StartupAssemblyBootstrap.ShouldOfferRestart(
|
|
Rollback(RollbackConfidence.RestoredToPreviousVersion),
|
|
wasRelaunched: false));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void The_restart_is_still_offered_for_a_mixed_install_because_it_does_run()
|
|
{
|
|
Assert.IsTrue(StartupAssemblyBootstrap.ShouldOfferRestart(
|
|
Rollback(RollbackConfidence.RestoredButInstallIsMixed),
|
|
wasRelaunched: false));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void The_restart_is_withheld_when_the_restore_did_not_finish()
|
|
{
|
|
Assert.IsFalse(StartupAssemblyBootstrap.ShouldOfferRestart(
|
|
Rollback(RollbackConfidence.RestoreIncomplete),
|
|
wasRelaunched: false));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void The_restart_is_withheld_in_a_process_that_a_restart_started()
|
|
{
|
|
Assert.IsFalse(StartupAssemblyBootstrap.ShouldOfferRestart(
|
|
Rollback(RollbackConfidence.RestoredToPreviousVersion),
|
|
wasRelaunched: true));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void Nothing_is_offered_when_no_rollback_happened()
|
|
{
|
|
Assert.IsFalse(StartupAssemblyBootstrap.ShouldOfferRestart(
|
|
new UpgradeRecoveryResult(false, string.Empty, string.Empty, []),
|
|
wasRelaunched: false));
|
|
}
|
|
|
|
private static UpgradeRecoveryResult Rollback(RollbackConfidence confidence)
|
|
=> new(true, "title", "body", []) { Confidence = confidence };
|
|
}
|