Skip to content

Commit

Permalink
Write the test log file as the test is running.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmds authored and omajid committed Jun 12, 2023
1 parent 706acd6 commit 1c5b2b3
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 340 deletions.
2 changes: 1 addition & 1 deletion Turkey.Tests/ProcessExtensionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public async Task WaitForExitAsync_DoesNotHangForOrphanedGrandChildren()
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(WaitTimeoutSeconds));

// The WaitForExit completes by cancellation.
await Assert.ThrowsAsync<TaskCanceledException>(() => process.WaitForExitAsync(cts.Token, new StringWriter(), new StringWriter()));
await Assert.ThrowsAsync<TaskCanceledException>(() => process.WaitForExitAsync(logger: msg => { }, cts.Token));
}
finally
{
Expand Down
16 changes: 7 additions & 9 deletions Turkey.Tests/TestOutputFormatTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xunit;

Expand Down Expand Up @@ -30,16 +31,15 @@ public async Task SingleTestWithPassingResultProducesValidXml()
var resultsFile = new FileInfo(Path.GetTempFileName());

var j = new TestOutputFormats.JUnitOutput(resultsFile);
var result = new TestResult(TestStatus.Passed, "", "");
await j.AfterRunningTestAsync("foo", result, new TimeSpan(0));
var result = TestResult.Passed;
await j.AfterRunningTestAsync("foo", result, new StringBuilder(), new TimeSpan(0));
await j.AfterRunningAllTestsAsync(null);
var xml = File.ReadAllText(resultsFile.FullName);

var expectedXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
<testsuite name=""dotnet"" tests=""1"" failures=""0"" errors=""0"">
<testcase name=""foo"" classname=""TestSuite"">
<system-out></system-out>
<system-err></system-err>
</testcase>
</testsuite>";

Expand All @@ -54,18 +54,16 @@ public async Task ControlCharactersInTestOutputAreNotPresentInXml()
var resultsFile = new FileInfo(Path.GetTempFileName());

var j = new TestOutputFormats.JUnitOutput(resultsFile);
var result = new TestResult(TestStatus.Passed,
standardOutput: "\u0001\u0002\u0003\u0004\u0005aaa\u0006\u0007\u0008",
standardError: "\u001A\u001B\u001Cbbb\u001d");
await j.AfterRunningTestAsync("foo", result, new TimeSpan(0));
var result = TestResult.Passed;
var testLog = new StringBuilder("\u0001\u0002\u0003\u0004\u0005aaa\u0006\u0007\u0008\u001A\u001B\u001Cbbb\u001d");
await j.AfterRunningTestAsync("foo", result, testLog, new TimeSpan(0));
await j.AfterRunningAllTestsAsync(null);
var xml = File.ReadAllText(resultsFile.FullName);

var expectedXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
<testsuite name=""dotnet"" tests=""1"" failures=""0"" errors=""0"">
<testcase name=""foo"" classname=""TestSuite"">
<system-out>aaa</system-out>
<system-err>bbb</system-err>
<system-out>aaabbb</system-out>
</testcase>
</testsuite>";

Expand Down
34 changes: 5 additions & 29 deletions Turkey/BashTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,13 @@ public BashTest(DirectoryInfo directory, SystemUnderTest system, string nuGetCon
{
}

protected override async Task<TestResult> InternalRunAsync(CancellationToken cancellationToken)
protected override async Task<TestResult> InternalRunAsync(Action<string> logger, CancellationToken cancellationToken)
{
var standardOutputWriter = new StringWriter();
var standardErrorWriter = new StringWriter();

FileInfo testFile = new FileInfo(Path.Combine(Directory.FullName, "test.sh"));
if (!testFile.Exists)
{
standardErrorWriter.WriteLine($"Unable to find 'test.sh' in {Directory.FullName}");
return new TestResult(
status: TestStatus.Failed,
standardOutput: standardOutputWriter.ToString(),
standardError: standardErrorWriter.ToString());
logger($"Unable to find 'test.sh' in {Directory.FullName}");
return TestResult.Failed;
}

ProcessStartInfo startInfo = new ProcessStartInfo()
Expand All @@ -44,27 +38,9 @@ protected override async Task<TestResult> InternalRunAsync(CancellationToken can
startInfo.EnvironmentVariables.Add(key, value);
}

standardOutputWriter.WriteLine($"Executing {startInfo.FileName} with arguments {startInfo.Arguments} in working directory {startInfo.WorkingDirectory}");
using (Process p = Process.Start(startInfo))
{
var status = TestStatus.Failed;
try
{
await p.WaitForExitAsync(cancellationToken, standardOutputWriter, standardErrorWriter);
status = (p.ExitCode == 0) ? TestStatus.Passed: TestStatus.Failed;
standardOutputWriter.WriteLine($"Exit Code: {p.ExitCode}");
}
catch (OperationCanceledException)
{
standardOutputWriter.WriteLine("[[TIMEOUT]]");
standardErrorWriter.WriteLine("[[TIMEOUT]]");
}
int exitCode = await ProcessRunner.RunAsync(startInfo, logger, cancellationToken);

return new TestResult(
status: status,
standardOutput: standardOutputWriter.ToString(),
standardError: standardErrorWriter.ToString());
}
return exitCode == 0 ? TestResult.Passed : TestResult.Failed;
}
}
}
43 changes: 8 additions & 35 deletions Turkey/DotNet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,7 @@ public Version LatestSdkVersion
}
}

public struct ProcessResult
{
public int ExitCode { get; }
public string StandardOutput { get; }
public string StandardError { get; }

public ProcessResult(int exitCode, string stdout, string stderr)
{
ExitCode = exitCode;
StandardOutput = stdout;
StandardError = stderr;
}
}

public static async Task<ProcessResult> BuildAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, CancellationToken token)
public static Task<int> BuildAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
{
var arguments = new string[]
{
Expand All @@ -102,21 +88,16 @@ public static async Task<ProcessResult> BuildAsync(DirectoryInfo workingDirector
"-p:UseSharedCompilation=false",
"-m:1",
};
var result = await RunDotNetCommandAsync(workingDirectory, arguments, environment, token);
return result;
return RunDotNetCommandAsync(workingDirectory, arguments, environment, logger, token);
}

public static async Task<ProcessResult> RunAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, CancellationToken token)
{
return await RunDotNetCommandAsync(workingDirectory, new string[] { "run", "--no-restore", "--no-build"} , environment, token);
}
public static Task<int> RunAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
=> RunDotNetCommandAsync(workingDirectory, new string[] { "run", "--no-restore", "--no-build"} , environment, logger, token);

public static async Task<ProcessResult> TestAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, CancellationToken token)
{
return await RunDotNetCommandAsync(workingDirectory, new string[] { "test", "--no-restore", "--no-build"} , environment, token);
}
public static Task<int> TestAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
=> RunDotNetCommandAsync(workingDirectory, new string[] { "test", "--no-restore", "--no-build"} , environment, logger, token);

private static async Task<ProcessResult> RunDotNetCommandAsync(DirectoryInfo workingDirectory, string[] commands, IReadOnlyDictionary<string, string> environment, CancellationToken token)
private static async Task<int> RunDotNetCommandAsync(DirectoryInfo workingDirectory, string[] commands, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
{
var arguments = string.Join(" ", commands);
ProcessStartInfo startInfo = new ProcessStartInfo()
Expand All @@ -134,15 +115,7 @@ private static async Task<ProcessResult> RunDotNetCommandAsync(DirectoryInfo wor
startInfo.EnvironmentVariables.Add(key, value);
}

using (var process = Process.Start(startInfo))
{
StringWriter standardOutputWriter = new StringWriter();
StringWriter standardErrorWriter = new StringWriter();
await process.WaitForExitAsync(token, standardOutputWriter, standardErrorWriter);
int exitCode = exitCode = process.ExitCode;

return new ProcessResult(exitCode, standardOutputWriter.ToString(), standardErrorWriter.ToString());
}
return await ProcessRunner.RunAsync(startInfo, logger, token);
}
}
}
36 changes: 0 additions & 36 deletions Turkey/LogWriter.cs

This file was deleted.

49 changes: 33 additions & 16 deletions Turkey/ProcessExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,55 @@

namespace Turkey
{
public static class ProcessRunner
{
public static async Task<int> RunAsync(ProcessStartInfo psi, Action<string> logger, CancellationToken token)
{
logger($"Executing {psi.FileName} with arguments {psi.Arguments} in working directory {psi.WorkingDirectory}");
using var process = Process.Start(psi);
await process.WaitForExitAsync(logger, token);
return process.ExitCode;
}
}

public static class ProcessExtensions
{
public static async Task WaitForExitAsync(this Process process, CancellationToken token, TextWriter standardOutput, TextWriter standardError)
public static async Task WaitForExitAsync(this Process process, Action<string> logger, CancellationToken token)
{
process.EnableRaisingEvents = true;
var outputHandler = new DataReceivedEventHandler(
(sender, e) =>
{
if (e.Data != null)
{
standardOutput.WriteLine(e.Data);
}
});
var errorHandler = new DataReceivedEventHandler(
(sender, e) =>
bool captureOutput = true;
DataReceivedEventHandler logToLogger = (sender, e) =>
{
if (e.Data != null)
{
if (e.Data != null)
lock (logger)
{
standardError.WriteLine(e.Data);
if (captureOutput)
{
logger(e.Data);
}
}
});
process.OutputDataReceived += outputHandler;
}
};
process.OutputDataReceived += logToLogger;
process.BeginOutputReadLine();
process.ErrorDataReceived += errorHandler;
process.ErrorDataReceived += logToLogger;
process.BeginErrorReadLine();

try
{
await process.WaitForExitAsync(token);

logger($"Process Exit Code: {process.ExitCode}");
}
catch (OperationCanceledException ex)
{
lock (logger)
{
captureOutput = false;
}
logger($"Process wait for exit cancelled.");

try
{
process.Kill(entireProcessTree: true);
Expand Down
18 changes: 2 additions & 16 deletions Turkey/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ public class Program
new string[] { "--verbose", "-v" },
"Show verbose output");

public static readonly Option<bool> compatibleOption = new Option<bool>(
new string[] { "--compatible", "-c" },
"Make output compatible with dotnet-bunny");

public static readonly Option<string> logDirectoryOption = new Option<string>(
new string[] { "--log-directory", "-l" },
"Set directory for writing log files");
Expand All @@ -43,7 +39,6 @@ public class Program

public static async Task<int> Run(string testRoot,
bool verbose,
bool compatible,
string logDirectory,
string additionalFeed,
IEnumerable<string> trait,
Expand Down Expand Up @@ -87,17 +82,11 @@ public static async Task<int> Run(string testRoot,
}
Console.WriteLine($"Testing everything under {testRootDirectory.FullName}");

LogWriter logWriter = new LogWriter(logDir);

Cleaner cleaner = new Cleaner();

DotNet dotnet = new DotNet();

TestOutput defaultOutput = new TestOutputFormats.NewOutput(logWriter);
if (compatible)
{
defaultOutput = new TestOutputFormats.DotNetBunnyOutput(logWriter);
}
TestOutput defaultOutput = new TestOutputFormats.NewOutput();

TestOutput junitOutput = new TestOutputFormats.JUnitOutput(logDir);

Expand Down Expand Up @@ -138,9 +127,7 @@ public static async Task<int> Run(string testRoot,
verboseOutput: verbose,
nuGetConfig: nuGetConfig);

var cancellationTokenSource = new Func<CancellationTokenSource>(() => new CancellationTokenSource(timeoutForEachTest));

var results = await runner.ScanAndRunAsync(testOutputs, cancellationTokenSource);
var results = await runner.ScanAndRunAsync(testOutputs, logDir.FullName, timeoutForEachTest);

int exitCode = (results.Failed == 0) ? 0 : 1;
return exitCode;
Expand Down Expand Up @@ -257,7 +244,6 @@ static async Task<int> Main(string[] args)
testRootArgument.Arity = ArgumentArity.ZeroOrOne;

rootCommand.AddArgument(testRootArgument);
rootCommand.AddOption(compatibleOption);
rootCommand.AddOption(verboseOption);
rootCommand.AddOption(logDirectoryOption);
rootCommand.AddOption(additionalFeedOption);
Expand Down
Loading

0 comments on commit 1c5b2b3

Please sign in to comment.