public void MutexStopsServerStarting() { var pipeName = Guid.NewGuid().ToString("N"); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); bool holdsMutex; using (var mutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out holdsMutex)) { Assert.True(holdsMutex); try { var host = new Mock <IClientConnectionHost>(MockBehavior.Strict); var result = DesktopBuildServerController.RunServer( pipeName, Path.GetTempPath(), host.Object, keepAlive: null); Assert.Equal(CommonCompiler.Failed, result); } finally { mutex.ReleaseMutex(); } } }
internal static async Task <ServerData> CreateServer( string pipeName = null, ICompilerServerHost compilerServerHost = null, bool failingServer = false, string tempPath = null) { // The total pipe path must be < 92 characters on Unix, so trim this down to 10 chars pipeName = pipeName ?? Guid.NewGuid().ToString().Substring(0, 10); compilerServerHost = compilerServerHost ?? DesktopBuildServerController.CreateCompilerServerHost(); tempPath = tempPath ?? Path.GetTempPath(); var clientConnectionHost = DesktopBuildServerController.CreateClientConnectionHostForServerHost(compilerServerHost, pipeName); if (failingServer) { clientConnectionHost = new FailingClientConnectionHost(clientConnectionHost); } var serverStatsSource = new TaskCompletionSource <ServerStats>(); var serverListenSource = new TaskCompletionSource <bool>(); var cts = new CancellationTokenSource(); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); var task = Task.Run(() => { var listener = new TestableDiagnosticListener(); listener.Listening += (sender, e) => { serverListenSource.TrySetResult(true); }; try { DesktopBuildServerController.RunServer( pipeName, tempPath, clientConnectionHost, listener, keepAlive: TimeSpan.FromMilliseconds(-1), cancellationToken: cts.Token); } finally { var serverStats = new ServerStats(connections: listener.ConnectionCount, completedConnections: listener.CompletedCount); serverStatsSource.SetResult(serverStats); } }); // 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 (BuildServerConnection.WasServerMutexOpen(mutexName) != true && !task.IsCompleted) { await Task.Yield(); } if (task.IsFaulted) { throw task.Exception; } return(new ServerData(cts, pipeName, serverStatsSource.Task, serverListenSource.Task)); }
public void RunServerWithLongTempPath() { var pipeName = Guid.NewGuid().ToString("N"); // Make a really long path. This should work on Windows, which doesn't rely on temp path, // but not on Unix, which has a max path length var tempPath = new string('a', 100); // This test fails by spinning forever. If the path is not seen as invalid, the server // starts up and will never return. Assert.Equal(CommonCompiler.Failed, DesktopBuildServerController.RunServer(pipeName, tempPath: tempPath)); }
public void MutexAcquiredWhenRunningServer() { var pipeName = Guid.NewGuid().ToString("N"); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); var host = new Mock <IClientConnectionHost>(MockBehavior.Strict); host .Setup(x => x.CreateListenTask(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 <IClientConnection>().Task); }); var result = DesktopBuildServerController.RunServer( pipeName, Path.GetTempPath(), host.Object, keepAlive: TimeSpan.FromSeconds(1)); Assert.Equal(CommonCompiler.Succeeded, result); }
internal static ServerData CreateServer( string pipeName = null, ICompilerServerHost compilerServerHost = null, bool failingServer = false) { pipeName = pipeName ?? Guid.NewGuid().ToString(); compilerServerHost = compilerServerHost ?? DesktopBuildServerController.CreateCompilerServerHost(); var clientConnectionHost = DesktopBuildServerController.CreateClientConnectionHostForServerHost(compilerServerHost, pipeName); if (failingServer) { clientConnectionHost = new FailingClientConnectionHost(clientConnectionHost); } var serverStatsSource = new TaskCompletionSource <ServerStats>(); var serverListenSource = new TaskCompletionSource <bool>(); var cts = new CancellationTokenSource(); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); var thread = new Thread(_ => { var listener = new TestableDiagnosticListener(); listener.Listening += (sender, e) => { serverListenSource.TrySetResult(true); }; try { DesktopBuildServerController.RunServer( pipeName, clientConnectionHost, listener, keepAlive: TimeSpan.FromMilliseconds(-1), cancellationToken: cts.Token); } finally { var serverStats = new ServerStats(connections: listener.ConnectionCount, completedConnections: listener.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 (BuildServerConnection.WasServerMutexOpen(mutexName) != true && thread.IsAlive) { Thread.Yield(); } return(new ServerData(cts, pipeName, serverStatsSource.Task, serverListenSource.Task)); }