Skip to content

Commit

Permalink
1.1.0-beta1 Release
Browse files Browse the repository at this point in the history
1.1.0-beta1 Release
  • Loading branch information
Arkatufus committed Nov 8, 2021
2 parents ed71eb0 + 8724ee5 commit 529608f
Show file tree
Hide file tree
Showing 83 changed files with 2,685 additions and 1,934 deletions.
1 change: 0 additions & 1 deletion NuGet.Config
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="myget.org/F/xunit" value="https://www.myget.org/F/xunit/api/v3/index.json" protocolVersion="3" />
<add key="myget.org/F/b4ff5f6" value="http://www.myget.org/F/b4ff5f68eccf4f6bbfed74f055f88d8f/api/v3/index.json" protocolVersion="3" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
Expand Down
27 changes: 27 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
#### 1.1.0-beta1 October 20 2019 ####

- [Switch to pure Xunit implementation](https://github.com/akkadotnet/Akka.MultiNodeTestRunner/pull/105)

In this release we removed VSTest Adapter and moved to a pure Xunit implementation. This brings about a few changes that needs to be observed:

- Moved `.runsettings` configuration feature to `xunit.multinode.runner.json`

`.runsettings` content are not passed downstream by `dotnet test` to the actual test runner, so this feature is moved to Xunit-like configuration through a .json file. You can declare your setting file name as either `{assembly_name}.xunit.multinode.runner.json` or `xunit.multinode.runner.json`. Supported settings are:
- `outputDirectory`: the output directory where all the runner logs will be stored. Note that this is different than the `dotnet test --result-directory` settings which dictates where the VSTest reporter will export their outputs.
__Default:__ `TestResults` in the folder where the tested assembly is located.
- `failedSpecsDirectory`: an output directory __inside the `outputDirectory`__ where all aggregated failed logs will be stored.
__Default:__ `FAILED_SPECS_LOGS`
- `listenAddress`: the host name or IP of the machine that is running the test. Will be bound to the TCP logging service.
__Default:__ `127.0.0.1` (localhost)
- `listenPort`: the port where the TCP logging service will be listening to. a random free port will be used if set to 0.
__Default:__ 0
- `appendLogOutput`: if set, all logs are appended to the old logs from previous runs.
__Default:__ true

- Parallelized test support (__BETA__)

Tests can be run in parallel now, with caveats. Parallel test is not recommended if any of your tests are very timing dependent;
it is still recommended that you __do not__ run your tests in parallel. Note that Xunit turns this feature on __by default__, so if your tests are failing, make sure that this feature is properly turned off. Please read the xunit [documentation](https://xunit.net/docs/running-tests-in-parallel) on how to set this up.

Note that the `maxParallelThreads` in Xunit will not be honored by this test adapter because MultiNode tests will spawn a process for every cluster node being used inside the test, inflating the number of threads being used inside a test.

#### 1.0.0 October 20 2019 ####
- Fix [result folder clearing, add documentation](https://github.com/akkadotnet/Akka.MultiNodeTestRunner/pull/95)

Expand Down
185 changes: 53 additions & 132 deletions src/Akka.MultiNode.RemoteHost/RemoteHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,166 +4,87 @@
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace Akka.MultiNode.RemoteHost
{
public static class RemoteHost
{
#region Static functions

public static Process Start(Action action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;

public static Process Start(Action<string[]> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;

public static Process Start(Func<int> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;

public static Process Start(Func<string[], int> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;

public static Process Start(Func<Task> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;

public static Process Start(Func<string[], Task> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;

public static Process Start(Func<Task<int>> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;

public static Process Start(Func<string[], Task<int>> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;

public static void Run(Action action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);

public static void Run(Action<string[]> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);

public static void Run(Func<int> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);

public static void Run(Func<string[], int> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);

public static void Run(Func<Task> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);

public static void Run(Func<string[], Task> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);

public static void Run(Func<Task<int>> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);

public static void Run(Func<string[], Task<int>> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);

public static Task RunAsync(Action action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;

public static Task RunAsync(Action<string[]> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;

public static Task RunAsync(Func<int> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;

public static Task RunAsync(Func<string[], int> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;

public static Task RunAsync(Func<Task> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;

public static Task RunAsync(Func<string[], Task> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;

public static Task RunAsync(Func<Task<int>> action, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;

public static Task RunAsync(Func<string[], Task<int>> action, string[] args, Action<RemoteHostOptions> configure = null)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;
public static (Process, Task) RunProcessAsync(
Func<string[], Task<int>> action,
string[] args,
Action<RemoteHostOptions> configure = null,
CancellationToken token = default)
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, token);

private static (Process process, Task exitedTask) Start(
MethodInfo method,
string[] args,
Action<RemoteHostOptions> configure,
bool waitForExit = false,
bool returnTask = false)
CancellationToken token = default)
{
Process process = null;
var process = new Process();
RemoteHostOptions options;
try
{
process = new Process();

var options = new RemoteHostOptions(process.StartInfo);
options = new RemoteHostOptions(process.StartInfo);
ConfigureProcessStartInfoForMethodInvocation(method, args, options.StartInfo);
configure?.Invoke(options);

TaskCompletionSource<bool> tcs = null;
if (returnTask)
{
tcs = new TaskCompletionSource<bool>();
}

if (options.OnExit != null || tcs != null)
}
catch
{
process.Dispose();
throw;
}

var tcs = new TaskCompletionSource<bool>();
if (token != default)
{
token.Register(() =>
{
process.EnableRaisingEvents = true;
process.Exited += (_1, _2) =>
try
{
options.OnExit(process);
if (tcs != null)
{
tcs?.SetResult(true);
process.Dispose();
}
};
}

if (options.OutputDataReceived != null)
{
process.OutputDataReceived += options.OutputDataReceived;
options.StartInfo.RedirectStandardOutput = true;
}

if (options.ErrorDataReceived != null)
{
process.ErrorDataReceived += options.ErrorDataReceived;
options.StartInfo.RedirectStandardError = true;
}
process.Kill();
} catch{}
});
}

process.Start();

if (options.OutputDataReceived != null)
{
process.BeginOutputReadLine();
}
process.EnableRaisingEvents = true;
process.Exited += (_1, _2) =>
{
options.OnExit(process);
if (options.ErrorDataReceived != null)
{
process.BeginErrorReadLine();
}
tcs.SetResult(true);
process.Dispose();
};

if (waitForExit)
{
process.WaitForExit();
}
if (options.OutputDataReceived != null)
{
process.OutputDataReceived += options.OutputDataReceived;
options.StartInfo.RedirectStandardOutput = true;
}

return (process, tcs?.Task);
if (options.ErrorDataReceived != null)
{
process.ErrorDataReceived += options.ErrorDataReceived;
options.StartInfo.RedirectStandardError = true;
}
catch

process.Start();

if (options.OutputDataReceived != null)
{
process?.Dispose();
throw;
process.BeginOutputReadLine();
}
finally

if (options.ErrorDataReceived != null)
{
if (waitForExit)
{
process?.Dispose();
}
process.BeginErrorReadLine();
}

return (process, tcs.Task);
}

private static void ConfigureProcessStartInfoForMethodInvocation(
Expand Down
71 changes: 0 additions & 71 deletions src/Akka.MultiNode.SampleMultiNodeTests/.runsettings

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
<ItemGroup>
<PackageReference Include="Akka.Cluster.TestKit" Version="$(AkkaVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="FluentAssertions" Version="$(FluentAssertionsVersion)" />
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" Version="$(TestSdkVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Akka.MultiNode.TestAdapter\Akka.MultiNode.TestAdapter.csproj" />
</ItemGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Akka.Cluster.TestKit;
using Akka.Remote.TestKit;
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;

namespace Akka.MultiNode.TestAdapter.SampleTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Akka.Cluster.TestKit;
using Akka.Remote.TestKit;
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;

namespace Akka.MultiNode.TestAdapter.SampleTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Xunit;
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;

namespace Akka.MultiNode.TestAdapter.SampleTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Xunit;

[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace Akka.MultiNode.TestAdapter.SampleTests.Metadata
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Akka.Cluster.TestKit;
using Akka.Remote.TestKit;
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;

namespace Akka.MultiNode.TestAdapter.SampleTests
{
Expand Down Expand Up @@ -33,7 +34,7 @@ private OneNodeFailedMultiNodeSpec(FailedMultiNodeSpecConfig config) : base(conf
}

[MultiNodeFact]
public void Should_fail()
public void One_node_failed_should_fail()
{
RunOn(() => throw new Exception("Spec should fail"), _config.First);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Akka.Cluster.TestKit;
using Akka.Remote.TestKit;
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;

namespace Akka.MultiNode.TestAdapter.SampleTests
{
Expand Down

0 comments on commit 529608f

Please sign in to comment.