feat(releases): add SelfUpdater.HandleReplaceSelfAsync

This commit is contained in:
mika kuns
2026-04-23 14:42:41 +02:00
parent e017d66023
commit 0c3dcb0052
2 changed files with 89 additions and 0 deletions

View File

@@ -124,3 +124,56 @@ public class SelfUpdaterDecisionTests
Assert.Equal(SelfUpdateDecisionKind.NoUpdate, d.Kind);
}
}
public class SelfUpdaterReplaceSelfTests : IDisposable
{
private readonly string _tempDir;
public SelfUpdaterReplaceSelfTests()
{
_tempDir = Path.Combine(Path.GetTempPath(), "ClaudeDo.Releases.Tests-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(_tempDir);
}
public void Dispose() { try { Directory.Delete(_tempDir, true); } catch { } }
[Fact]
public async Task Replace_DeletesOldAndCopiesCurrent()
{
var oldPath = Path.Combine(_tempDir, "old.exe");
var currentPath = Path.Combine(_tempDir, "current.exe");
await File.WriteAllTextAsync(oldPath, "OLD");
await File.WriteAllTextAsync(currentPath, "NEW");
var relaunchedWith = "";
var result = await SelfUpdater.HandleReplaceSelfAsync(
oldPath: oldPath,
currentExePath: currentPath,
launchProcess: path => { relaunchedWith = path; return true; },
maxWaitMs: 500);
Assert.True(result);
Assert.Equal(oldPath, relaunchedWith);
Assert.Equal("NEW", await File.ReadAllTextAsync(oldPath));
}
[Fact]
public async Task Replace_TimesOutWhenFileStaysLocked_ReturnsFalse()
{
var oldPath = Path.Combine(_tempDir, "locked.exe");
var currentPath = Path.Combine(_tempDir, "current.exe");
await File.WriteAllTextAsync(oldPath, "OLD");
await File.WriteAllTextAsync(currentPath, "NEW");
// Hold an exclusive lock across the wait window.
using var lockStream = new FileStream(oldPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
var result = await SelfUpdater.HandleReplaceSelfAsync(
oldPath: oldPath,
currentExePath: currentPath,
launchProcess: _ => true,
maxWaitMs: 200);
Assert.False(result);
}
}