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 async Task ServerRunning_ShutdownRequest_processesSuccessfully() { // Arrange using (var serverData = ServerUtilities.CreateServer()) { // Act var serverProcessId = await ServerUtilities.SendShutdown(serverData.PipeName); // Assert Assert.Equal(Process.GetCurrentProcess().Id, serverProcessId); await serverData.Verify(connections : 1, completed : 1); } }
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); }
public async Task ServerRunning_MultipleShutdownRequests_HandlesSuccessfully() { // Arrange var startCompilationSource = new TaskCompletionSource <bool>(); var finishCompilationSource = new TaskCompletionSource <bool>(); var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) => { // At this point, the connection has been accepted and the compilation has started. startCompilationSource.SetResult(true); // We want this to keep running even after the shutdown is seen. finishCompilationSource.Task.Wait(); return(EmptyServerResponse); }); using (var serverData = ServerUtilities.CreateServer(compilerHost: host)) { var compileTask = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest); // Wait for the request to go through and trigger compilation. await startCompilationSource.Task; // Act for (var i = 0; i < 10; i++) { // The compilation is now in progress, send the shutdown. var processId = await ServerUtilities.SendShutdown(serverData.PipeName); Assert.Equal(Process.GetCurrentProcess().Id, processId); Assert.False(compileTask.IsCompleted); } // Now let the task complete. finishCompilationSource.SetResult(true); // Assert var response = await compileTask; Assert.Equal(ServerResponse.ResponseType.Completed, response.Type); Assert.Equal(0, ((CompletedServerResponse)response).ReturnCode); await serverData.Verify(connections : 11, completed : 11); } }
public async Task ServerRunning_CancelCompilation_CancelsSuccessfully() { // Arrange const int requestCount = 5; var count = 0; var completionSource = new TaskCompletionSource <bool>(); var host = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) => { if (Interlocked.Increment(ref count) == requestCount) { completionSource.SetResult(true); } ct.WaitHandle.WaitOne(); return(new RejectedServerResponse()); }); var semaphore = new SemaphoreSlim(1); Action <object, EventArgs> onListening = (s, e) => { semaphore.Release(); }; using (var serverData = ServerUtilities.CreateServer(compilerHost: host, onListening: onListening)) { // Send all the requests. var clients = new List <Client>(); for (var i = 0; i < requestCount; i++) { // Wait for the server to start listening. await semaphore.WaitAsync(TimeSpan.FromMinutes(1)); var client = await Client.ConnectAsync(serverData.PipeName, timeout : null, cancellationToken : default); await EmptyServerRequest.WriteAsync(client.Stream); clients.Add(client); } // Act // Wait until all of the connections are being processed by the server. await completionSource.Task; // Now cancel var stats = await serverData.CancelAndCompleteAsync(); // Assert Assert.Equal(requestCount, stats.Connections); Assert.Equal(requestCount, count); // Read the server response to each client. foreach (var client in clients) { var task = ServerResponse.ReadAsync(client.Stream); // We expect this to throw because the stream is already closed. await Assert.ThrowsAnyAsync <IOException>(() => task); client.Dispose(); } } }