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(); } } }
internal static ServerData CreateServer( string pipeName = null, CompilerHost compilerHost = null, ConnectionHost connectionHost = null, Action <object, EventArgs> onListening = null) { pipeName = pipeName ?? Guid.NewGuid().ToString(); compilerHost = compilerHost ?? CompilerHost.Create(); connectionHost = connectionHost ?? ConnectionHost.Create(pipeName); var serverStatsSource = new TaskCompletionSource <ServerStats>(); var serverListenSource = new TaskCompletionSource <bool>(); var cts = new CancellationTokenSource(); var mutexName = MutexName.GetServerMutexName(pipeName); var thread = new Thread(_ => { var eventBus = new TestableEventBus(); eventBus.Listening += (sender, e) => { serverListenSource.TrySetResult(true); }; if (onListening != null) { eventBus.Listening += (sender, e) => onListening(sender, e); } try { RunServer( pipeName, connectionHost, compilerHost, cts.Token, eventBus, Timeout.InfiniteTimeSpan); } finally { var serverStats = new ServerStats(connections: eventBus.ConnectionCount, completedConnections: eventBus.CompletedCount); serverStatsSource.SetResult(serverStats); } }); thread.Start(); // The contract of this function is that it will return once the server has started. Spin here until // we can verify the server has started or simply failed to start. while (ServerConnection.WasServerMutexOpen(mutexName) != true && thread.IsAlive) { Thread.Yield(); } return(new ServerData(cts, pipeName, serverStatsSource.Task, serverListenSource.Task)); }
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); }