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();
                }
            }
        }
Example #2
0
        public async Task ServerRunning_ShutdownRequest_DoesNotAbortCompilation()
        {
            // Arrange
            var completionSource = new TaskCompletionSource <bool>();
            var host             = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) =>
            {
                // We want this to keep running even after the shutdown is seen.
                completionSource.Task.Wait();
                return(EmptyServerResponse);
            });

            using (var serverData = ServerUtilities.CreateServer(compilerHost: host))
            {
                var compileTask = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest);

                // Act
                // The compilation is now in progress, send the shutdown.
                await ServerUtilities.SendShutdown(serverData.PipeName);

                Assert.False(compileTask.IsCompleted);

                // Now let the task complete.
                completionSource.SetResult(true);

                // Assert
                var response = await compileTask;
                Assert.Equal(ServerResponse.ResponseType.Completed, response.Type);
                Assert.Equal(0, ((CompletedServerResponse)response).ReturnCode);

                await serverData.Verify(connections : 2, completed : 2);
            }
        }
        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);
        }
Example #5
0
        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());
            });

            using (var serverData = ServerUtilities.CreateServer(compilerHost: host))
            {
                var tasks = new List <Task <ServerResponse> >();
                for (var i = 0; i < requestCount; i++)
                {
                    var task = ServerUtilities.Send(serverData.PipeName, EmptyServerRequest);
                    tasks.Add(task);
                }

                // Act
                // Wait until all of the connections are being processed by the server.
                completionSource.Task.Wait();

                // Now cancel
                var stats = await serverData.CancelAndCompleteAsync();

                // Assert
                Assert.Equal(requestCount, stats.Connections);
                Assert.Equal(requestCount, count);

                foreach (var task in tasks)
                {
                    // We expect this to throw because the stream is already closed.
                    await Assert.ThrowsAsync <EndOfStreamException>(() => task);
                }
            }
        }
        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();
                }
            }
        }