Skip to content

Commit

Permalink
GD-127: Replace stdout based TestEventProcessor by IPC implementation (
Browse files Browse the repository at this point in the history
…#129)

# Why
see #127 

# What
- renamed project file to the real name `gdUnit4Net`
- introduced IPC for test event reporting
- increase api version to 4.3.0
- increase adapter version to 2.0.0
  • Loading branch information
MikeSchulze authored Jun 24, 2024
1 parent cb66317 commit 8f8327b
Show file tree
Hide file tree
Showing 20 changed files with 682 additions and 537 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ mono_crash.*.json

.fake
.ionide
gdUnit4Net.sln.DotSettings.user
4 changes: 2 additions & 2 deletions PackageVersions.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<MicrosoftSdkVersion>17.9.0</MicrosoftSdkVersion>
<MicrosoftCodeAnalysisCSharpVersion>4.9.2</MicrosoftCodeAnalysisCSharpVersion>
<MoqVersion>4.18.4</MoqVersion>
<GdUnitAPIVersion>4.2.5</GdUnitAPIVersion>
<GdUnitTestAdapterVersion>1.1.2</GdUnitTestAdapterVersion>
<GdUnitAPIVersion>4.3.0</GdUnitAPIVersion>
<GdUnitTestAdapterVersion>2.0.0</GdUnitTestAdapterVersion>
</PropertyGroup>
</Project>
35 changes: 34 additions & 1 deletion api/src/api/TestAdapterReporter.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
namespace GdUnit4.Api;

using System;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;

using Newtonsoft.Json;

internal class TestAdapterReporter : ITestEventListener
{
public const string PipeName = "gdunit4-event-pipe";
private readonly NamedPipeClientStream client;
private readonly StreamWriter? writer;

public TestAdapterReporter()
{
client = new NamedPipeClientStream(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous, TokenImpersonationLevel.Impersonation);
if (!client.IsConnected)
try
{
Console.WriteLine("Try to connect to GdUnit4 test report server!");
client.Connect(TimeSpan.FromSeconds(5));
writer = new StreamWriter(client) { AutoFlush = true };
writer.WriteLine("TestAdapterReporter: Successfully connected to GdUnit4 test report server!");
}
catch (TimeoutException e)
{
Console.Error.WriteLine(e);
throw;
}
}

public void Dispose()
{
writer?.WriteLine("TestAdapterReporter: Disconnecting from GdUnit4 test report server.");
writer?.Dispose();
client.Dispose();
}

public bool IsFailed { get; set; }

public void PublishEvent(TestEvent e)
{
if (e.IsFailed || e.IsError)
IsFailed = true;
var json = JsonConvert.SerializeObject(e);
Console.WriteLine($"GdUnitTestEvent:{json}");
writer!.WriteLine($"GdUnitTestEvent:{json}");
}
}
17 changes: 8 additions & 9 deletions api/src/api/TestReporter.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
namespace GdUnit4.Api;

using System;

using GdUnit4.Core;
using Core;

internal class TestReporter : ITestEventListener
{
public bool IsFailed { get; set; }

private static readonly GdUnitConsole Console = new();

public TestReporter()
{ }
public bool IsFailed { get; set; }

public void PublishEvent(TestEvent testEvent) => PrintStatus(testEvent);

public void Dispose()
{
}

private void PrintStatus(TestEvent testEvent)
{
switch (testEvent.Type)
Expand Down Expand Up @@ -74,9 +76,6 @@ void WriteStatus(TestEvent testEvent)

private static void WriteFailureReport(TestEvent testEvent)
{
foreach (var report in testEvent.Reports)
{
Console.Println(report.ToString().RichTextNormalize().Indentation(2), ConsoleColor.DarkCyan);
}
foreach (var report in testEvent.Reports) Console.Println(report.ToString().RichTextNormalize().Indentation(2), ConsoleColor.DarkCyan);
}
}
103 changes: 55 additions & 48 deletions api/src/api/TestRunner.cs
Original file line number Diff line number Diff line change
@@ -1,74 +1,68 @@
namespace GdUnit4.Api;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommandLine;

using GdUnit4.Executions;
using GdUnit4.Core;

using Newtonsoft.Json;

public partial class TestRunner : Godot.Node
{
using CommandLine;

public class Options
{
[Option(Required = false, HelpText = "If FailFast=true the test run will abort on first test failure.")]
public bool FailFast { get; set; } = false;
using Core;

[Option(Required = false, HelpText = "Runs the Runner in test adapter mode.")]
public bool TestAdapter { get; set; }
using Executions;

[Option(Required = false, HelpText = "The test runner config.")]
public string ConfigFile { get; set; } = "";
using Godot;

[Option(Required = false, HelpText = "Adds the given test suite or directory to the execution pipeline.")]
public string Add { get; set; } = "";
}
using Newtonsoft.Json;

public partial class TestRunner : Node
{
private bool FailFast { get; set; } = true;

public async Task RunTests()
{
var cmdArgs = Godot.OS.GetCmdlineArgs();
var cmdArgs = OS.GetCmdlineArgs();

await new Parser(with =>
{
with.EnableDashDash = true;
with.IgnoreUnknownArguments = true;
})
.ParseArguments<Options>(cmdArgs)
.WithParsedAsync(async o =>
{
FailFast = o.FailFast;
var exitCode = await (o.TestAdapter
? RunTests(LoadTestSuites(o.ConfigFile), new TestAdapterReporter())
: RunTests(LoadTestSuites(new DirectoryInfo(o.Add)), new TestReporter()));
Console.WriteLine($"Testrun ends with exit code: {exitCode}, FailFast:{FailFast}");
GetTree().Quit(exitCode);
});
{
with.EnableDashDash = true;
with.IgnoreUnknownArguments = true;
})
.ParseArguments<Options>(cmdArgs)
.WithParsedAsync(async o =>
{
FailFast = o.FailFast;
var exitCode = await (o.TestAdapter
? RunTests(LoadTestSuites(o.ConfigFile), new TestAdapterReporter())
: RunTests(LoadTestSuites(new DirectoryInfo(o.Add)), new TestReporter()));
Console.WriteLine($"Testrun ends with exit code: {exitCode}, FailFast:{FailFast}");
GetTree().Quit(exitCode);
});
}

private async Task<int> RunTests(IEnumerable<TestSuite> testSuites, ITestEventListener listener)
{
if (!testSuites.Any())
using (listener)
{
Console.Error.WriteLine("No testsuite's specified!, Abort!");
return -1;
}
using Executor executor = new();
executor.AddTestEventListener(listener);
if (!testSuites.Any())
{
Console.Error.WriteLine("No testsuite's specified!, Abort!");
return -1;
}

foreach (var testSuite in testSuites)
{
await executor.ExecuteInternally(testSuite!);
if (listener.IsFailed && FailFast)
break;
using Executor executor = new();
executor.AddTestEventListener(listener);

foreach (var testSuite in testSuites)
{
await executor.ExecuteInternally(testSuite!);
if (listener.IsFailed && FailFast)
break;
}

return listener.IsFailed ? 100 : 0;
}
return listener.IsFailed ? 100 : 0;
}

private static TestSuite? TryCreateTestSuite(KeyValuePair<string, IEnumerable<TestCaseConfig>> entry)
Expand Down Expand Up @@ -109,13 +103,26 @@ private static IEnumerable<TestSuite> LoadTestSuites(DirectoryInfo rootDir, stri
Console.WriteLine($"Scanning for test suites in: {currentDir.FullName}");

foreach (var filePath in Directory.EnumerateFiles(currentDir.FullName, searchPattern))
{
if (GdUnitTestSuiteBuilder.ParseType(filePath, true) != null)
yield return new TestSuite(filePath);
}

foreach (var directory in currentDir.GetDirectories())
stack.Push(directory);
}
}

public class Options
{
[Option(Required = false, HelpText = "If FailFast=true the test run will abort on first test failure.")]
public bool FailFast { get; set; } = false;

[Option(Required = false, HelpText = "Runs the Runner in test adapter mode.")]
public bool TestAdapter { get; set; }

[Option(Required = false, HelpText = "The test runner config.")]
public string ConfigFile { get; set; } = "";

[Option(Required = false, HelpText = "Adds the given test suite or directory to the execution pipeline.")]
public string Add { get; set; } = "";
}
}
5 changes: 3 additions & 2 deletions api/src/core/event/TestEventListener.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

namespace GdUnit4;

internal interface ITestEventListener
using System;

internal interface ITestEventListener : IDisposable
{
bool IsFailed { get; protected set; }

Expand Down
Loading

0 comments on commit 8f8327b

Please sign in to comment.