using WxAgent.Core; using Xunit; namespace WxAgent.Core.Tests; public sealed class InterprocessCommandGateTests { [Fact] public async Task SeparateInstancesShareAnExclusiveLease() { var path = Path.Combine(Path.GetTempPath(), "wx-gate-" + Guid.NewGuid(), "commands.lock"); try { using var first = new InterprocessCommandGate(path); using var second = new InterprocessCommandGate(path); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); await first.WaitAsync(timeout.Token); var waiting = second.WaitAsync(timeout.Token); Assert.False(waiting.IsCompleted); first.Release(); await waiting; second.Release(); } finally { Directory.Delete(Path.GetDirectoryName(path)!, recursive: true); } } [Fact] public async Task CancelledContentionDoesNotPoisonTheLocalQueue() { var path = Path.Combine(Path.GetTempPath(), "wx-gate-" + Guid.NewGuid(), "commands.lock"); try { using var first = new InterprocessCommandGate(path); using var second = new InterprocessCommandGate(path); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); await first.WaitAsync(timeout.Token); using var cancelled = new CancellationTokenSource(TimeSpan.FromMilliseconds(100)); await Assert.ThrowsAnyAsync(() => second.WaitAsync(cancelled.Token)); first.Release(); await second.WaitAsync(timeout.Token); second.Release(); } finally { Directory.Delete(Path.GetDirectoryName(path)!, recursive: true); } } [Fact] public async Task NonContentionIoErrorsAreNotRetried() { var path = Path.Combine(Path.GetTempPath(), "wx-gate-" + Guid.NewGuid(), "commands.lock"); Directory.CreateDirectory(path); // A directory cannot be opened as the lock file. try { using var gate = new InterprocessCommandGate(path); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); var error = await Record.ExceptionAsync(() => gate.WaitAsync(timeout.Token)); Assert.True(error is IOException or UnauthorizedAccessException); Directory.Delete(path); await gate.WaitAsync(timeout.Token); gate.Release(); } finally { Directory.Delete(Path.GetDirectoryName(path)!, recursive: true); } } }