public async Task ExternalTool_WhenAsync_WithTimeout_EventuallyWritesBothOutputStreamsToFile() { // This does not really work... in the current implementation the stuff gets written, true, but only // once the timedout process actually finishes (if it ever does!). So is that really "working"? Eeeh... const string canary1 = "eb6b46bu6"; const string canary2 = "dsrt7n46n8"; var outputFile = Path.GetTempFileName(); // Need to do this the long way around to avoid consuming the result. var instance = new ExternalTool { ExecutablePath = TestData.CommandHandler, // The command is supposed to execute for a long time, to ensure that we time out below. Arguments = TestData.MakeCommandString(string.Format("echo {0} & {1} & {2}", canary1, canary2, TestData.GetSleepCommand(10))), OutputFilePath = outputFile }.Start(); try { using (var cancel = new CancellationTokenSource(TimeSpan.FromSeconds(2))) { // Should be long enough that the echo succeeds but short enough that the timeout does not. var result = await instance.GetResultAsync(cancel.Token); // Forward outputs to show what happened if we do not time out. result.ForwardOutputs(); } throw new Exception("Should have timed out before reaching this point!"); } catch (TaskCanceledException) { Debug.WriteLine("Expected timeout occurred."); // The file only becomes accessible when the process exits (even if we time out earlier). // So wait for the file to become accessible here. var timeout = new CancellationTokenSource(30000).Token; while (!timeout.IsCancellationRequested) { try { File.Open(outputFile, FileMode.Open, FileAccess.Read, FileShare.Read).Dispose(); break; } catch { timeout.WaitHandle.WaitOne(100); } } } try { var outputFileContents = File.ReadAllText(outputFile); Assert.IsTrue(outputFileContents.Contains(canary1)); Assert.IsTrue(outputFileContents.Contains(canary2)); } finally { try { File.Delete(outputFile); } catch { // Don't care if this fails (weird slow test runners and all that - file deletion is wonky). } } }