public void ConnectToServerFails() { // Create and grab the mutex for the server. This should make // the client believe that a server is active and it will try // to connect. When it fails it should fall back to in-proc // compilation. bool holdsMutex; using (var serverMutex = new Mutex(initiallyOwned: true, name: BuildProtocolConstants.GetServerMutexName(_pipeName), createdNew: out holdsMutex)) { Assert.True(holdsMutex); var ranLocal = false; // Note: Connecting to a server can take up to a second to time out var client = CreateClient( compileFunc: delegate { ranLocal = true; return(0); }); var exitCode = client.RunCompilation(new[] { "/shared" }, _buildPaths).ExitCode; Assert.Equal(0, exitCode); Assert.True(ranLocal); } }
internal static BuildRequest CreateEmptyCSharpWithKeepAlive(TimeSpan keepAlive, string workingDirectory, string tempDirectory = null) => BuildRequest.Create( RequestLanguage.CSharpCompile, Array.Empty <string>(), workingDirectory, tempDirectory ?? Path.GetTempPath(), compilerHash: BuildProtocolConstants.GetCommitHash(), keepAlive: keepAlive.TotalSeconds.ToString());
internal static ServerData CreateServer( string pipeName = null, TimeSpan?timeout = null, ICompilerServerHost compilerServerHost = null) { pipeName = pipeName ?? Guid.NewGuid().ToString(); compilerServerHost = compilerServerHost ?? new DesktopCompilerServerHost(DefaultClientDirectory, DefaultSdkDirectory); var taskSource = new TaskCompletionSource <ServerStats>(); var cts = new CancellationTokenSource(); var thread = new Thread(_ => { var listener = new TestableDiagnosticListener(); try { var clientConnectionHost = new NamedPipeClientConnectionHost(compilerServerHost, pipeName); var mutexName = BuildProtocolConstants.GetServerMutexName(pipeName); VBCSCompiler.Run( mutexName, clientConnectionHost, listener, timeout ?? TimeSpan.FromMilliseconds(-1), cts.Token); } finally { var serverStats = new ServerStats(connections: listener.ConnectionCount, completedConnections: listener.CompletedCount); taskSource.SetResult(serverStats); } }); thread.Start(); return(new ServerData(cts, taskSource.Task, pipeName)); }
public async Task RejectEmptyTempPath() { using var temp = new TempRoot(); using var serverData = await ServerUtil.CreateServer(Logger); var request = BuildRequest.Create( RequestLanguage.CSharpCompile, workingDirectory: temp.CreateDirectory().Path, tempDirectory: null, compilerHash: BuildProtocolConstants.GetCommitHash(), libDirectory: null, args: Array.Empty <string>() ); var response = await serverData.SendAsync(request); Assert.Equal(ResponseType.Rejected, response.Type); }
public async Task ServerShutdownsDuringProcessing() { using (var readyMre = new ManualResetEvent(initialState: false)) using (var doneMre = new ManualResetEvent(initialState: false)) { var pipeName = Guid.NewGuid().ToString(); var mutexName = BuildProtocolConstants.GetServerMutexName(pipeName); bool created = false; bool connected = false; var thread = new Thread(() => { using (var stream = new NamedPipeServerStream(pipeName)) { var mutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out created); readyMre.Set(); stream.WaitForConnection(); connected = true; // Client is waiting for a response. Close the mutex now. Then close the connection // so the client gets an error. mutex.ReleaseMutex(); mutex.Dispose(); stream.Close(); doneMre.WaitOne(); } }); // Block until the mutex and named pipe is setup. thread.Start(); readyMre.WaitOne(); var exitCode = await VBCSCompiler.RunShutdownAsync(pipeName, waitForProcess : false); // Let the fake server exit. doneMre.Set(); thread.Join(); Assert.Equal(CommonCompiler.Succeeded, exitCode); Assert.True(connected); Assert.True(created); } }
public async Task <ConnectionData> HandleConnection(bool allowCompilationRequests = true, CancellationToken cancellationToken = default(CancellationToken)) { try { BuildRequest request; try { Log("Begin reading request."); request = await BuildRequest.ReadAsync(_stream, cancellationToken).ConfigureAwait(false); ValidateBuildRequest(request); Log("End reading request."); } catch (Exception e) { LogException(e, "Error reading build request."); return(new ConnectionData(CompletionReason.CompilationNotStarted)); } if (request.ProtocolVersion != BuildProtocolConstants.ProtocolVersion) { return(await HandleMismatchedVersionRequest(cancellationToken).ConfigureAwait(false)); } else if (!string.Equals(request.CompilerHash, BuildProtocolConstants.GetCommitHash(), StringComparison.OrdinalIgnoreCase)) { return(await HandleIncorrectHashRequest(cancellationToken).ConfigureAwait(false)); } else if (IsShutdownRequest(request)) { return(await HandleShutdownRequest(cancellationToken).ConfigureAwait(false)); } else if (!allowCompilationRequests) { return(await HandleRejectedRequest(cancellationToken).ConfigureAwait(false)); } else { return(await HandleCompilationRequest(request, cancellationToken).ConfigureAwait(false)); } } finally { Close(); } }
private async Task <BuildRequest> CreateBuildRequest( string sourceText, TimeSpan?keepAlive = null ) { var directory = Temp.CreateDirectory(); var file = directory.CreateFile("temp.cs"); await file.WriteAllTextAsync(sourceText); var builder = ImmutableArray.CreateBuilder <BuildRequest.Argument>(); if (keepAlive.HasValue) { builder.Add( new BuildRequest.Argument( BuildProtocolConstants.ArgumentId.KeepAlive, argumentIndex: 0, value: keepAlive.Value.TotalSeconds.ToString() ) ); } builder.Add( new BuildRequest.Argument( BuildProtocolConstants.ArgumentId.CurrentDirectory, argumentIndex: 0, value: directory.Path ) ); builder.Add( new BuildRequest.Argument( BuildProtocolConstants.ArgumentId.CommandLineArgument, argumentIndex: 0, value: file.Path ) ); return(new BuildRequest( RequestLanguage.CSharpCompile, BuildProtocolConstants.GetCommitHash(), builder.ToImmutable() )); }
public async Task NoServerConnection() { using (var readyMre = new ManualResetEvent(initialState: false)) using (var doneMre = new ManualResetEvent(initialState: false)) { var pipeName = Guid.NewGuid().ToString(); var mutexName = BuildProtocolConstants.GetServerMutexName(pipeName); bool created = false; bool connected = false; var thread = new Thread(() => { using (var mutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out created)) using (var stream = new NamedPipeServerStream(pipeName)) { readyMre.Set(); // Get a client connection and then immediately close it. Don't give any response. stream.WaitForConnection(); connected = true; stream.Close(); doneMre.WaitOne(); mutex.ReleaseMutex(); } }); // Block until the mutex and named pipe is setup. thread.Start(); readyMre.WaitOne(); var exitCode = await VBCSCompiler.RunShutdownAsync(pipeName, waitForProcess : false); // Let the fake server exit. doneMre.Set(); thread.Join(); Assert.Equal(CommonCompiler.Failed, exitCode); Assert.True(connected); Assert.True(created); } }
/// <summary> /// Create a compiler server that fails all connections. /// </summary> internal static ServerData CreateServerFailsConnection(string pipeName = null) { pipeName = pipeName ?? Guid.NewGuid().ToString(); var taskSource = new TaskCompletionSource <ServerStats>(); var cts = new CancellationTokenSource(); using (var mre = new ManualResetEvent(initialState: false)) { var thread = new Thread(_ => { var mutexName = BuildProtocolConstants.GetServerMutexName(pipeName); bool holdsMutex; using (var serverMutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out holdsMutex)) { mre.Set(); if (!holdsMutex) { throw new InvalidOperationException("Mutex should be unique"); } var connections = CreateServerFailsConnectionCore(pipeName, cts.Token).Result; taskSource.SetResult(new ServerStats(connections: connections, completedConnections: 0)); } }); thread.Start(); // Can't exit until the mutex is acquired. Otherwise the client can end up in a race // condition trying to start the server. mre.WaitOne(); } return(new ServerData(cts, taskSource.Task, pipeName)); }
internal static BuildRequest CreateEmptyCSharp(string workingDirectory, string tempDirectory = null) => BuildRequest.Create( RequestLanguage.CSharpCompile, Array.Empty <string>(), workingDirectory, tempDirectory ?? Path.GetTempPath(), compilerHash: BuildProtocolConstants.GetCommitHash());
internal static BuildRequest CreateEmptyCSharpWithKeepAlive(TimeSpan keepAlive) => BuildRequest.Create( RequestLanguage.CSharpCompile, Array.Empty <string>(), compilerHash: BuildProtocolConstants.GetCommitHash(), keepAlive: keepAlive.TotalSeconds.ToString());