Skip to content

Commit 529608f

Browse files
authored
1.1.0-beta1 Release
1.1.0-beta1 Release
2 parents ed71eb0 + 8724ee5 commit 529608f

File tree

83 files changed

+2685
-1934
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2685
-1934
lines changed

NuGet.Config

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<configuration>
33
<packageSources>
4-
<clear />
54
<add key="myget.org/F/xunit" value="https://www.myget.org/F/xunit/api/v3/index.json" protocolVersion="3" />
65
<add key="myget.org/F/b4ff5f6" value="http://www.myget.org/F/b4ff5f68eccf4f6bbfed74f055f88d8f/api/v3/index.json" protocolVersion="3" />
76
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />

RELEASE_NOTES.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
#### 1.1.0-beta1 October 20 2019 ####
2+
3+
- [Switch to pure Xunit implementation](https://github.com/akkadotnet/Akka.MultiNodeTestRunner/pull/105)
4+
5+
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:
6+
7+
- Moved `.runsettings` configuration feature to `xunit.multinode.runner.json`
8+
9+
`.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:
10+
- `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.
11+
__Default:__ `TestResults` in the folder where the tested assembly is located.
12+
- `failedSpecsDirectory`: an output directory __inside the `outputDirectory`__ where all aggregated failed logs will be stored.
13+
__Default:__ `FAILED_SPECS_LOGS`
14+
- `listenAddress`: the host name or IP of the machine that is running the test. Will be bound to the TCP logging service.
15+
__Default:__ `127.0.0.1` (localhost)
16+
- `listenPort`: the port where the TCP logging service will be listening to. a random free port will be used if set to 0.
17+
__Default:__ 0
18+
- `appendLogOutput`: if set, all logs are appended to the old logs from previous runs.
19+
__Default:__ true
20+
21+
- Parallelized test support (__BETA__)
22+
23+
Tests can be run in parallel now, with caveats. Parallel test is not recommended if any of your tests are very timing dependent;
24+
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.
25+
26+
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.
27+
128
#### 1.0.0 October 20 2019 ####
229
- Fix [result folder clearing, add documentation](https://github.com/akkadotnet/Akka.MultiNodeTestRunner/pull/95)
330

src/Akka.MultiNode.RemoteHost/RemoteHost.cs

Lines changed: 53 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -4,166 +4,87 @@
44
using System.IO;
55
using System.Reflection;
66
using System.Runtime.InteropServices;
7+
using System.Threading;
78
using System.Threading.Tasks;
89

910
namespace Akka.MultiNode.RemoteHost
1011
{
1112
public static class RemoteHost
1213
{
1314
#region Static functions
14-
15-
public static Process Start(Action action, Action<RemoteHostOptions> configure = null)
16-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;
17-
18-
public static Process Start(Action<string[]> action, string[] args, Action<RemoteHostOptions> configure = null)
19-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;
20-
21-
public static Process Start(Func<int> action, Action<RemoteHostOptions> configure = null)
22-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;
23-
24-
public static Process Start(Func<string[], int> action, string[] args, Action<RemoteHostOptions> configure = null)
25-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;
26-
27-
public static Process Start(Func<Task> action, Action<RemoteHostOptions> configure = null)
28-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;
29-
30-
public static Process Start(Func<string[], Task> action, string[] args, Action<RemoteHostOptions> configure = null)
31-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;
32-
33-
public static Process Start(Func<Task<int>> action, Action<RemoteHostOptions> configure = null)
34-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure).process;
35-
36-
public static Process Start(Func<string[], Task<int>> action, string[] args, Action<RemoteHostOptions> configure = null)
37-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure).process;
38-
39-
public static void Run(Action action, Action<RemoteHostOptions> configure = null)
40-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);
41-
42-
public static void Run(Action<string[]> action, string[] args, Action<RemoteHostOptions> configure = null)
43-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);
44-
45-
public static void Run(Func<int> action, Action<RemoteHostOptions> configure = null)
46-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);
47-
48-
public static void Run(Func<string[], int> action, string[] args, Action<RemoteHostOptions> configure = null)
49-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);
50-
51-
public static void Run(Func<Task> action, Action<RemoteHostOptions> configure = null)
52-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);
53-
54-
public static void Run(Func<string[], Task> action, string[] args, Action<RemoteHostOptions> configure = null)
55-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);
56-
57-
public static void Run(Func<Task<int>> action, Action<RemoteHostOptions> configure = null)
58-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, waitForExit: true);
59-
60-
public static void Run(Func<string[], Task<int>> action, string[] args, Action<RemoteHostOptions> configure = null)
61-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, waitForExit: true);
62-
63-
public static Task RunAsync(Action action, Action<RemoteHostOptions> configure = null)
64-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;
65-
66-
public static Task RunAsync(Action<string[]> action, string[] args, Action<RemoteHostOptions> configure = null)
67-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;
68-
69-
public static Task RunAsync(Func<int> action, Action<RemoteHostOptions> configure = null)
70-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;
71-
72-
public static Task RunAsync(Func<string[], int> action, string[] args, Action<RemoteHostOptions> configure = null)
73-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;
74-
75-
public static Task RunAsync(Func<Task> action, Action<RemoteHostOptions> configure = null)
76-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;
77-
78-
public static Task RunAsync(Func<string[], Task> action, string[] args, Action<RemoteHostOptions> configure = null)
79-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;
80-
81-
public static Task RunAsync(Func<Task<int>> action, Action<RemoteHostOptions> configure = null)
82-
=> Start(GetMethodInfo(action), Array.Empty<string>(), configure, returnTask: true).exitedTask;
83-
84-
public static Task RunAsync(Func<string[], Task<int>> action, string[] args, Action<RemoteHostOptions> configure = null)
85-
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, returnTask: true).exitedTask;
15+
public static (Process, Task) RunProcessAsync(
16+
Func<string[], Task<int>> action,
17+
string[] args,
18+
Action<RemoteHostOptions> configure = null,
19+
CancellationToken token = default)
20+
=> Start(GetMethodInfo(action), args ?? throw new ArgumentNullException(nameof(args)), configure, token);
8621

8722
private static (Process process, Task exitedTask) Start(
8823
MethodInfo method,
8924
string[] args,
9025
Action<RemoteHostOptions> configure,
91-
bool waitForExit = false,
92-
bool returnTask = false)
26+
CancellationToken token = default)
9327
{
94-
Process process = null;
28+
var process = new Process();
29+
RemoteHostOptions options;
9530
try
9631
{
97-
process = new Process();
98-
99-
var options = new RemoteHostOptions(process.StartInfo);
32+
options = new RemoteHostOptions(process.StartInfo);
10033
ConfigureProcessStartInfoForMethodInvocation(method, args, options.StartInfo);
10134
configure?.Invoke(options);
102-
103-
TaskCompletionSource<bool> tcs = null;
104-
if (returnTask)
105-
{
106-
tcs = new TaskCompletionSource<bool>();
107-
}
108-
109-
if (options.OnExit != null || tcs != null)
35+
}
36+
catch
37+
{
38+
process.Dispose();
39+
throw;
40+
}
41+
42+
var tcs = new TaskCompletionSource<bool>();
43+
if (token != default)
44+
{
45+
token.Register(() =>
11046
{
111-
process.EnableRaisingEvents = true;
112-
process.Exited += (_1, _2) =>
47+
try
11348
{
114-
options.OnExit(process);
115-
116-
if (tcs != null)
117-
{
118-
tcs?.SetResult(true);
119-
process.Dispose();
120-
}
121-
};
122-
}
123-
124-
if (options.OutputDataReceived != null)
125-
{
126-
process.OutputDataReceived += options.OutputDataReceived;
127-
options.StartInfo.RedirectStandardOutput = true;
128-
}
129-
130-
if (options.ErrorDataReceived != null)
131-
{
132-
process.ErrorDataReceived += options.ErrorDataReceived;
133-
options.StartInfo.RedirectStandardError = true;
134-
}
49+
process.Kill();
50+
} catch{}
51+
});
52+
}
13553

136-
process.Start();
137-
138-
if (options.OutputDataReceived != null)
139-
{
140-
process.BeginOutputReadLine();
141-
}
54+
process.EnableRaisingEvents = true;
55+
process.Exited += (_1, _2) =>
56+
{
57+
options.OnExit(process);
14258

143-
if (options.ErrorDataReceived != null)
144-
{
145-
process.BeginErrorReadLine();
146-
}
59+
tcs.SetResult(true);
60+
process.Dispose();
61+
};
14762

148-
if (waitForExit)
149-
{
150-
process.WaitForExit();
151-
}
63+
if (options.OutputDataReceived != null)
64+
{
65+
process.OutputDataReceived += options.OutputDataReceived;
66+
options.StartInfo.RedirectStandardOutput = true;
67+
}
15268

153-
return (process, tcs?.Task);
69+
if (options.ErrorDataReceived != null)
70+
{
71+
process.ErrorDataReceived += options.ErrorDataReceived;
72+
options.StartInfo.RedirectStandardError = true;
15473
}
155-
catch
74+
75+
process.Start();
76+
77+
if (options.OutputDataReceived != null)
15678
{
157-
process?.Dispose();
158-
throw;
79+
process.BeginOutputReadLine();
15980
}
160-
finally
81+
82+
if (options.ErrorDataReceived != null)
16183
{
162-
if (waitForExit)
163-
{
164-
process?.Dispose();
165-
}
84+
process.BeginErrorReadLine();
16685
}
86+
87+
return (process, tcs.Task);
16788
}
16889

16990
private static void ConfigureProcessStartInfoForMethodInvocation(

src/Akka.MultiNode.SampleMultiNodeTests/.runsettings

Lines changed: 0 additions & 71 deletions
This file was deleted.

src/Akka.MultiNode.SampleMultiNodeTests/Akka.MultiNode.SampleMultiNodeTests.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
<ItemGroup>
99
<PackageReference Include="Akka.Cluster.TestKit" Version="$(AkkaVersion)" />
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
11-
<PackageReference Include="FluentAssertions" Version="$(FluentAssertionsVersion)" />
12-
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" Version="$(TestSdkVersion)" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\Akka.MultiNode.TestAdapter\Akka.MultiNode.TestAdapter.csproj" />
1315
</ItemGroup>
1416

1517
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

src/Akka.MultiNode.SampleMultiNodeTests/BadConfigMultiNodeSpec.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using Akka.Cluster.TestKit;
33
using Akka.Remote.TestKit;
4+
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;
45

56
namespace Akka.MultiNode.TestAdapter.SampleTests
67
{

src/Akka.MultiNode.SampleMultiNodeTests/FailedMultiNodeSpec.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using Akka.Cluster.TestKit;
33
using Akka.Remote.TestKit;
4+
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;
45

56
namespace Akka.MultiNode.TestAdapter.SampleTests
67
{

src/Akka.MultiNode.SampleMultiNodeTests/IgnoredXunitTest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using Xunit;
3+
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;
34

45
namespace Akka.MultiNode.TestAdapter.SampleTests
56
{

src/Akka.MultiNode.SampleMultiNodeTests/Metadata/SampleTestsMetadata.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using Xunit;
2+
3+
[assembly: CollectionBehavior(DisableTestParallelization = true)]
14
namespace Akka.MultiNode.TestAdapter.SampleTests.Metadata
25
{
36
/// <summary>

src/Akka.MultiNode.SampleMultiNodeTests/OneNodeFailedMultiNodeSpec.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using Akka.Cluster.TestKit;
33
using Akka.Remote.TestKit;
4+
using MultiNodeFactAttribute = Akka.MultiNode.TestAdapter.MultiNodeFactAttribute;
45

56
namespace Akka.MultiNode.TestAdapter.SampleTests
67
{
@@ -33,7 +34,7 @@ private OneNodeFailedMultiNodeSpec(FailedMultiNodeSpecConfig config) : base(conf
3334
}
3435

3536
[MultiNodeFact]
36-
public void Should_fail()
37+
public void One_node_failed_should_fail()
3738
{
3839
RunOn(() => throw new Exception("Spec should fail"), _config.First);
3940
}

0 commit comments

Comments
 (0)