public void ServerStartup_MutexAlreadyAcquired_Fails() { // Arrange var pipeName = Guid.NewGuid().ToString("N"); var mutexName = MutexName.GetServerMutexName(pipeName); var compilerHost = new Mock <CompilerHost>(MockBehavior.Strict); var host = new Mock <ConnectionHost>(MockBehavior.Strict); // Act & Assert using (var mutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out var holdsMutex)) { Assert.True(holdsMutex); try { var result = ServerUtilities.RunServer(pipeName, host.Object, compilerHost.Object); // Assert failure Assert.Equal(1, result); } finally { mutex.ReleaseMutex(); } } }
public void ServerStartup_SuccessfullyAcquiredMutex() { // Arrange, Act & Assert var pipeName = Guid.NewGuid().ToString("N"); var mutexName = MutexName.GetServerMutexName(pipeName); var compilerHost = new Mock <CompilerHost>(MockBehavior.Strict); var host = new Mock <ConnectionHost>(MockBehavior.Strict); host .Setup(x => x.WaitForConnectionAsync(It.IsAny <CancellationToken>())) .Returns(() => { // Use a thread instead of Task to guarantee this code runs on a different // thread and we can validate the mutex state. var source = new TaskCompletionSource <bool>(); var thread = new Thread(_ => { Mutex mutex = null; try { Assert.True(Mutex.TryOpenExisting(mutexName, out mutex)); Assert.False(mutex.WaitOne(millisecondsTimeout: 0)); source.SetResult(true); } catch (Exception ex) { source.SetException(ex); throw; } finally { mutex?.Dispose(); } }); // Synchronously wait here. Don't returned a Task value because we need to // ensure the above check completes before the server hits a timeout and // releases the mutex. thread.Start(); source.Task.Wait(); return(new TaskCompletionSource <Connection>().Task); }); var result = ServerUtilities.RunServer(pipeName, host.Object, compilerHost.Object, keepAlive: TimeSpan.FromSeconds(1)); Assert.Equal(0, result); }