diff --git a/Akka.MultiNodeTestRunner.sln b/Akka.MultiNodeTestRunner.sln
index 1d9a60b..d3ab93a 100644
--- a/Akka.MultiNodeTestRunner.sln
+++ b/Akka.MultiNodeTestRunner.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.47
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNodeTestRunner", "src\Akka.MultiNodeTestRunner\Akka.MultiNodeTestRunner.csproj", "{E945AABA-2779-41E8-9B43-8898FFD64F22}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNode.TestRunner", "src\Akka.MultiNode.TestRunner\Akka.MultiNode.TestRunner.csproj", "{E945AABA-2779-41E8-9B43-8898FFD64F22}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{79D71264-186B-4F62-8930-35DD9ECCAF3B}"
ProjectSection(SolutionItems) = preProject
@@ -13,11 +13,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{79D71264
build.sh = build.sh
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNodeTestRunner.Shared", "src\Akka.MultiNodeTestRunner.Shared\Akka.MultiNodeTestRunner.Shared.csproj", "{2F249AFE-6F7E-42CA-9D84-A3914F9DD158}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNode.Shared", "src\Akka.MultiNode.Shared\Akka.MultiNode.Shared.csproj", "{2F249AFE-6F7E-42CA-9D84-A3914F9DD158}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.NodeTestRunner", "src\Akka.NodeTestRunner\Akka.NodeTestRunner.csproj", "{5150BF37-8247-4A47-AFB6-300DD7426DC4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNode.NodeRunner", "src\Akka.MultiNode.NodeRunner\Akka.MultiNode.NodeRunner.csproj", "{5150BF37-8247-4A47-AFB6-300DD7426DC4}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNodeTestRunner.Shared.Tests", "src\Akka.MultiNodeTestRunner.Shared.Tests\Akka.MultiNodeTestRunner.Shared.Tests.csproj", "{6E3C7F54-F954-4D4C-B9CA-ACFEF046E036}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.MultiNode.Shared.Tests", "src\Akka.MultiNode.Shared.Tests\Akka.MultiNode.Shared.Tests.csproj", "{6E3C7F54-F954-4D4C-B9CA-ACFEF046E036}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.MultiNode.TestAdapter", "src\Akka.MultiNode.TestAdapter\Akka.MultiNode.TestAdapter.csproj", "{F3037C62-E780-4619-89B3-BA21C7168DFA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.MultiNode.SampleMultiNodeTests", "src\Akka.MultiNode.SampleMultiNodeTests\Akka.MultiNode.SampleMultiNodeTests.csproj", "{89D2C131-718F-4C93-9343-72E5BE6F7317}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.MultiNode.TestRunner.Shared", "src\Akka.MultiNode.TestRunner.Shared\Akka.MultiNode.TestRunner.Shared.csproj", "{ECAF9A0E-8ED2-460A-8408-4648F2BC3FB5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.MultiNode.TestAdapter.Tests", "src\Akka.MultiNode.TestAdapter.Tests\Akka.MultiNode.TestAdapter.Tests.csproj", "{A66D60EE-714F-4297-A9BD-222CFD868C28}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -41,6 +49,22 @@ Global
{6E3C7F54-F954-4D4C-B9CA-ACFEF046E036}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E3C7F54-F954-4D4C-B9CA-ACFEF046E036}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E3C7F54-F954-4D4C-B9CA-ACFEF046E036}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F3037C62-E780-4619-89B3-BA21C7168DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F3037C62-E780-4619-89B3-BA21C7168DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F3037C62-E780-4619-89B3-BA21C7168DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F3037C62-E780-4619-89B3-BA21C7168DFA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {89D2C131-718F-4C93-9343-72E5BE6F7317}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {89D2C131-718F-4C93-9343-72E5BE6F7317}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {89D2C131-718F-4C93-9343-72E5BE6F7317}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {89D2C131-718F-4C93-9343-72E5BE6F7317}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ECAF9A0E-8ED2-460A-8408-4648F2BC3FB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ECAF9A0E-8ED2-460A-8408-4648F2BC3FB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ECAF9A0E-8ED2-460A-8408-4648F2BC3FB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ECAF9A0E-8ED2-460A-8408-4648F2BC3FB5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A66D60EE-714F-4297-A9BD-222CFD868C28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A66D60EE-714F-4297-A9BD-222CFD868C28}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A66D60EE-714F-4297-A9BD-222CFD868C28}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A66D60EE-714F-4297-A9BD-222CFD868C28}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/NuGet.Config b/NuGet.Config
index c1584db..e11b891 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -1,10 +1,12 @@
-
-
-
-
+
+
+
-
\ No newline at end of file
+
+
+
+
diff --git a/build.fsx b/build.fsx
index 9f51c7a..09b5a5d 100644
--- a/build.fsx
+++ b/build.fsx
@@ -201,9 +201,9 @@ Target "CreateNuget" (fun _ ->
let projects = !! "src/**/*.csproj"
-- "src/**/*Tests.csproj" // Don't publish unit tests
-- "src/**/*Tests*.csproj"
- -- "src/**/*.MultiNodeTestRunner.csproj"
- -- "src/**/*.MultiNodeTestRunner.Shared.csproj"
- -- "src/**/*.NodeTestRunner.csproj"
+ -- "src/**/*.MultiNode.TestRunner.csproj"
+ -- "src/**/*.MultiNode.TestRunner.Shared.csproj"
+ -- "src/**/*.MultiNode.NodeRunner.csproj"
let runSingleProject project =
DotNetCli.Pack
@@ -219,7 +219,7 @@ Target "CreateNuget" (fun _ ->
)
Target "PublishMntr" (fun _ ->
- let executableProjects = !! "./src/**/Akka.MultiNodeTestRunner.csproj"
+ let executableProjects = !! "./src/**/Akka.MultiNode.TestRunner.csproj"
executableProjects |> Seq.iter (fun project ->
DotNetCli.Restore
@@ -251,12 +251,12 @@ Target "PublishMntr" (fun _ ->
Target "CreateMntrNuget" (fun _ ->
// uses the template file to create a temporary .nuspec file with the correct version
- CopyFile "./src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec" "./src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec.template"
+ CopyFile "./src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.nuspec" "./src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.nuspec.template"
let commonPropsVersionPrefix = XMLRead true "./src/common.props" "" "" "//Project/PropertyGroup/VersionPrefix" |> Seq.head
let versionReplacement = List.ofSeq [ "@version@", commonPropsVersionPrefix + (if (not (versionSuffix = "")) then ("-" + versionSuffix) else "") ]
- TemplateHelper.processTemplates versionReplacement [ "./src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec" ]
+ TemplateHelper.processTemplates versionReplacement [ "./src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.nuspec" ]
- let executableProjects = !! "./src/**/Akka.MultiNodeTestRunner.csproj"
+ let executableProjects = !! "./src/**/Akka.MultiNode.TestRunner.csproj"
executableProjects |> Seq.iter (fun project ->
DotNetCli.Pack
@@ -269,7 +269,7 @@ Target "CreateMntrNuget" (fun _ ->
OutputPath = "\"" + outputNuGet + "\"" } )
)
- DeleteFile "./src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec"
+ DeleteFile "./src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.nuspec"
)
Target "PublishNuget" (fun _ ->
@@ -356,7 +356,7 @@ Target "Nuget" DoNothing
"Build" ==> "RunTests"
// nuget dependencies
-"Clean" ==> "Build" ==> "CreateMntrNuget" ==> "CreateNuget"
+"BuildRelease" ==> "CreateMntrNuget" ==> "CreateNuget"
"CreateNuget" ==> "SignPackages" ==> "PublishNuget" ==> "Nuget"
// docs
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..80d84a2
--- /dev/null
+++ b/global.json
@@ -0,0 +1,5 @@
+{
+ "msbuild-sdks": {
+ "MSBuild.Sdk.Extras": "2.0.54"
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.NodeTestRunner/Akka.NodeTestRunner.csproj b/src/Akka.MultiNode.NodeRunner/Akka.MultiNode.NodeRunner.csproj
similarity index 73%
rename from src/Akka.NodeTestRunner/Akka.NodeTestRunner.csproj
rename to src/Akka.MultiNode.NodeRunner/Akka.MultiNode.NodeRunner.csproj
index 2a0ccf8..8e6f508 100644
--- a/src/Akka.NodeTestRunner/Akka.NodeTestRunner.csproj
+++ b/src/Akka.MultiNode.NodeRunner/Akka.MultiNode.NodeRunner.csproj
@@ -1,17 +1,16 @@
+
- Akka.NodeTestRunner
+ Akka.MultiNode.NodeRunner
$(NetFrameworkTestVersion);$(NetCoreTestVersion)
Exe
+ Akka.MultiNode.NodeRunner
+ true
-
-
-
-
-
+
@@ -21,6 +20,10 @@
+
+
+
+
$(DefineConstants);CORECLR
diff --git a/src/Akka.NodeTestRunner/Discovery.cs b/src/Akka.MultiNode.NodeRunner/Discovery.cs
similarity index 97%
rename from src/Akka.NodeTestRunner/Discovery.cs
rename to src/Akka.MultiNode.NodeRunner/Discovery.cs
index e8d083b..dca083c 100644
--- a/src/Akka.NodeTestRunner/Discovery.cs
+++ b/src/Akka.MultiNode.NodeRunner/Discovery.cs
@@ -11,7 +11,7 @@
using Xunit;
using Xunit.Abstractions;
-namespace Akka.NodeTestRunner
+namespace Akka.MultiNode.NodeRunner
{
[Serializable]
public class Discovery : TestMessageVisitor
diff --git a/src/Akka.NodeTestRunner/Program.cs b/src/Akka.MultiNode.NodeRunner/Program.cs
similarity index 89%
rename from src/Akka.NodeTestRunner/Program.cs
rename to src/Akka.MultiNode.NodeRunner/Program.cs
index e36351e..20b44ef 100644
--- a/src/Akka.NodeTestRunner/Program.cs
+++ b/src/Akka.MultiNode.NodeRunner/Program.cs
@@ -10,20 +10,20 @@
using System.Linq;
using System.Net;
using System.Reflection;
-using System.Text;
using System.Threading;
-using System.Threading.Tasks;
using Akka.Actor;
using Akka.IO;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Environment;
+using Akka.MultiNode.Shared.Sinks;
using Akka.Remote.TestKit;
using Xunit;
+
#if CORECLR
using System.Runtime.Loader;
using Microsoft.Extensions.DependencyModel;
#endif
-namespace Akka.NodeTestRunner
+namespace Akka.MultiNode.NodeRunner
{
class Program
{
@@ -50,16 +50,26 @@ static int Main(string[] args)
var system = ActorSystem.Create("NoteTestRunner-" + nodeIndex);
var tcpClient = _logger = system.ActorOf();
system.Tcp().Tell(new Tcp.Connect(listenEndpoint), tcpClient);
+
+ MultiNodeEnvironment.Initialize();
#if CORECLR
// In NetCore, if the assembly file hasn't been touched,
// XunitFrontController would fail loading external assemblies and its dependencies.
AssemblyLoadContext.Default.Resolving += (assemblyLoadContext, assemblyName) => DefaultOnResolving(assemblyLoadContext, assemblyName, assemblyFileName);
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyFileName);
- DependencyContext.Load(assembly)
+ var dependencyContext = DependencyContext.Load(assembly);
+ if (dependencyContext == null)
+ {
+ Console.WriteLine($"Failed to load assembly under .NET Core from {assemblyFileName}. " +
+ $"Possible reason is that assembly is compiled under .NET Full Framework.");
+ Environment.Exit(1);
+ return 1;
+ }
+
+ dependencyContext
.CompileLibraries
- .Where(dep => dep.Name.ToLower()
- .Contains(assembly.FullName.Split(new[] { ',' })[0].ToLower()))
+ .Where(dep => dep.Name.ToLower().Contains(assembly.FullName.Split(new[] {','})[0].ToLower()))
.Select(dependency => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(dependency.Name)));
#endif
@@ -72,7 +82,7 @@ static int Main(string[] args)
* the Discovery class to actually not find any individual specs to run
*/
var assemblyName = Path.GetFileName(assemblyFileName);
- Console.WriteLine("Running specs for {0} [{1}]", assemblyName, assemblyFileName);
+ Console.WriteLine("Running specs for {0} [{1}] ", assemblyName, assemblyFileName);
using (var discovery = new Discovery(assemblyName, typeName))
{
using (var sink = new Sink(nodeIndex, nodeRole, tcpClient))
@@ -139,8 +149,9 @@ static int Main(string[] args)
FlushLogMessages();
system.Terminate().Wait();
- Environment.Exit(sink.Passed && !timedOut ? 0 : 1);
- return sink.Passed ? 0 : 1;
+ var retCode = sink.Passed && !timedOut ? 0 : 1;
+ Environment.Exit(retCode);
+ return retCode;
}
}
}
diff --git a/src/Akka.NodeTestRunner/Properties/AssemblyInfo.cs b/src/Akka.MultiNode.NodeRunner/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Akka.NodeTestRunner/Properties/AssemblyInfo.cs
rename to src/Akka.MultiNode.NodeRunner/Properties/AssemblyInfo.cs
diff --git a/src/Akka.NodeTestRunner/Sink.cs b/src/Akka.MultiNode.NodeRunner/Sink.cs
similarity index 96%
rename from src/Akka.NodeTestRunner/Sink.cs
rename to src/Akka.MultiNode.NodeRunner/Sink.cs
index 8e4cb04..64025bc 100644
--- a/src/Akka.NodeTestRunner/Sink.cs
+++ b/src/Akka.MultiNode.NodeRunner/Sink.cs
@@ -6,16 +6,14 @@
//-----------------------------------------------------------------------
using System;
-using System.Collections.Generic;
-using System.Text;
using System.Threading;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
using Xunit;
using Xunit.Abstractions;
using IMessageSink = Xunit.Abstractions.IMessageSink;
-namespace Akka.NodeTestRunner
+namespace Akka.MultiNode.NodeRunner
{
#if CORECLR
class Sink : IMessageSink, IDisposable
@@ -46,6 +44,7 @@ public bool OnMessage(IMessageSinkMessage message)
_logger.Tell(resultMessage.Output);
Console.WriteLine(resultMessage.Output);
}
+
var testPassed = message as ITestPassed;
if (testPassed != null)
{
diff --git a/src/Akka.MultiNode.SampleMultiNodeTests/Akka.MultiNode.SampleMultiNodeTests.csproj b/src/Akka.MultiNode.SampleMultiNodeTests/Akka.MultiNode.SampleMultiNodeTests.csproj
new file mode 100644
index 0000000..c47f264
--- /dev/null
+++ b/src/Akka.MultiNode.SampleMultiNodeTests/Akka.MultiNode.SampleMultiNodeTests.csproj
@@ -0,0 +1,36 @@
+
+
+
+
+ $(NetFrameworkTestVersion);$(NetCoreTestVersion)
+ Akka.MultiNode.TestAdapter.SampleTests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);RELEASE
+
+
+
diff --git a/src/Akka.MultiNode.SampleMultiNodeTests/IgnoredXunitTest.cs b/src/Akka.MultiNode.SampleMultiNodeTests/IgnoredXunitTest.cs
new file mode 100644
index 0000000..90b6fe1
--- /dev/null
+++ b/src/Akka.MultiNode.SampleMultiNodeTests/IgnoredXunitTest.cs
@@ -0,0 +1,14 @@
+using System;
+using Xunit;
+
+namespace Akka.MultiNode.TestAdapter.SampleTests
+{
+ public class IgnoredXunitTest
+ {
+ [Fact(Skip = "This test should be ignored by MNTR")]
+ public void Ignored_test()
+ {
+ throw new Exception("This test should be ignored by MNTR");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.SampleMultiNodeTests/SampleMultiNodeSpec.cs b/src/Akka.MultiNode.SampleMultiNodeTests/SampleMultiNodeSpec.cs
new file mode 100644
index 0000000..01bc929
--- /dev/null
+++ b/src/Akka.MultiNode.SampleMultiNodeTests/SampleMultiNodeSpec.cs
@@ -0,0 +1,50 @@
+using Akka.Cluster.TestKit;
+using Akka.MultiNode.NodeRunner;
+using Akka.MultiNode.Shared.Environment;
+using Akka.MultiNode.TestRunner.Shared;
+using Akka.Remote.TestKit;
+
+namespace Akka.MultiNode.TestAdapter.SampleTests
+{
+ public class SampleMultiNodeSpecConfig : MultiNodeConfig
+ {
+ public RoleName First { get; }
+ public RoleName Second { get; }
+
+ public SampleMultiNodeSpecConfig()
+ {
+ First = Role("first");
+ Second = Role("second");
+
+ CommonConfig = DebugConfig(true)
+ .WithFallback(MultiNodeClusterSpec.ClusterConfig());
+ }
+ }
+
+ public class SampleMultiNodeSpec : MultiNodeClusterSpec
+ {
+ private readonly SampleMultiNodeSpecConfig _config;
+
+ public SampleMultiNodeSpec() : this(new SampleMultiNodeSpecConfig())
+ {
+ }
+
+ private SampleMultiNodeSpec(SampleMultiNodeSpecConfig config) : base(config, typeof(SampleMultiNodeSpec))
+ {
+ _config = config;
+ }
+
+ // [MultiNodeFact]
+ [CustomMultiNodeFact]
+ public void Should_start_and_join_cluster()
+ {
+ RunOn(StartClusterNode, _config.First);
+
+ EnterBarrier("first-started");
+
+ RunOn(() => Cluster.Join(GetAddress(_config.First)), _config.Second);
+
+ EnterBarrier("after");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.SampleMultiNodeTests/SampleTestsMetadata.cs b/src/Akka.MultiNode.SampleMultiNodeTests/SampleTestsMetadata.cs
new file mode 100644
index 0000000..2f7a6c9
--- /dev/null
+++ b/src/Akka.MultiNode.SampleMultiNodeTests/SampleTestsMetadata.cs
@@ -0,0 +1,20 @@
+using System.IO;
+using System.Reflection;
+
+namespace Akka.MultiNode.TestAdapter.SampleTests
+{
+ ///
+ /// SampleTestsMetadata
+ ///
+ public static class SampleTestsMetadata
+ {
+ ///
+ /// Sample tests assembly path
+ ///
+ public static string AssemblyPath => typeof(SampleMultiNodeSpec).Assembly.Location;
+ ///
+ /// Gets assembly file name
+ ///
+ public static string AssemblyFileName => typeof(SampleMultiNodeSpec).Assembly.GetName().Name + ".dll";
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/Akka.MultiNodeTestRunner.Shared.Tests.csproj b/src/Akka.MultiNode.Shared.Tests/Akka.MultiNode.Shared.Tests.csproj
similarity index 68%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/Akka.MultiNodeTestRunner.Shared.Tests.csproj
rename to src/Akka.MultiNode.Shared.Tests/Akka.MultiNode.Shared.Tests.csproj
index f1df1de..92b3d2b 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/Akka.MultiNodeTestRunner.Shared.Tests.csproj
+++ b/src/Akka.MultiNode.Shared.Tests/Akka.MultiNode.Shared.Tests.csproj
@@ -2,23 +2,25 @@
- Akka.MultiNodeTestRunner.Shared.Tests
+ Akka.MultiNode.Shared.Tests
$(NetFrameworkTestVersion);$(NetCoreTestVersion)
false
+ Akka.MultiNode.Shared.Tests
-
-
+
+
+
-
+
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoveryCases.cs b/src/Akka.MultiNode.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoveryCases.cs
similarity index 84%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoveryCases.cs
rename to src/Akka.MultiNode.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoveryCases.cs
index 5616f32..2ebe204 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoveryCases.cs
+++ b/src/Akka.MultiNode.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoveryCases.cs
@@ -7,7 +7,7 @@
using Akka.Remote.TestKit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests.MultiNodeTestRunnerDiscovery
+namespace Akka.MultiNode.Shared.Tests.MultiNodeTestRunnerDiscovery
{
public class DiscoveryCases
{
@@ -43,9 +43,9 @@ public DeeplyInheritedConfig()
}
}
- public abstract class DeeplyInheritedBaseSpec
+ public abstract class DeeplyInheritedBaseSpec : MultiNodeSpec
{
- public DeeplyInheritedBaseSpec(DeeplyInheritedConfig config)
+ public DeeplyInheritedBaseSpec(DeeplyInheritedConfig config) : base(config, typeof(DeeplyInheritedBaseSpec))
{
}
@@ -53,6 +53,9 @@ public DeeplyInheritedBaseSpec(DeeplyInheritedConfig config)
public void Dummy()
{
}
+
+ ///
+ protected override int InitialParticipantsValueFactory { get; }
}
public abstract class DeeplyInheritedMediumSpec : DeeplyInheritedBaseSpec
@@ -99,10 +102,10 @@ public FloodyConfig()
}
}
- public abstract class FloodyBaseSpec
+ public abstract class FloodyBaseSpec : MultiNodeSpec
{
- public FloodyBaseSpec(FloodyConfig config)
+ public FloodyBaseSpec(FloodyConfig config) : base(config, typeof(FloodyBaseSpec))
{
}
@@ -110,6 +113,9 @@ public FloodyBaseSpec(FloodyConfig config)
public void Dummy()
{
}
+
+ ///
+ protected override int InitialParticipantsValueFactory { get; }
}
public class FloodyChildSpec1 : FloodyBaseSpec
@@ -149,9 +155,9 @@ public DiverseConfig()
}
}
- public class DiverseSpec
+ public class DiverseSpec : MultiNodeSpec
{
- public DiverseSpec(DiverseConfig config)
+ public DiverseSpec(DiverseConfig config) : base(config, typeof(DiverseSpec))
{
}
@@ -159,6 +165,9 @@ public DiverseSpec(DiverseConfig config)
public void Dummy()
{
}
+
+ ///
+ protected override int InitialParticipantsValueFactory { get; }
}
}
}
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs b/src/Akka.MultiNode.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs
similarity index 96%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs
rename to src/Akka.MultiNode.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs
index 99e485e..4671508 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs
@@ -9,11 +9,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using Akka.TestKit;
-using Xunit;
+using Akka.MultiNode.TestRunner;
+using Akka.MultiNode.TestRunner.Shared;
using FluentAssertions;
+using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests.MultiNodeTestRunnerDiscovery
+namespace Akka.MultiNode.Shared.Tests.MultiNodeTestRunnerDiscovery
{
public class DiscoverySpec
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/NodeDataActorSpec.cs b/src/Akka.MultiNode.Shared.Tests/NodeDataActorSpec.cs
similarity index 96%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/NodeDataActorSpec.cs
rename to src/Akka.MultiNode.Shared.Tests/NodeDataActorSpec.cs
index e7741f4..8d45719 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/NodeDataActorSpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/NodeDataActorSpec.cs
@@ -6,12 +6,11 @@
//-----------------------------------------------------------------------
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.TestKit;
+using Akka.MultiNode.Shared.Reporting;
+using Akka.MultiNode.Shared.Sinks;
using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests
+namespace Akka.MultiNode.Shared.Tests
{
public class NodeDataActorSpec : TestKit.Xunit2.TestKit
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/NodeMessageHelpers.cs b/src/Akka.MultiNode.Shared.Tests/NodeMessageHelpers.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/NodeMessageHelpers.cs
rename to src/Akka.MultiNode.Shared.Tests/NodeMessageHelpers.cs
index 620f65e..35d6052 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/NodeMessageHelpers.cs
+++ b/src/Akka.MultiNode.Shared.Tests/NodeMessageHelpers.cs
@@ -9,10 +9,10 @@
using System.Collections.Generic;
using System.Linq;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.Util;
+using Akka.MultiNode.Shared.Reporting;
+using Akka.MultiNode.Shared.Tests.Utils;
-namespace Akka.MultiNodeTestRunner.Shared.Tests
+namespace Akka.MultiNode.Shared.Tests
{
///
/// Helper class for creating
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/ParsingSpec.cs b/src/Akka.MultiNode.Shared.Tests/ParsingSpec.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/ParsingSpec.cs
rename to src/Akka.MultiNode.Shared.Tests/ParsingSpec.cs
index 4f52873..2fd4b35 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/ParsingSpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/ParsingSpec.cs
@@ -9,12 +9,11 @@
using Akka.Actor;
using Akka.Configuration;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.TestKit;
+using Akka.MultiNode.Shared.Sinks;
using FluentAssertions;
using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests
+namespace Akka.MultiNode.Shared.Tests
{
///
/// Used to test the 's ability to parse
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/Persistence/JsonPersistentTestRunStoreSpec.cs b/src/Akka.MultiNode.Shared.Tests/Persistence/JsonPersistentTestRunStoreSpec.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/Persistence/JsonPersistentTestRunStoreSpec.cs
rename to src/Akka.MultiNode.Shared.Tests/Persistence/JsonPersistentTestRunStoreSpec.cs
index 4761df2..fbe101a 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/Persistence/JsonPersistentTestRunStoreSpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/Persistence/JsonPersistentTestRunStoreSpec.cs
@@ -8,14 +8,13 @@
using System.IO;
using System.Linq;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Persistence;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.TestKit;
+using Akka.MultiNode.Shared.Persistence;
+using Akka.MultiNode.Shared.Reporting;
+using Akka.MultiNode.Shared.Sinks;
using FluentAssertions;
using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests.Persistence
+namespace Akka.MultiNode.Shared.Tests.Persistence
{
public class JsonPersistentTestRunStoreSpec : TestKit.Xunit2.TestKit
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/Properties/AssemblyInfo.cs b/src/Akka.MultiNode.Shared.Tests/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/Properties/AssemblyInfo.cs
rename to src/Akka.MultiNode.Shared.Tests/Properties/AssemblyInfo.cs
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/ResultSummaryTests.cs b/src/Akka.MultiNode.Shared.Tests/ResultSummaryTests.cs
similarity index 96%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/ResultSummaryTests.cs
rename to src/Akka.MultiNode.Shared.Tests/ResultSummaryTests.cs
index d55aa44..84cf311 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/ResultSummaryTests.cs
+++ b/src/Akka.MultiNode.Shared.Tests/ResultSummaryTests.cs
@@ -4,12 +4,13 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Collections.Generic;
-using Akka.MultiNodeTestRunner.TrxReporter.Models;
+using Akka.MultiNode.Shared.TrxReporter.Models;
using FluentAssertions;
using Xunit;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Tests
+namespace Akka.MultiNode.Shared.Tests
{
public class ResultSummaryTests
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/SpecRunCoordinatorSpec.cs b/src/Akka.MultiNode.Shared.Tests/SpecRunCoordinatorSpec.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/SpecRunCoordinatorSpec.cs
rename to src/Akka.MultiNode.Shared.Tests/SpecRunCoordinatorSpec.cs
index 2cb43d1..c00a42c 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/SpecRunCoordinatorSpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/SpecRunCoordinatorSpec.cs
@@ -8,12 +8,11 @@
using System.Collections.Generic;
using System.Linq;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.TestKit;
+using Akka.MultiNode.Shared.Reporting;
+using Akka.MultiNode.Shared.Sinks;
using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests
+namespace Akka.MultiNode.Shared.Tests
{
public class SpecRunCoordinatorSpec : TestKit.Xunit2.TestKit
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/TestRunCoordinatorSpec.cs b/src/Akka.MultiNode.Shared.Tests/TestRunCoordinatorSpec.cs
similarity index 95%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/TestRunCoordinatorSpec.cs
rename to src/Akka.MultiNode.Shared.Tests/TestRunCoordinatorSpec.cs
index 228a097..37303ff 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/TestRunCoordinatorSpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/TestRunCoordinatorSpec.cs
@@ -5,16 +5,14 @@
//
//-----------------------------------------------------------------------
-using System;
using System.Collections.Generic;
using System.Linq;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.TestKit;
+using Akka.MultiNode.Shared.Reporting;
+using Akka.MultiNode.Shared.Sinks;
using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests
+namespace Akka.MultiNode.Shared.Tests
{
public class TestRunCoordinatorSpec : TestKit.Xunit2.TestKit
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared.Tests/TestRunShutdownSpec.cs b/src/Akka.MultiNode.Shared.Tests/TestRunShutdownSpec.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared.Tests/TestRunShutdownSpec.cs
rename to src/Akka.MultiNode.Shared.Tests/TestRunShutdownSpec.cs
index a564321..02bf50f 100644
--- a/src/Akka.MultiNodeTestRunner.Shared.Tests/TestRunShutdownSpec.cs
+++ b/src/Akka.MultiNode.Shared.Tests/TestRunShutdownSpec.cs
@@ -7,13 +7,11 @@
using System;
using System.Linq;
-using System.Threading.Tasks;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.TestKit;
+using Akka.MultiNode.Shared.Sinks;
using Xunit;
-namespace Akka.MultiNodeTestRunner.Shared.Tests
+namespace Akka.MultiNode.Shared.Tests
{
///
/// Used to validate that we can get final reporting on shutdown
diff --git a/src/Akka.MultiNode.Shared.Tests/Utils/ContinuousEnumerator.cs b/src/Akka.MultiNode.Shared.Tests/Utils/ContinuousEnumerator.cs
new file mode 100644
index 0000000..801c181
--- /dev/null
+++ b/src/Akka.MultiNode.Shared.Tests/Utils/ContinuousEnumerator.cs
@@ -0,0 +1,86 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (C) 2009-2019 Lightbend Inc.
+// Copyright (C) 2013-2019 .NET Foundation
+//
+//-----------------------------------------------------------------------
+
+ using System.Collections;
+ using System.Collections.Generic;
+
+ namespace Akka.MultiNode.Shared.Tests.Utils
+{
+ ///
+ /// Implements a circular around an existing .
+ ///
+ /// This allows for continuous read-only iteration over a set.
+ ///
+ /// The type of objects to enumerate
+ ///
+ /// Duplicates Akka.Utils.ContinuousEnumerator class from Akka.NET https://github.com/akkadotnet/akka.net
+ ///
+ internal sealed class ContinuousEnumerator : IEnumerator
+ {
+ private readonly IEnumerator _internalEnumerator;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The raw iterator from some object
+ public ContinuousEnumerator(IEnumerator internalEnumerator)
+ {
+ _internalEnumerator = internalEnumerator;
+ }
+
+ ///
+ public void Dispose()
+ {
+ _internalEnumerator.Dispose();
+ }
+
+ ///
+ public bool MoveNext()
+ {
+ if (!_internalEnumerator.MoveNext())
+ {
+ _internalEnumerator.Reset();
+ return _internalEnumerator.MoveNext();
+ }
+ return true;
+ }
+
+ ///
+ public void Reset()
+ {
+ _internalEnumerator.Reset();
+ }
+
+ ///
+ public T Current { get { return _internalEnumerator.Current; } }
+
+ object IEnumerator.Current
+ {
+ get { return Current; }
+ }
+ }
+
+ ///
+ /// Extension method class for adding support to any
+ /// instance within Akka.NET
+ ///
+ internal static class ContinuousEnumeratorExtensions
+ {
+ ///
+ /// Provides a instance for .
+ ///
+ /// Internally, it just wraps 's internal iterator with circular iteration behavior.
+ ///
+ /// TBD
+ /// TBD
+ public static ContinuousEnumerator GetContinuousEnumerator(this IEnumerable collection)
+ {
+ return new ContinuousEnumerator(collection.GetEnumerator());
+ }
+ }
+}
+
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Akka.MultiNodeTestRunner.Shared.csproj b/src/Akka.MultiNode.Shared/Akka.MultiNode.Shared.csproj
similarity index 85%
rename from src/Akka.MultiNodeTestRunner.Shared/Akka.MultiNodeTestRunner.Shared.csproj
rename to src/Akka.MultiNode.Shared/Akka.MultiNode.Shared.csproj
index 506c80b..e0db28c 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Akka.MultiNodeTestRunner.Shared.csproj
+++ b/src/Akka.MultiNode.Shared/Akka.MultiNode.Shared.csproj
@@ -1,13 +1,15 @@
- Akka.MultiNodeTestRunner.Shared
- $(NetStandardLibVersion)
+ Akka.MultiNode.Shared
+ $(NetStandardLibVersion)
false
false
+ Akka.MultiNode.Shared
+
diff --git a/src/Akka.MultiNodeTestRunner.Shared/CompilerErrorCollection.cs b/src/Akka.MultiNode.Shared/CompilerErrorCollection.cs
similarity index 90%
rename from src/Akka.MultiNodeTestRunner.Shared/CompilerErrorCollection.cs
rename to src/Akka.MultiNode.Shared/CompilerErrorCollection.cs
index 5f87322..d40c950 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/CompilerErrorCollection.cs
+++ b/src/Akka.MultiNode.Shared/CompilerErrorCollection.cs
@@ -5,12 +5,10 @@
//
//-----------------------------------------------------------------------
-using System;
using System.Collections.Generic;
-using System.Reflection;
#if CORECLR
-namespace System.CodeDom.Compiler
+namespace Akka.MultiNode.Shared
{
public class CompilerErrorCollection : List
{
diff --git a/src/Akka.MultiNode.Shared/Environment/CustomMultiNodeFactAttribute.cs b/src/Akka.MultiNode.Shared/Environment/CustomMultiNodeFactAttribute.cs
new file mode 100644
index 0000000..b0abe31
--- /dev/null
+++ b/src/Akka.MultiNode.Shared/Environment/CustomMultiNodeFactAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+using Xunit;
+
+namespace Akka.MultiNode.Shared.Environment
+{
+ // TODO: Remove this after Akka.Cluster.TestKit.MultiNodeFactAttribute will be updated (https://github.com/akkadotnet/akka.net/issues/4188)
+ public class CustomMultiNodeFactAttribute : FactAttribute
+ {
+ ///
+ /// Set by MultiNodeTestRunner when running multi-node tests
+ ///
+ public const string MultiNodeTestEnvironmentName = "__AKKA_MULTI_NODE_ENVIRONMENT";
+
+ private static readonly Lazy ExecutedByMultiNodeRunner = new Lazy(() =>
+ {
+ return System.Environment.GetEnvironmentVariable(MultiNodeTestEnvironmentName) != null;
+ });
+
+ public override string Skip
+ {
+ get => !ExecutedByMultiNodeRunner.Value ? "Must be executed by multi-node test runner" : base.Skip;
+ set => base.Skip = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.Shared/Environment/MultiNodeEnvironment.cs b/src/Akka.MultiNode.Shared/Environment/MultiNodeEnvironment.cs
new file mode 100644
index 0000000..1843e40
--- /dev/null
+++ b/src/Akka.MultiNode.Shared/Environment/MultiNodeEnvironment.cs
@@ -0,0 +1,16 @@
+namespace Akka.MultiNode.Shared.Environment
+{
+ ///
+ /// MultiNodeEnvironment
+ ///
+ public static class MultiNodeEnvironment
+ {
+ ///
+ /// Initializes multi-node test environment. Used by and NodeRunner.
+ ///
+ public static void Initialize()
+ {
+ System.Environment.SetEnvironmentVariable(CustomMultiNodeFactAttribute.MultiNodeTestEnvironmentName, "1");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNodeTestRunner.Shared/ExitCodeContainer.cs b/src/Akka.MultiNode.Shared/ExitCodeContainer.cs
similarity index 88%
rename from src/Akka.MultiNodeTestRunner.Shared/ExitCodeContainer.cs
rename to src/Akka.MultiNode.Shared/ExitCodeContainer.cs
index eb253f2..8b5606b 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/ExitCodeContainer.cs
+++ b/src/Akka.MultiNode.Shared/ExitCodeContainer.cs
@@ -5,9 +5,9 @@
//
//-----------------------------------------------------------------------
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
-namespace Akka.MultiNodeTestRunner.Shared
+namespace Akka.MultiNode.Shared
{
///
/// Global state for hanging onto the exit code used by the process.
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Extensions/DateTimeExtension.cs b/src/Akka.MultiNode.Shared/Extensions/DateTimeExtension.cs
similarity index 77%
rename from src/Akka.MultiNodeTestRunner.Shared/Extensions/DateTimeExtension.cs
rename to src/Akka.MultiNode.Shared/Extensions/DateTimeExtension.cs
index aa0bcfe..04a4dcc 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Extensions/DateTimeExtension.cs
+++ b/src/Akka.MultiNode.Shared/Extensions/DateTimeExtension.cs
@@ -6,14 +6,9 @@
//-----------------------------------------------------------------------
using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
#if CORECLR
-namespace Akka.MultiNodeTestRunner.Shared.Extensions
+namespace Akka.MultiNode.Shared.Extensions
{
internal static class DateTimeExtension
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Extensions/TypeExtension.cs b/src/Akka.MultiNode.Shared/Extensions/TypeExtension.cs
similarity index 81%
rename from src/Akka.MultiNodeTestRunner.Shared/Extensions/TypeExtension.cs
rename to src/Akka.MultiNode.Shared/Extensions/TypeExtension.cs
index b6c7a68..b6593c7 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Extensions/TypeExtension.cs
+++ b/src/Akka.MultiNode.Shared/Extensions/TypeExtension.cs
@@ -6,14 +6,10 @@
//-----------------------------------------------------------------------
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
#if CORECLR
-namespace Akka.MultiNodeTestRunner.Shared.Extensions
+namespace Akka.MultiNode.Shared.Extensions
{
internal static class TypeExtension
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/NodeTest.cs b/src/Akka.MultiNode.Shared/NodeTest.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared/NodeTest.cs
rename to src/Akka.MultiNode.Shared/NodeTest.cs
index 7a720a1..f98dba9 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/NodeTest.cs
+++ b/src/Akka.MultiNode.Shared/NodeTest.cs
@@ -5,7 +5,7 @@
//
//-----------------------------------------------------------------------
-namespace Akka.MultiNodeTestRunner.Shared
+namespace Akka.MultiNode.Shared
{
public class NodeTest
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/EnumerableExtensions.cs b/src/Akka.MultiNode.Shared/Persistence/EnumerableExtensions.cs
similarity index 93%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/EnumerableExtensions.cs
rename to src/Akka.MultiNode.Shared/Persistence/EnumerableExtensions.cs
index 60c1682..cd91e7f 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/EnumerableExtensions.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/EnumerableExtensions.cs
@@ -7,7 +7,7 @@
using System.Collections.Generic;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
public static class EnumerableExtensions
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/FileNameGenerator.cs b/src/Akka.MultiNode.Shared/Persistence/FileNameGenerator.cs
similarity index 96%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/FileNameGenerator.cs
rename to src/Akka.MultiNode.Shared/Persistence/FileNameGenerator.cs
index 850a56c..81dca69 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/FileNameGenerator.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/FileNameGenerator.cs
@@ -8,7 +8,7 @@
using System;
using System.IO;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
public class FileNameGenerator
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/IPersistentTestRunStore.cs b/src/Akka.MultiNode.Shared/Persistence/IPersistentTestRunStore.cs
similarity index 86%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/IPersistentTestRunStore.cs
rename to src/Akka.MultiNode.Shared/Persistence/IPersistentTestRunStore.cs
index ed9f388..68eebad 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/IPersistentTestRunStore.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/IPersistentTestRunStore.cs
@@ -5,9 +5,9 @@
//
//-----------------------------------------------------------------------
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
///
/// Persistent store for saving instances
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/IRetrievableTestRunStore.cs b/src/Akka.MultiNode.Shared/Persistence/IRetrievableTestRunStore.cs
similarity index 87%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/IRetrievableTestRunStore.cs
rename to src/Akka.MultiNode.Shared/Persistence/IRetrievableTestRunStore.cs
index b5584f9..2ccc446 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/IRetrievableTestRunStore.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/IRetrievableTestRunStore.cs
@@ -5,9 +5,9 @@
//
//-----------------------------------------------------------------------
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
///
/// Persistent store for retrieving instances
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/JsonPersistentTestRunStore.cs b/src/Akka.MultiNode.Shared/Persistence/JsonPersistentTestRunStore.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/JsonPersistentTestRunStore.cs
rename to src/Akka.MultiNode.Shared/Persistence/JsonPersistentTestRunStore.cs
index a4bb992..e8e841b 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/JsonPersistentTestRunStore.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/JsonPersistentTestRunStore.cs
@@ -9,11 +9,11 @@
using System.IO;
using System.Reflection;
using System.Text;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Reporting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
///
/// JavaScript Object Notation (JSON) implementation of the
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/TimelineItem.cs b/src/Akka.MultiNode.Shared/Persistence/TimelineItem.cs
similarity index 95%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/TimelineItem.cs
rename to src/Akka.MultiNode.Shared/Persistence/TimelineItem.cs
index 1e1b147..6816a87 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/TimelineItem.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/TimelineItem.cs
@@ -7,7 +7,7 @@
using System;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
public class TimelineItem
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/TimelineItemFactory.cs b/src/Akka.MultiNode.Shared/Persistence/TimelineItemFactory.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/TimelineItemFactory.cs
rename to src/Akka.MultiNode.Shared/Persistence/TimelineItemFactory.cs
index 5a0dba7..fc66d8a 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/TimelineItemFactory.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/TimelineItemFactory.cs
@@ -7,7 +7,7 @@
using System;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
public static class TimelineItemFactory
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerPersistentTestRunStore.cs b/src/Akka.MultiNode.Shared/Persistence/VisualizerPersistentTestRunStore.cs
similarity index 90%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerPersistentTestRunStore.cs
rename to src/Akka.MultiNode.Shared/Persistence/VisualizerPersistentTestRunStore.cs
index e4f7d37..65f3a52 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerPersistentTestRunStore.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/VisualizerPersistentTestRunStore.cs
@@ -6,10 +6,9 @@
//-----------------------------------------------------------------------
using System.IO;
+using Akka.MultiNode.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
///
/// Stores test run as a html page.
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.Tree.cs b/src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.Tree.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.Tree.cs
rename to src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.Tree.cs
index 95c807f..e98b562 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.Tree.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.Tree.cs
@@ -8,9 +8,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
partial class VisualizerRuntimeTemplate
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.cs b/src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.cs
similarity index 99%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.cs
rename to src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.cs
index 9d24ad3..bc59aef 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.cs
+++ b/src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.cs
@@ -16,10 +16,10 @@
// ------------------------------------------------------------------------------
#if CORECLR
-using Akka.MultiNodeTestRunner.Shared.Extensions;
+using Akka.MultiNode.Shared.Extensions;
#endif
-namespace Akka.MultiNodeTestRunner.Shared.Persistence
+namespace Akka.MultiNode.Shared.Persistence
{
using System.Linq;
using System.Text;
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.tt b/src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.tt
similarity index 100%
rename from src/Akka.MultiNodeTestRunner.Shared/Persistence/VisualizerRuntimeTemplate.tt
rename to src/Akka.MultiNode.Shared/Persistence/VisualizerRuntimeTemplate.tt
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Properties/AssemblyInfo.cs b/src/Akka.MultiNode.Shared/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Akka.MultiNodeTestRunner.Shared/Properties/AssemblyInfo.cs
rename to src/Akka.MultiNode.Shared/Properties/AssemblyInfo.cs
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Reporting/MultiNodeMessage.cs b/src/Akka.MultiNode.Shared/Reporting/MultiNodeMessage.cs
similarity index 99%
rename from src/Akka.MultiNodeTestRunner.Shared/Reporting/MultiNodeMessage.cs
rename to src/Akka.MultiNode.Shared/Reporting/MultiNodeMessage.cs
index cce8c2a..99df610 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Reporting/MultiNodeMessage.cs
+++ b/src/Akka.MultiNode.Shared/Reporting/MultiNodeMessage.cs
@@ -8,7 +8,7 @@
using System;
using Akka.Event;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Reporting
{
///
/// Message from an individual node
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Reporting/NodeDataActor.cs b/src/Akka.MultiNode.Shared/Reporting/NodeDataActor.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared/Reporting/NodeDataActor.cs
rename to src/Akka.MultiNode.Shared/Reporting/NodeDataActor.cs
index 682bf45..e5b8dd7 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Reporting/NodeDataActor.cs
+++ b/src/Akka.MultiNode.Shared/Reporting/NodeDataActor.cs
@@ -7,9 +7,9 @@
using System;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Reporting
{
///
/// Actor responsible for processing test messages for an individual node within a multi-node test
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Reporting/SpecRunCoordinator.cs b/src/Akka.MultiNode.Shared/Reporting/SpecRunCoordinator.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/Reporting/SpecRunCoordinator.cs
rename to src/Akka.MultiNode.Shared/Reporting/SpecRunCoordinator.cs
index 488ad11..18c9d73 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Reporting/SpecRunCoordinator.cs
+++ b/src/Akka.MultiNode.Shared/Reporting/SpecRunCoordinator.cs
@@ -9,9 +9,9 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Reporting
{
///
/// Actor responsible for organizing the results of an individual spec
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Reporting/TeamCityLoggerActor.cs b/src/Akka.MultiNode.Shared/Reporting/TeamCityLoggerActor.cs
similarity index 84%
rename from src/Akka.MultiNodeTestRunner.Shared/Reporting/TeamCityLoggerActor.cs
rename to src/Akka.MultiNode.Shared/Reporting/TeamCityLoggerActor.cs
index c149994..ff21af1 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Reporting/TeamCityLoggerActor.cs
+++ b/src/Akka.MultiNode.Shared/Reporting/TeamCityLoggerActor.cs
@@ -6,13 +6,9 @@
//-----------------------------------------------------------------------
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Akka.Actor;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Reporting
{
public class TeamCityLoggerActor : ReceiveActor
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Reporting/TestRunCoordinator.cs b/src/Akka.MultiNode.Shared/Reporting/TestRunCoordinator.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared/Reporting/TestRunCoordinator.cs
rename to src/Akka.MultiNode.Shared/Reporting/TestRunCoordinator.cs
index 7005053..ca79879 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Reporting/TestRunCoordinator.cs
+++ b/src/Akka.MultiNode.Shared/Reporting/TestRunCoordinator.cs
@@ -10,9 +10,9 @@
using System.Linq;
using System.Threading.Tasks;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Reporting
{
///
/// Actor responsible for organizing all of the data for each test run
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Reporting/TestRunTree.cs b/src/Akka.MultiNode.Shared/Reporting/TestRunTree.cs
similarity index 99%
rename from src/Akka.MultiNodeTestRunner.Shared/Reporting/TestRunTree.cs
rename to src/Akka.MultiNode.Shared/Reporting/TestRunTree.cs
index 45abfda..067c021 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Reporting/TestRunTree.cs
+++ b/src/Akka.MultiNode.Shared/Reporting/TestRunTree.cs
@@ -10,7 +10,7 @@
using System.Linq;
using Newtonsoft.Json;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Reporting
{
///
/// The top of the tree - represents an entire test run.
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/ConsoleMessageSinkActor.cs b/src/Akka.MultiNode.Shared/Sinks/ConsoleMessageSinkActor.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/ConsoleMessageSinkActor.cs
rename to src/Akka.MultiNode.Shared/Sinks/ConsoleMessageSinkActor.cs
index a4b73cb..75ce364 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/ConsoleMessageSinkActor.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/ConsoleMessageSinkActor.cs
@@ -9,12 +9,11 @@
using System.Linq;
using Akka.Actor;
using Akka.Event;
+using Akka.MultiNode.Shared.Reporting;
#if CORECLR
-using Akka.MultiNodeTestRunner.Shared.Extensions;
#endif
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// implementation that logs all of its output directly to the .
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/FileSystemAppenderActor.cs b/src/Akka.MultiNode.Shared/Sinks/FileSystemAppenderActor.cs
similarity index 87%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/FileSystemAppenderActor.cs
rename to src/Akka.MultiNode.Shared/Sinks/FileSystemAppenderActor.cs
index 0f553a1..c162f01 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/FileSystemAppenderActor.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/FileSystemAppenderActor.cs
@@ -9,7 +9,7 @@
using System.IO;
using Akka.Actor;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// Actor that just writes dumb messages to the file system - used for capturing
@@ -25,7 +25,7 @@ public FileSystemAppenderActor(string fullFilePath)
ReceiveAny(o =>
{
- File.AppendAllText(_fullFilePath, o.ToString() + Environment.NewLine);
+ File.AppendAllText(_fullFilePath, o + System.Environment.NewLine);
});
}
}
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/FileSystemMessageSinkActor.cs b/src/Akka.MultiNode.Shared/Sinks/FileSystemMessageSinkActor.cs
similarity index 86%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/FileSystemMessageSinkActor.cs
rename to src/Akka.MultiNode.Shared/Sinks/FileSystemMessageSinkActor.cs
index 16c13f8..44ac2fa 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/FileSystemMessageSinkActor.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/FileSystemMessageSinkActor.cs
@@ -8,10 +8,10 @@
using System;
using System.IO;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Persistence;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Persistence;
+using Akka.MultiNode.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// A file system implementation
@@ -64,8 +64,15 @@ protected override void AdditionalReceives()
protected override void HandleTestRunTree(TestRunTree tree)
{
+ var filePath = Path.GetFullPath(FileName);
+
+ // Create output dir if not exists
+ var dir = new DirectoryInfo(Path.GetDirectoryName(filePath));
+ if (!dir.Exists)
+ dir.Create();
+
if (_reportStatus)
- Console.WriteLine("Writing test state to: {0}", Path.GetFullPath(FileName));
+ Console.WriteLine("Writing test state to: {0}", filePath);
try
{
FileStore.SaveTestRun(FileName, tree);
@@ -73,7 +80,7 @@ protected override void HandleTestRunTree(TestRunTree tree)
catch (Exception ex) //avoid throwing exception back to parent - just continue
{
if (_reportStatus)
- Console.WriteLine("Failed to write test state to {0}. Cause: {1}", Path.GetFullPath(FileName), ex);
+ Console.WriteLine("Failed to write test state to {0}. Cause: {1}", filePath, ex);
}
if (_reportStatus)
Console.WriteLine("Finished.");
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/IMessageSink.cs b/src/Akka.MultiNode.Shared/Sinks/IMessageSink.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/IMessageSink.cs
rename to src/Akka.MultiNode.Shared/Sinks/IMessageSink.cs
index 1e4721c..56218d0 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/IMessageSink.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/IMessageSink.cs
@@ -10,9 +10,8 @@
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// Interface used to define destinations for MultiNodeTest messages
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/MessageSink.cs b/src/Akka.MultiNode.Shared/Sinks/MessageSink.cs
similarity index 99%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/MessageSink.cs
rename to src/Akka.MultiNode.Shared/Sinks/MessageSink.cs
index 228d992..89ae4cd 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/MessageSink.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/MessageSink.cs
@@ -11,9 +11,8 @@
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// Abstract base class for all implementations. Includes some methods
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/MessageSinkActor.cs b/src/Akka.MultiNode.Shared/Sinks/MessageSinkActor.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/MessageSinkActor.cs
rename to src/Akka.MultiNode.Shared/Sinks/MessageSinkActor.cs
index 5a55da0..bd78bd3 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/MessageSinkActor.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/MessageSinkActor.cs
@@ -6,9 +6,9 @@
//-----------------------------------------------------------------------
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// Actor responsible for directing the flow of all messages for each test run.
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/Messages.cs b/src/Akka.MultiNode.Shared/Sinks/Messages.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/Messages.cs
rename to src/Akka.MultiNode.Shared/Sinks/Messages.cs
index e9bcc07..1afb70b 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/Messages.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/Messages.cs
@@ -8,9 +8,8 @@
using System;
using System.Collections.Generic;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
#region Message types
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/SinkCoordinator.cs b/src/Akka.MultiNode.Shared/Sinks/SinkCoordinator.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/SinkCoordinator.cs
rename to src/Akka.MultiNode.Shared/Sinks/SinkCoordinator.cs
index 89199f0..dc87f4c 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/SinkCoordinator.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/SinkCoordinator.cs
@@ -11,9 +11,8 @@
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// Top-level actor responsible for managing all instances.
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/Spec.cs b/src/Akka.MultiNode.Shared/Sinks/Spec.cs
similarity index 91%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/Spec.cs
rename to src/Akka.MultiNode.Shared/Sinks/Spec.cs
index 8c02672..969d20b 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/Spec.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/Spec.cs
@@ -5,19 +5,16 @@
//
//-----------------------------------------------------------------------
-using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
-using System.Threading.Tasks;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// Message class used for reporting a test pass.
///
///
- /// The Akka.MultiNodeTestRunner.Shared.MessageSink depends on the format string
+ /// The Akka.MultiNode.Shared.MessageSink depends on the format string
/// that this class produces, so do not remove or refactor it.
///
///
@@ -45,7 +42,7 @@ public override string ToString()
/// Message class used for reporting a test fail.
///
///
- /// The Akka.MultiNodeTestRunner.Shared.MessageSink depends on the format string
+ /// The Akka.MultiNode.Shared.MessageSink depends on the format string
/// that this class produces, so do not remove or refactor it.
///
///
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/SpecLog.cs b/src/Akka.MultiNode.Shared/Sinks/SpecLog.cs
similarity index 95%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/SpecLog.cs
rename to src/Akka.MultiNode.Shared/Sinks/SpecLog.cs
index c825a95..9ac9eeb 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/SpecLog.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/SpecLog.cs
@@ -7,7 +7,7 @@
using System.Collections.Generic;
-namespace Akka.MultiNodeTestRunner.Shared.Reporting
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// SpecLog
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs b/src/Akka.MultiNode.Shared/Sinks/TeamCityMessageSinkActor.cs
similarity index 90%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs
rename to src/Akka.MultiNode.Shared/Sinks/TeamCityMessageSinkActor.cs
index 4a5acf9..a6823fa 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/TeamCityMessageSinkActor.cs
@@ -6,22 +6,13 @@
//-----------------------------------------------------------------------
using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Akka.Actor;
-using Akka.Event;
+using Akka.MultiNode.Shared.Reporting;
+using JetBrains.TeamCity.ServiceMessages.Write.Special;
#if CORECLR
-using Akka.MultiNodeTestRunner.Shared.Extensions;
#endif
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using JetBrains.TeamCity.ServiceMessages;
-using JetBrains.TeamCity.ServiceMessages.Write.Special;
-using JetBrains.TeamCity.ServiceMessages.Write.Special.Impl.Writer;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
public class TeamCityMessageSinkActor : TestCoordinatorEnabledMessageSink
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/TestCoordinatorEnabledMessageSink.cs b/src/Akka.MultiNode.Shared/Sinks/TestCoordinatorEnabledMessageSink.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/TestCoordinatorEnabledMessageSink.cs
rename to src/Akka.MultiNode.Shared/Sinks/TestCoordinatorEnabledMessageSink.cs
index 2bc03f1..7f91610 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/TestCoordinatorEnabledMessageSink.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/TestCoordinatorEnabledMessageSink.cs
@@ -8,9 +8,9 @@
using System;
using System.Threading.Tasks;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
+using Akka.MultiNode.Shared.Reporting;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
///
/// A implementation that is capable of using a for
diff --git a/src/Akka.MultiNodeTestRunner.Shared/Sinks/TimelineLogCollectorActor.cs b/src/Akka.MultiNode.Shared/Sinks/TimelineLogCollectorActor.cs
similarity index 98%
rename from src/Akka.MultiNodeTestRunner.Shared/Sinks/TimelineLogCollectorActor.cs
rename to src/Akka.MultiNode.Shared/Sinks/TimelineLogCollectorActor.cs
index 70555e3..e6d3961 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/Sinks/TimelineLogCollectorActor.cs
+++ b/src/Akka.MultiNode.Shared/Sinks/TimelineLogCollectorActor.cs
@@ -13,10 +13,8 @@
using System.Text.RegularExpressions;
using Akka.Actor;
using Akka.Event;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.Util.Internal;
-namespace Akka.MultiNodeTestRunner.Shared.Sinks
+namespace Akka.MultiNode.Shared.Sinks
{
public class TimelineLogCollectorActor : ReceiveActor
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ErrorInfo.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/ErrorInfo.cs
similarity index 86%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ErrorInfo.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/ErrorInfo.cs
index 0b5e456..95cbe10 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ErrorInfo.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/ErrorInfo.cs
@@ -4,10 +4,11 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class ErrorInfo : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ITestEntity.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/ITestEntity.cs
similarity index 90%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ITestEntity.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/ITestEntity.cs
index fc4a51a..ea03b07 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ITestEntity.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/ITestEntity.cs
@@ -4,9 +4,10 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Xml.Linq;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public interface ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Identifier.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/Identifier.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Identifier.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/Identifier.cs
index 9629241..1d6c982 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Identifier.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/Identifier.cs
@@ -4,9 +4,10 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public struct Identifier
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Output.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/Output.cs
similarity index 87%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Output.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/Output.cs
index 77ad4cb..848a661 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Output.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/Output.cs
@@ -4,13 +4,14 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class Output : ITestEntity
{
@@ -24,7 +25,7 @@ public XElement Serialize()
{
XElement TextElem(string element, List lines) =>
lines.Count > 0
- ? Elem(element, Text(string.Join(Environment.NewLine, lines)))
+ ? Elem(element, Text(string.Join(System.Environment.NewLine, lines)))
: null;
return Elem("Output",
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ResultSummary.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/ResultSummary.cs
similarity index 96%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ResultSummary.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/ResultSummary.cs
index 74c827d..215b24a 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/ResultSummary.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/ResultSummary.cs
@@ -4,13 +4,14 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class ResultSummary : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestEntry.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestEntry.cs
similarity index 89%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestEntry.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/TestEntry.cs
index 5385934..0995b3c 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestEntry.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestEntry.cs
@@ -4,10 +4,11 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class TestEntry : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestList.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestList.cs
similarity index 86%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestList.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/TestList.cs
index 56ee1fd..b832983 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestList.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestList.cs
@@ -4,10 +4,11 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class TestList : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestOutcome.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestOutcome.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestOutcome.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/TestOutcome.cs
index ae73b4d..7bc2a87 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestOutcome.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestOutcome.cs
@@ -5,7 +5,7 @@
//
// -----------------------------------------------------------------------
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public enum TestOutcome
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestRun.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestRun.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestRun.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/TestRun.cs
index 8f166f5..3df4a6a 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestRun.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestRun.cs
@@ -4,12 +4,13 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class TestRun : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestSettings.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestSettings.cs
similarity index 86%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestSettings.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/TestSettings.cs
index bde156b..fd43bd3 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/TestSettings.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/TestSettings.cs
@@ -4,10 +4,11 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class TestSettings : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Times.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/Times.cs
similarity index 90%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Times.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/Times.cs
index 2d99331..88980a9 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/Times.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/Times.cs
@@ -4,11 +4,12 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class Times : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/UnitTest.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/UnitTest.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/UnitTest.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/UnitTest.cs
index 5e3aa63..07c259b 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/UnitTest.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/UnitTest.cs
@@ -4,11 +4,12 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Collections.Generic;
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class UnitTest : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/UnitTestResult.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/UnitTestResult.cs
similarity index 95%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/UnitTestResult.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/UnitTestResult.cs
index 1178619..dbb7758 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/UnitTestResult.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/UnitTestResult.cs
@@ -4,12 +4,13 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using System.Collections.Generic;
using System.Xml.Linq;
-using static Akka.MultiNodeTestRunner.TrxReporter.Models.XmlHelper;
+using static Akka.MultiNode.Shared.TrxReporter.Models.XmlHelper;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
public class UnitTestResult : ITestEntity
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/XmlHelper.cs b/src/Akka.MultiNode.Shared/TrxReporter/Models/XmlHelper.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/XmlHelper.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/Models/XmlHelper.cs
index a66b2b6..7e52bd9 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/Models/XmlHelper.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/Models/XmlHelper.cs
@@ -4,11 +4,12 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
-namespace Akka.MultiNodeTestRunner.TrxReporter.Models
+namespace Akka.MultiNode.Shared.TrxReporter.Models
{
internal static class XmlHelper
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/SpecEvent.cs b/src/Akka.MultiNode.Shared/TrxReporter/SpecEvent.cs
similarity index 93%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/SpecEvent.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/SpecEvent.cs
index 8d5f833..f2a73a7 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/SpecEvent.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/SpecEvent.cs
@@ -4,9 +4,10 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
-namespace Akka.MultiNodeTestRunner.Shared.AzureDevOps
+namespace Akka.MultiNode.Shared.TrxReporter
{
public class SpecEvent
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/SpecSession.cs b/src/Akka.MultiNode.Shared/TrxReporter/SpecSession.cs
similarity index 95%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/SpecSession.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/SpecSession.cs
index 14bb574..9cc2307 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/SpecSession.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/SpecSession.cs
@@ -4,11 +4,12 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using System.Collections.Generic;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
-namespace Akka.MultiNodeTestRunner.Shared.AzureDevOps
+namespace Akka.MultiNode.Shared.TrxReporter
{
public class SpecSession
{
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/TrxMessageSink.cs b/src/Akka.MultiNode.Shared/TrxReporter/TrxMessageSink.cs
similarity index 85%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/TrxMessageSink.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/TrxMessageSink.cs
index 311ec5c..138d1c6 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/TrxMessageSink.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/TrxMessageSink.cs
@@ -4,16 +4,17 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using Akka.Actor;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
+using Akka.MultiNode.Shared.Sinks;
-namespace Akka.MultiNodeTestRunner.Shared.AzureDevOps
+namespace Akka.MultiNode.Shared.TrxReporter
{
public class TrxMessageSink : MessageSink
{
public TrxMessageSink(string suiteName)
- : base(Props.Create(() => new TrxSinkActor(suiteName, Environment.UserName, Environment.MachineName, true)))
+ : base(Props.Create(() => new TrxSinkActor(suiteName, System.Environment.UserName, System.Environment.MachineName, true)))
{
}
diff --git a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/TrxSinkActor.cs b/src/Akka.MultiNode.Shared/TrxReporter/TrxSinkActor.cs
similarity index 97%
rename from src/Akka.MultiNodeTestRunner.Shared/TrxReporter/TrxSinkActor.cs
rename to src/Akka.MultiNode.Shared/TrxReporter/TrxSinkActor.cs
index 20de3c8..77fd916 100644
--- a/src/Akka.MultiNodeTestRunner.Shared/TrxReporter/TrxSinkActor.cs
+++ b/src/Akka.MultiNode.Shared/TrxReporter/TrxSinkActor.cs
@@ -4,16 +4,17 @@
// Copyright (C) 2013-2019 .NET Foundation
//
// -----------------------------------------------------------------------
+
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.MultiNodeTestRunner.TrxReporter.Models;
+using Akka.MultiNode.Shared.Reporting;
+using Akka.MultiNode.Shared.Sinks;
+using Akka.MultiNode.Shared.TrxReporter.Models;
-namespace Akka.MultiNodeTestRunner.Shared.AzureDevOps
+namespace Akka.MultiNode.Shared.TrxReporter
{
public class TrxSinkActor : TestCoordinatorEnabledMessageSink
{
diff --git a/src/Akka.MultiNode.TestAdapter.Tests/Akka.MultiNode.TestAdapter.Tests.csproj b/src/Akka.MultiNode.TestAdapter.Tests/Akka.MultiNode.TestAdapter.Tests.csproj
new file mode 100644
index 0000000..11d3b15
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter.Tests/Akka.MultiNode.TestAdapter.Tests.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+ $(NetFrameworkTestVersion);$(NetCoreTestVersion)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Akka.MultiNode.TestAdapter.Tests/Helpers/FakeFrameworkHandler.cs b/src/Akka.MultiNode.TestAdapter.Tests/Helpers/FakeFrameworkHandler.cs
new file mode 100644
index 0000000..97da2a6
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter.Tests/Helpers/FakeFrameworkHandler.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using Akka.Util;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+namespace Akka.MultiNode.TestAdapter.Tests.Helpers
+{
+ ///
+ /// Fake to pass to method
+ ///
+ class FakeFrameworkHandler : IFrameworkHandle
+ {
+ public List<(TestMessageLevel Level, string Message)> Messages { get; } = new List<(TestMessageLevel Level, string Message)>();
+ public List TestResults { get; } = new List();
+ public List StartedTestCases { get; } = new List();
+ public List<(TestCase TestCase, Option Outcome)> FinishedTestCases { get; } = new List<(TestCase TestCase, Option Outcome)>();
+
+ ///
+ public void SendMessage(TestMessageLevel testMessageLevel, string message)
+ {
+ Messages.Add((testMessageLevel, message));
+ }
+
+ ///
+ public void RecordResult(TestResult testResult)
+ {
+ TestResults.Add(testResult);
+ }
+
+ ///
+ public void RecordStart(TestCase testCase)
+ {
+ StartedTestCases.Add(testCase);
+ }
+
+ ///
+ public void RecordEnd(TestCase testCase, TestOutcome outcome)
+ {
+ FinishedTestCases.Add((testCase, outcome));
+ }
+
+ ///
+ public void RecordAttachments(IList attachmentSets)
+ {
+ }
+
+ ///
+ public int LaunchProcessWithDebuggerAttached(string filePath, string workingDirectory, string arguments,
+ IDictionary environmentVariables)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public bool EnableShutdownAfterTestRun { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter.Tests/Helpers/FakeRunContext.cs b/src/Akka.MultiNode.TestAdapter.Tests/Helpers/FakeRunContext.cs
new file mode 100644
index 0000000..2f4c603
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter.Tests/Helpers/FakeRunContext.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+
+namespace Akka.MultiNode.TestAdapter.Tests.Helpers
+{
+ ///
+ /// Fake to pass to method
+ ///
+ class FakeRunContext : IRunContext
+ {
+ public ITestCaseFilterExpression GetTestCaseFilter(IEnumerable supportedProperties, Func propertyProvider)
+ {
+ return null;
+ }
+
+ public IRunSettings RunSettings { get; }
+ public bool KeepAlive { get; }
+ public bool InIsolation { get; }
+ public bool IsDataCollectionEnabled { get; }
+ public bool IsBeingDebugged { get; }
+ public string TestRunDirectory { get; }
+ public string SolutionDirectory { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter.Tests/Helpers/TestCollections.cs b/src/Akka.MultiNode.TestAdapter.Tests/Helpers/TestCollections.cs
new file mode 100644
index 0000000..b674159
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter.Tests/Helpers/TestCollections.cs
@@ -0,0 +1,13 @@
+namespace Akka.MultiNode.TestAdapter.Tests.Helpers
+{
+ ///
+ /// TestCollections
+ ///
+ public static class TestCollections
+ {
+ ///
+ /// Collection of tests that are running MNTR
+ ///
+ public const string MultiNode = "MNTR Collection";
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs b/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs
new file mode 100644
index 0000000..867d914
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using Akka.MultiNode.TestAdapter.SampleTests;
+using Akka.MultiNode.TestAdapter.Tests.Helpers;
+using FluentAssertions;
+using Xunit;
+
+namespace Akka.MultiNode.TestAdapter.Tests
+{
+ [Collection(TestCollections.MultiNode)]
+ public class MultiNodeTestExecutorSpec
+ {
+ [Fact]
+ public void Should_run_tests_and_report_results()
+ {
+ var sampleTestAssemblyPath = Path.GetFullPath(SampleTestsMetadata.AssemblyFileName);
+ File.Exists(sampleTestAssemblyPath).Should().BeTrue($"Assemblies with samples should exist at {sampleTestAssemblyPath}");
+
+ var executor = new MultiNodeTestExecutor();
+ var frameworkHandler = new FakeFrameworkHandler();
+ executor.RunTests(new []{ sampleTestAssemblyPath }, new FakeRunContext(), frameworkHandler);
+ frameworkHandler.TestResults.Should().NotBeEmpty();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter.Tests/TestRunnerSpec.cs b/src/Akka.MultiNode.TestAdapter.Tests/TestRunnerSpec.cs
new file mode 100644
index 0000000..46b0789
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter.Tests/TestRunnerSpec.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using Akka.MultiNode.TestAdapter.SampleTests;
+using Akka.MultiNode.TestAdapter.Tests.Helpers;
+using Akka.MultiNode.TestRunner.Shared;
+using FluentAssertions;
+using Xunit;
+
+namespace Akka.MultiNode.TestAdapter.Tests
+{
+ [Collection(TestCollections.MultiNode)]
+ public class TestRunnerSpec
+ {
+ [Fact]
+ public void Should_discover_sample_tests_and_run_them()
+ {
+ var sampleTestAssemblyPath = Path.GetFullPath(SampleTestsMetadata.AssemblyFileName);
+ File.Exists(sampleTestAssemblyPath).Should().BeTrue($"Assembly with samples should exist at {sampleTestAssemblyPath}");
+
+ var runner = new MultiNodeTestRunner();
+ var results = runner.Execute(sampleTestAssemblyPath, MultiNodeTestRunnerOptions.Default);
+ results.Should().NotBeEmpty();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj b/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj
new file mode 100644
index 0000000..a0fc24f
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj
@@ -0,0 +1,50 @@
+
+
+
+
+ Akka.MultiNode.TestAdapter
+ true
+ embedded
+ latest
+ $(NetFrameworkTestVersion);$(NetCoreTestVersion)
+ true
+ true
+ Visual Studio 2017 15.9+ Test Explorer runner for the Akka.NET MultiNode tests
+ build
+ 2.4.1
+ true
+ $(NoWarn)1701;1702;NU5105
+ Akka.MultiNode.TestAdapter
+
+
+
+ Akka.MultiNode.TestAdapter
+ $(DefineConstants);NETFRAMEWORK
+
+
+
+ Akka.MultiNode.DotNetCore.TestAdapter
+ $(DefineConstants);NETCOREAPP;CORECLR
+
+
+
+ $(DefineConstants);RELEASE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Akka.MultiNode.TestAdapter/ExecutorMetadata.cs b/src/Akka.MultiNode.TestAdapter/ExecutorMetadata.cs
new file mode 100644
index 0000000..a76848c
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter/ExecutorMetadata.cs
@@ -0,0 +1,13 @@
+namespace Akka.MultiNode.TestAdapter
+{
+ ///
+ /// ExecutorMetadata
+ ///
+ public static class ExecutorMetadata
+ {
+ ///
+ /// Executor URI used by this test adapter
+ ///
+ public const string ExecutorUri = "executor://MultiNodeExecutor";
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter/MultiNodeTestDiscoverer.cs b/src/Akka.MultiNode.TestAdapter/MultiNodeTestDiscoverer.cs
new file mode 100644
index 0000000..5251eab
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter/MultiNodeTestDiscoverer.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Akka.MultiNode.TestRunner.Shared;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+namespace Akka.MultiNode.TestAdapter
+{
+ ///
+ /// TestDiscoverer
+ ///
+ ///
+ /// See how it works here: https://github.com/Microsoft/vstest-docs/blob/master/RFCs/0004-Adapter-Extensibility.md
+ ///
+ [FileExtension(".dll")]
+ [DefaultExecutorUri(ExecutorMetadata.ExecutorUri)]
+ public class TestDiscoverer : ITestDiscoverer
+ {
+ ///
+ /// Discovers the tests available from the provided container.
+ ///
+ /// Collection of test containers.
+ /// Context in which discovery is being performed.
+ /// Logger used to log messages.
+ /// Used to send testcases and discovery related events back to Discoverer manager.
+ public void DiscoverTests(IEnumerable sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink)
+ {
+ foreach (var assemblyPath in sources)
+ {
+ var (specs, errors) = MultiNodeTestRunner.DiscoverSpecs(assemblyPath);
+
+ foreach (var discoveryErrorMessage in errors.SelectMany(e => e.Messages))
+ {
+ logger.SendMessage(TestMessageLevel.Error, discoveryErrorMessage);
+ }
+
+ foreach (var discoveredSpec in specs)
+ {
+ discoverySink.SendTestCase(new TestCase(discoveredSpec.SpecName, new Uri(ExecutorMetadata.ExecutorUri), assemblyPath));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestAdapter/MultiNodeTestExecutor.cs b/src/Akka.MultiNode.TestAdapter/MultiNodeTestExecutor.cs
new file mode 100644
index 0000000..2c4a6c6
--- /dev/null
+++ b/src/Akka.MultiNode.TestAdapter/MultiNodeTestExecutor.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using Akka.MultiNode.TestRunner.Shared;
+using Akka.Util;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+namespace Akka.MultiNode.TestAdapter
+{
+ ///
+ /// TestExecutor
+ ///
+ ///
+ /// See how it works here: https://github.com/Microsoft/vstest-docs/blob/master/RFCs/0004-Adapter-Extensibility.md
+ ///
+ [ExtensionUri(ExecutorMetadata.ExecutorUri)]
+ public class MultiNodeTestExecutor : ITestExecutor
+ {
+ ///
+ /// Cancel the execution of the tests.
+ ///
+ public void Cancel()
+ {
+ // TODO: Implement proper cancellation
+ }
+
+ ///
+ /// Runs only the tests specified by parameter 'tests'.
+ ///
+ ///
+ /// ITestExecutor.RunTests with a set of test cases gets called in mostly VS IDE scenarios("Run Selected tests" scenarios)
+ /// where a discovery operation has already been performed.
+ /// This would already have the information as to what ITestExecutor can run the test case via a URI property.
+ /// The platform would then just call into that specific executor to run the test cases.
+ ///
+ /// Tests to be run.
+ /// Context to use when executing the tests.
+ /// Handle to the framework to record results and to do framework operations.
+ public void RunTests(IEnumerable tests, IRunContext runContext, IFrameworkHandle frameworkHandle)
+ {
+ throw new NotImplementedException("Running from VS is not implemented yet");
+
+ // This is called from VS "Run Selected tests" command.
+ // Need to get assembly paths and perform specs filtering by name
+ List assemblyPaths = null;
+
+ var filteredSpecNames = tests.Select(t => t.FullyQualifiedName).ToList();
+ RunTestsWithOptions(assemblyPaths, frameworkHandle, new MultiNodeTestRunnerOptions(specNames: filteredSpecNames));
+ }
+
+ ///
+ /// Runs 'all' the tests present in the specified 'containers'.
+ ///
+ /// Path to test container files to look for tests in.
+ /// Context to use when executing the tests.
+ /// Handle to the framework to record results and to do framework operations.
+ public void RunTests(IEnumerable sources, IRunContext runContext, IFrameworkHandle frameworkHandle)
+ {
+ RunTestsWithOptions(sources, frameworkHandle, MultiNodeTestRunnerOptions.Default);
+ }
+
+ private void RunTestsWithOptions(IEnumerable sources, IFrameworkHandle frameworkHandle, MultiNodeTestRunnerOptions options)
+ {
+ var testAssemblyPaths = sources.ToList();
+ frameworkHandle.SendMessage(TestMessageLevel.Informational, $"Loading tests from assemblies: {string.Join(", ", testAssemblyPaths)}");
+
+ foreach (var assemblyPath in testAssemblyPaths)
+ {
+ TestCase BuildTestCase(string name) => new TestCase(name, new Uri(ExecutorMetadata.ExecutorUri), assemblyPath);
+
+ var testCases = new ConcurrentDictionary();
+ try
+ {
+ var runner = new MultiNodeTestRunner();
+ runner.TestStarted += testName =>
+ {
+ var testCase = BuildTestCase(testName);
+ testCases.AddOrUpdate(testName, name => testCase, (name, existingCase) => testCase);
+ frameworkHandle.RecordStart(testCase);
+ };
+
+ runner.TestFinished += testResult =>
+ {
+ var testCase = testCases[testResult.TestName];
+ frameworkHandle.RecordResult(new TestResult(testCase)
+ {
+ // TODO: Set other props
+ Outcome = MapToOutcome(testResult.Status)
+ });
+ frameworkHandle.RecordEnd(testCase, MapToOutcome(testResult.Status));
+ };
+
+ runner.Execute(assemblyPath, options);
+ }
+ catch (Exception ex)
+ {
+ frameworkHandle.SendMessage(TestMessageLevel.Error, $"Failed during test execution: {ex}");
+ }
+ }
+ }
+
+ private TestOutcome MapToOutcome(MultiNodeTestResult.TestStatus status)
+ {
+ switch (status)
+ {
+ case MultiNodeTestResult.TestStatus.Passed:
+ return TestOutcome.Passed;
+ case MultiNodeTestResult.TestStatus.Skipped:
+ return TestOutcome.Skipped;
+ case MultiNodeTestResult.TestStatus.Failed:
+ return TestOutcome.Failed;
+ default:
+ return TestOutcome.None; // Unknown result
+ }
+ }
+ }
+}
diff --git a/src/Akka.MultiNode.TestRunner.Shared/Akka.MultiNode.TestRunner.Shared.csproj b/src/Akka.MultiNode.TestRunner.Shared/Akka.MultiNode.TestRunner.Shared.csproj
new file mode 100644
index 0000000..32d3f08
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner.Shared/Akka.MultiNode.TestRunner.Shared.csproj
@@ -0,0 +1,40 @@
+
+
+
+
+ Akka.MultiNode.TestRunner.Shared
+ $(NetFrameworkTestVersion);$(NetCoreTestVersion)
+ Akka.MultiNode.TestRunner.Shared
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);CORECLR
+
+
+
+ $(DefineConstants);RELEASE
+
+
+
diff --git a/src/Akka.MultiNodeTestRunner/Discovery.cs b/src/Akka.MultiNode.TestRunner.Shared/Discovery.cs
similarity index 94%
rename from src/Akka.MultiNodeTestRunner/Discovery.cs
rename to src/Akka.MultiNode.TestRunner.Shared/Discovery.cs
index 6d1d1e3..6834d09 100644
--- a/src/Akka.MultiNodeTestRunner/Discovery.cs
+++ b/src/Akka.MultiNode.TestRunner.Shared/Discovery.cs
@@ -7,17 +7,15 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Reflection;
-using System.Runtime.CompilerServices;
using System.Threading;
-using Akka.MultiNodeTestRunner.Shared;
+using Akka.MultiNode.Shared;
using Akka.Remote.TestKit;
using Xunit.Abstractions;
using Xunit.Sdk;
-namespace Akka.MultiNodeTestRunner
+namespace Akka.MultiNode.TestRunner.Shared
{
#if CORECLR
public class Discovery : IMessageSink, IDisposable
@@ -80,6 +78,12 @@ private List LoadTestCaseDetails(ITestCaseDiscoveryMessage testCaseDis
var testAssembly = Assembly.LoadFrom(testCaseDiscoveryMessage.TestAssembly.Assembly.AssemblyPath);
var specType = testAssembly.GetType(testClass.Name);
#endif
+ if (!typeof(Remote.TestKit.MultiNodeSpec).IsAssignableFrom(specType))
+ {
+ Console.WriteLine($"Ignoring {testClass.Name} test class - MNTR spec should inherit from {typeof(Remote.TestKit.MultiNodeSpec).FullName}");
+ return new List();
+ }
+
var roles = RoleNames(specType);
var details = roles.Select((r, i) => new NodeTest
diff --git a/src/Akka.MultiNode.TestRunner.Shared/MultiNodeSpec.cs b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeSpec.cs
new file mode 100644
index 0000000..d76282c
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeSpec.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using System.Linq;
+using Akka.MultiNode.Shared;
+
+namespace Akka.MultiNode.TestRunner.Shared
+{
+ ///
+ /// Spec found by
+ ///
+ public class MultiNodeSpec
+ {
+ public MultiNodeSpec(string specName, List tests)
+ {
+ SpecName = specName;
+ Tests = tests;
+ }
+
+ public string SpecName { get; }
+ public List Tests { get; }
+
+ public NodeTest FirstTest => Tests.First();
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestResult.cs b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestResult.cs
new file mode 100644
index 0000000..9bec330
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestResult.cs
@@ -0,0 +1,42 @@
+namespace Akka.MultiNode.TestRunner.Shared
+{
+ ///
+ /// MultiNodeTestResult
+ ///
+ public class MultiNodeTestResult
+ {
+ ///
+ /// MultiNodeTestResult
+ ///
+ public MultiNodeTestResult(string testName, TestStatus status)
+ {
+ TestName = testName;
+ Status = status;
+ }
+
+ ///
+ /// Full name of executed test
+ ///
+ public string TestName { get; }
+ ///
+ /// Test result
+ ///
+ public TestStatus Status { get; }
+
+ public enum TestStatus
+ {
+ ///
+ /// Test passed
+ ///
+ Passed,
+ ///
+ /// Test skipped
+ ///
+ Skipped,
+ ///
+ /// Test failed
+ ///
+ Failed
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestRunner.cs b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestRunner.cs
new file mode 100644
index 0000000..c4983c3
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestRunner.cs
@@ -0,0 +1,539 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (C) 2009-2019 Lightbend Inc.
+// Copyright (C) 2013-2019 .NET Foundation
+//
+//-----------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Akka.Actor;
+using Akka.IO;
+using Akka.MultiNode.Shared;
+using Akka.MultiNode.Shared.Environment;
+using Akka.MultiNode.Shared.Persistence;
+using Akka.MultiNode.Shared.Sinks;
+using Akka.MultiNode.Shared.TrxReporter;
+using Akka.Remote.TestKit;
+using Akka.Util;
+using Newtonsoft.Json;
+using Xunit;
+using ErrorMessage = Xunit.Sdk.ErrorMessage;
+
+#if CORECLR
+using System.Runtime.Loader;
+#endif
+
+namespace Akka.MultiNode.TestRunner.Shared
+{
+ ///
+ /// Entry point for the MultiNodeTestRunner
+ ///
+ public class MultiNodeTestRunner
+ {
+ private static readonly HashSet ValidNetCorePlatform = new HashSet
+ {
+ "net",
+ "netcore"
+ };
+
+ protected ActorSystem TestRunSystem;
+ protected IActorRef SinkCoordinator;
+
+ public Action TestStarted;
+ public Action TestFinished;
+
+ ///
+ /// Executes multi-node tests from given assembly
+ ///
+ public List Execute(string assemblyPath, MultiNodeTestRunnerOptions options)
+ {
+ ValidatePlatform(options);
+
+ // Perform output cleanup before anything is logged
+ if (options.ClearOutputDirectory && Directory.Exists(options.OutputDirectory))
+ Directory.Delete(options.OutputDirectory, true);
+
+ TestRunSystem = ActorSystem.Create("TestRunnerLogging");
+
+ var suiteName = Path.GetFileNameWithoutExtension(Path.GetFullPath(assemblyPath));
+ SinkCoordinator = CreateSinkCoordinator(options, suiteName);
+
+ var tcpLogger = TestRunSystem.ActorOf(Props.Create(() => new TcpLoggingServer(SinkCoordinator)), "TcpLogger");
+ var listenEndpoint = new IPEndPoint(IPAddress.Parse(options.ListenAddress), options.ListenPort);
+ TestRunSystem.Tcp().Tell(new Tcp.Bind(tcpLogger, listenEndpoint), sender: tcpLogger);
+
+ EnableAllSinks(assemblyPath, options);
+
+ // Set MNTR environment for correct tests discovert
+ MultiNodeEnvironment.Initialize();
+
+ // In NetCore, if the assembly file hasn't been touched,
+ // XunitFrontController would fail loading external assemblies and its dependencies.
+ PreLoadTestAssembly_WhenNetCore(assemblyPath);
+
+ // Here is where main action goes
+ var results = DiscoverAndRunSpecs(assemblyPath, options, tcpLogger);
+
+ AbortTcpLoggingServer(tcpLogger);
+ CloseAllSinks();
+
+ // Block until all Sinks have been terminated.
+ TestRunSystem.WhenTerminated.Wait(TimeSpan.FromMinutes(1));
+
+ // Return the proper exit code
+ return results;
+ }
+
+ ///
+ /// Discovers all tests in given assembly
+ ///
+ public static (List Specs, List Errors) DiscoverSpecs(string assemblyPath)
+ {
+ MultiNodeEnvironment.Initialize();
+
+ using (var controller = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyPath))
+ {
+ using (var discovery = new Discovery())
+ {
+ controller.Find(false, discovery, TestFrameworkOptions.ForDiscovery());
+ discovery.Finished.WaitOne();
+
+ if (!discovery.WasSuccessful)
+ {
+ return (Specs: new List(), Errors: discovery.Errors);
+ }
+
+ var specs = discovery.Tests.Reverse().Select(pair => new MultiNodeSpec(pair.Key, pair.Value)).ToList();
+ return (specs, new List());
+ }
+ }
+ }
+
+ private List DiscoverAndRunSpecs(string assemblyPath, MultiNodeTestRunnerOptions options, IActorRef tcpLogger)
+ {
+ var testResults = new List();
+ PublishRunnerMessage($"Running MultiNodeTests for {assemblyPath}");
+
+ var (discoveredSpecs, errors) = DiscoverSpecs(assemblyPath);
+ if (errors.Any())
+ {
+ ReportDiscoveryErrors(errors);
+ return testResults;
+ }
+
+ // If port was set random, request the actual port from TcpLoggingServer
+ var listenPort = options.ListenPort > 0
+ ? options.ListenPort
+ : tcpLogger.Ask(TcpLoggingServer.GetBoundPort.Instance).Result;
+
+ foreach (var spec in discoveredSpecs)
+ {
+ var testName = spec.Tests.First().MethodName;
+ TestStarted?.Invoke(spec.SpecName);
+
+ if (!string.IsNullOrEmpty(spec.FirstTest.SkipReason))
+ {
+ PublishRunnerMessage($"Skipping test {testName}. Reason - {spec.FirstTest.SkipReason}");
+ var skippedResult = new MultiNodeTestResult(testName, MultiNodeTestResult.TestStatus.Skipped);
+ testResults.Add(skippedResult);
+ TestFinished?.Invoke(skippedResult);
+ continue;
+ }
+
+ if (options.SpecNames != null &&
+ !options.SpecNames.All(name => spec.FirstTest.TestName.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) < 0))
+ {
+ PublishRunnerMessage($"Skipping [{spec.FirstTest.MethodName}] (Filtering)");
+ var skippedResult = new MultiNodeTestResult(testName, MultiNodeTestResult.TestStatus.Skipped);
+ testResults.Add(skippedResult);
+ TestFinished?.Invoke(skippedResult);
+ continue;
+ }
+
+ // Run test on several nodes and report results
+ var result = RunSpec(assemblyPath, options, spec, listenPort);
+ TestFinished?.Invoke(result);
+ testResults.Add(result);
+ }
+
+ return testResults;
+ }
+
+ private MultiNodeTestResult RunSpec(string assemblyPath, MultiNodeTestRunnerOptions options, MultiNodeSpec spec, int listenPort)
+ {
+ PublishRunnerMessage($"Starting test {spec.FirstTest.MethodName}");
+ Console.Out.WriteLine($"Starting test {spec.FirstTest.MethodName}");
+
+ StartNewSpec(spec.Tests);
+
+ var timelineCollector = TestRunSystem.ActorOf(Props.Create(() => new TimelineLogCollectorActor()));
+ string testOutputDir = null;
+ string runningSpecName = null;
+
+ var processes = new List();
+ foreach (var nodeTest in spec.Tests)
+ {
+ //Loop through each test, work out number of nodes to run on and kick off process
+ var sbArguments = new StringBuilder()
+ .Append($@"-Dmultinode.test-class=""{nodeTest.TypeName}"" ")
+ .Append($@"-Dmultinode.test-method=""{nodeTest.MethodName}"" ")
+ .Append($@"-Dmultinode.max-nodes={spec.Tests.Count} ")
+ .Append($@"-Dmultinode.server-host=""{"localhost"}"" ")
+ .Append($@"-Dmultinode.host=""{"localhost"}"" ")
+ .Append($@"-Dmultinode.index={nodeTest.Node - 1} ")
+ .Append($@"-Dmultinode.role=""{nodeTest.Role}"" ")
+ .Append($@"-Dmultinode.listen-address={options.ListenAddress} ")
+ .Append($@"-Dmultinode.listen-port={listenPort} ");
+
+ // Configure process for node
+ var process = BuildNodeProcess(assemblyPath, options, sbArguments);
+ processes.Add(process);
+
+ runningSpecName = nodeTest.TestName;
+
+ //TODO: might need to do some validation here to avoid the 260 character max path error on Windows
+ var folder = Directory.CreateDirectory(Path.Combine(options.OutputDirectory, nodeTest.TestName));
+ testOutputDir = testOutputDir ?? folder.FullName;
+
+ // Start process for node
+ StartNodeProcess(process, nodeTest, options, folder, timelineCollector);
+ }
+
+ // Wait for all nodes to finish and collect results
+ var specFailed = WaitForNodeExit(processes);
+
+ PublishRunnerMessage("Waiting 3 seconds for all messages from all processes to be collected.");
+ Thread.Sleep(TimeSpan.FromSeconds(3));
+
+ // Save timelined logs to file system
+ DumpAggregatedSpecLogs(options, testOutputDir, timelineCollector, specFailed, runningSpecName);
+
+ FinishSpec(spec.Tests, timelineCollector);
+
+ return new MultiNodeTestResult(runningSpecName, specFailed ? MultiNodeTestResult.TestStatus.Failed : MultiNodeTestResult.TestStatus.Passed);
+ }
+
+ private void DumpAggregatedSpecLogs(MultiNodeTestRunnerOptions options, string testOutputDir,
+ IActorRef timelineCollector, bool specFailed, string runningSpecName)
+ {
+ if (testOutputDir == null) return;
+ var dumpTasks = new List()
+ {
+ // Dump aggregated timeline to file for this test
+ timelineCollector.Ask(new TimelineLogCollectorActor.DumpToFile(Path.Combine(testOutputDir, "aggregated.txt"))),
+ // Print aggregated timeline into the console
+ timelineCollector.Ask(new TimelineLogCollectorActor.PrintToConsole())
+ };
+
+ if (specFailed)
+ {
+ var failedSpecPath = Path.Combine(Path.GetFullPath(options.OutputDirectory), options.FailedSpecsDirectory, $"{runningSpecName}.txt");
+ var dumpFailureArtifactTask = timelineCollector.Ask(new TimelineLogCollectorActor.DumpToFile(failedSpecPath));
+ dumpTasks.Add(dumpFailureArtifactTask);
+ }
+
+ Task.WaitAll(dumpTasks.ToArray());
+ }
+
+ private bool WaitForNodeExit(List processes)
+ {
+ var specFailed = false;
+ foreach (var process in processes)
+ {
+ process.WaitForExit();
+ specFailed = specFailed || process.ExitCode > 0;
+ process.Dispose();
+ }
+
+ return specFailed;
+ }
+
+ private void StartNodeProcess(Process process, NodeTest nodeTest, MultiNodeTestRunnerOptions options,
+ DirectoryInfo specFolder, IActorRef timelineCollector)
+ {
+ var nodeIndex = nodeTest.Node;
+ var nodeRole = nodeTest.Role;
+ var logFilePath = Path.Combine(specFolder.FullName, $"node{nodeIndex}__{nodeRole}__{options.Platform}.txt");
+ var nodeInfo = new TimelineLogCollectorActor.NodeInfo(nodeIndex, nodeRole, options.Platform, nodeTest.TestName);
+ var fileActor = TestRunSystem.ActorOf(Props.Create(() => new FileSystemAppenderActor(logFilePath)));
+ process.OutputDataReceived += (sender, eventArgs) =>
+ {
+ if (eventArgs?.Data != null)
+ {
+ fileActor.Tell(eventArgs.Data);
+ timelineCollector.Tell(new TimelineLogCollectorActor.LogMessage(nodeInfo, eventArgs.Data));
+ if (options.TeamCityFormattingOn)
+ {
+ // teamCityTest.WriteStdOutput(eventArgs.Data); TODO: open flood gates
+ }
+ }
+ };
+ var closureTest = nodeTest;
+ process.Exited += (sender, eventArgs) =>
+ {
+ if (process.ExitCode == 0)
+ {
+ ReportSpecPassFromExitCode(nodeIndex, nodeRole, closureTest.TestName);
+ }
+ };
+
+ process.Start();
+ process.BeginOutputReadLine();
+ PublishRunnerMessage($"Started node {nodeIndex} : {nodeRole} on pid {process.Id}");
+ }
+
+ private Process BuildNodeProcess(string assemblyPath, MultiNodeTestRunnerOptions options, StringBuilder sbArguments)
+ {
+#if CORECLR
+ const string nrNetFileName = "Akka.MultiNode.NodeRunner.exe";
+ const string nrNetCodeFileName = "Akka.MultiNode.NodeRunner.dll";
+ var searchPaths = new []
+ {
+ AppContext.BaseDirectory,
+ Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ };
+
+ // Try to find node runner location (may be different under `dotnet test` on different platforms)
+ var ntrNetPath = FileToolInPaths(nrNetFileName, searchPaths);
+ var ntrNetCorePath = FileToolInPaths(nrNetCodeFileName, searchPaths);
+
+ string fileName;
+ switch (options.Platform)
+ {
+ case "net":
+ if (!ntrNetPath.HasValue)
+ throw new Exception($"No {nrNetFileName} file is found at paths: {string.Join(", ", searchPaths)}");
+
+ fileName = ntrNetPath.Value;
+ sbArguments.Insert(0, $@" -Dmultinode.test-assembly=""{assemblyPath}"" ");
+ break;
+ case "netcore":
+ if (!ntrNetCorePath.HasValue)
+ throw new Exception($"No {nrNetCodeFileName} file is found at paths: {string.Join(", ", searchPaths)}");
+
+ fileName = "dotnet";
+ sbArguments.Insert(0, $@" -Dmultinode.test-assembly=""{assemblyPath}"" ");
+ sbArguments.Insert(0, ntrNetCorePath.Value);
+ break;
+ default: throw new ArgumentOutOfRangeException();
+ }
+
+ return new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = fileName,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ Arguments = sbArguments.ToString(),
+ WorkingDirectory = Path.GetDirectoryName(assemblyPath)
+ }
+ };
+#else
+ const string nodeRunnerFileName = "Akka.MultiNode.NodeRunner.exe";
+ var searchPaths = new []
+ {
+ AppContext.BaseDirectory,
+ Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ };
+
+ // Under 'dotnet test' or as standalone util location of node runner is different.
+ // The most robust way is to just scan possible locations and find it
+ var ntrNetPath = FileToolInPaths(nodeRunnerFileName, dirPaths: searchPaths);
+ if (!ntrNetPath.HasValue)
+ throw new Exception($"Failed to find node runner '{nodeRunnerFileName}' at paths: {string.Join(", ", searchPaths)}");
+
+ sbArguments.Insert(0, $@"-Dmultinode.test-assembly=""{assemblyPath}"" ");
+ return new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = ntrNetPath.Value,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ Arguments = sbArguments.ToString()
+ }
+ };
+#endif
+ }
+
+ private void ReportDiscoveryErrors(List errors)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine("One or more exception was thrown while discovering test cases. Test Aborted.");
+ foreach (var err in errors)
+ {
+ for (int i = 0; i < err.ExceptionTypes.Length; ++i)
+ {
+ sb.AppendLine();
+ sb.Append($"{err.ExceptionTypes[i]}: {err.Messages[i]}");
+ sb.Append(err.StackTraces[i]);
+ }
+ }
+
+ PublishRunnerMessage(sb.ToString());
+ Console.Out.WriteLine(sb.ToString());
+ }
+
+ private void PreLoadTestAssembly_WhenNetCore(string assemblyPath)
+ {
+#if CORECLR
+ var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
+ var asms = assembly.GetReferencedAssemblies();
+ var basePath = Path.GetDirectoryName(assemblyPath);
+ foreach (var asm in asms)
+ {
+ try
+ {
+ Assembly.Load(new AssemblyName(asm.FullName));
+ }
+ catch (Exception)
+ {
+ var path = Path.Combine(basePath, asm.Name + ".dll");
+ try
+ {
+ AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
+ }
+ catch (Exception e)
+ {
+ Console.Out.WriteLine($"Failed to load dll: {path}");
+ }
+ }
+ }
+#endif
+ }
+
+ private void ValidatePlatform(MultiNodeTestRunnerOptions options)
+ {
+#if CORECLR
+ if (!ValidNetCorePlatform.Contains(options.Platform))
+ {
+ throw new Exception($"Target platform not supported: {options.Platform}. Supported platforms are net and netcore");
+ }
+#else
+ if (options.Platform != "net")
+ {
+ throw new Exception($"Target platform not supported: {options.Platform}. Supported platforms are net");
+ }
+#endif
+ }
+
+ private IActorRef CreateSinkCoordinator(MultiNodeTestRunnerOptions options, string suiteName)
+ {
+ Props coordinatorProps;
+ switch (options.Reporter.ToLowerInvariant())
+ {
+ case "trx":
+ coordinatorProps = Props.Create(() => new SinkCoordinator(new[] {new TrxMessageSink(suiteName)}));
+ break;
+
+ case "teamcity":
+ coordinatorProps = Props.Create(() =>
+ new SinkCoordinator(new[] {new TeamCityMessageSink(Console.WriteLine, suiteName)}));
+ break;
+
+ case "console":
+ coordinatorProps = Props.Create(() => new SinkCoordinator(new[] {new ConsoleMessageSink()}));
+ break;
+
+ default:
+ throw new ArgumentException(
+ $"Given reporter name '{options.Reporter}' is not understood, valid reporters are: trx and teamcity");
+ }
+
+ return TestRunSystem.ActorOf(coordinatorProps, "sinkCoordinator");
+ }
+
+ static string ChangeDllPathPlatform(string path, string targetPlatform)
+ {
+ return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), "..", targetPlatform, Path.GetFileName(path)));
+ }
+
+ private void EnableAllSinks(string assemblyName, MultiNodeTestRunnerOptions options)
+ {
+ var now = DateTime.UtcNow;
+
+ // if multinode.output-directory wasn't specified, the results files will be written
+ // to the same directory as the test assembly.
+ var outputDirectory = options.OutputDirectory;
+
+ MessageSink CreateJsonFileSink()
+ {
+ var fileName = FileNameGenerator.GenerateFileName(outputDirectory, assemblyName, options.Platform, ".json", now);
+ var jsonStoreProps = Props.Create(() => new FileSystemMessageSinkActor(new JsonPersistentTestRunStore(), fileName, !options.TeamCityFormattingOn, true));
+ return new FileSystemMessageSink(jsonStoreProps);
+ }
+
+ MessageSink CreateVisualizerFileSink()
+ {
+ var fileName = FileNameGenerator.GenerateFileName(outputDirectory, assemblyName, options.Platform, ".html", now);
+ var visualizerProps = Props.Create(() => new FileSystemMessageSinkActor(new VisualizerPersistentTestRunStore(), fileName, !options.TeamCityFormattingOn, true));
+ return new FileSystemMessageSink(visualizerProps);
+ }
+
+ var fileSystemSink = CommandLine.GetProperty("multinode.enable-filesink");
+ if (!string.IsNullOrEmpty(fileSystemSink))
+ {
+ SinkCoordinator.Tell(new SinkCoordinator.EnableSink(CreateJsonFileSink()));
+ SinkCoordinator.Tell(new SinkCoordinator.EnableSink(CreateVisualizerFileSink()));
+ }
+ }
+
+ private void AbortTcpLoggingServer(IActorRef tcpLogger)
+ {
+ tcpLogger.Ask(new TcpLoggingServer.StopListener(), TimeSpan.FromMinutes(1)).Wait();
+ }
+
+ private void CloseAllSinks()
+ {
+ SinkCoordinator.Tell(new SinkCoordinator.CloseAllSinks());
+ }
+
+ private void StartNewSpec(IList tests)
+ {
+ SinkCoordinator.Tell(tests);
+ }
+
+ private void ReportSpecPassFromExitCode(int nodeIndex, string nodeRole, string testName)
+ {
+ SinkCoordinator.Tell(new NodeCompletedSpecWithSuccess(nodeIndex, nodeRole, testName + " passed."));
+ }
+
+ private void FinishSpec(IList tests, IActorRef timelineCollector)
+ {
+ var spec = tests.First();
+ var log = timelineCollector.Ask(new TimelineLogCollectorActor.GetSpecLog(), TimeSpan.FromMinutes(1)).Result;
+ SinkCoordinator.Tell(new EndSpec(spec.TestName, spec.MethodName, log));
+ }
+
+ private void PublishRunnerMessage(string message)
+ {
+ SinkCoordinator.Tell(new SinkCoordinator.RunnerMessage(message));
+ }
+
+ ///
+ /// Finds given tool in specified paths
+ ///
+ private Option FileToolInPaths(string toolFileName, params string[] dirPaths)
+ {
+ foreach (var dir in dirPaths)
+ {
+ var path = Path.Combine(dir, toolFileName);
+ if (File.Exists(path))
+ return path;
+ }
+
+ return Option.None;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestRunnerOptions.cs b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestRunnerOptions.cs
new file mode 100644
index 0000000..d020a8b
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner.Shared/MultiNodeTestRunnerOptions.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.IO;
+using Akka.Util;
+
+namespace Akka.MultiNode.TestRunner.Shared
+{
+ ///
+ /// MultiNodeTestRunnerOptions
+ ///
+ public class MultiNodeTestRunnerOptions
+ {
+ ///
+ /// Default options
+ ///
+ public static readonly MultiNodeTestRunnerOptions Default = new MultiNodeTestRunnerOptions();
+
+ public MultiNodeTestRunnerOptions(string outputDirectory = null, string failedSpecsDirectory = null,
+ string listenAddress = null, int listenPort = 0, List specNames = null,
+ string platform = null, string reporter = null, bool clearOutputDirectory = false,
+ bool teamCityFormattingOn = false)
+ {
+ ListenPort = listenPort;
+ SpecNames = specNames;
+ ClearOutputDirectory = clearOutputDirectory;
+ TeamCityFormattingOn = teamCityFormattingOn;
+ Reporter = reporter ?? "console";
+ Platform = platform ?? (RuntimeDetector.IsWindows ? "net" : "netcore");
+ FailedSpecsDirectory = failedSpecsDirectory ?? "FAILED_SPECS_LOGS";
+ ListenAddress = listenAddress ?? "127.0.0.1";
+ OutputDirectory = outputDirectory ?? "TestResults";
+ }
+
+ ///
+ /// File output directory
+ ///
+ public string OutputDirectory { get; }
+ ///
+ /// Subdirectory to store failed specs logs
+ ///
+ public string FailedSpecsDirectory { get; }
+ ///
+ /// MNTR controller listener address
+ ///
+ public string ListenAddress { get; }
+ ///
+ /// MNTR controller listener port. Set 0 to use random available port
+ ///
+ public int ListenPort { get; }
+ ///
+ /// List of spec names to be executed. Other specs are skipped
+ ///
+ public List SpecNames { get; }
+ ///
+ /// Current platform. "net" or "netcore"
+ ///
+ public string Platform { get; }
+ ///
+ /// Reporter. "trx"/"teamcity"/"console"
+ ///
+ public string Reporter { get; }
+ ///
+ /// If set, performs output directory cleanup before running tests
+ ///
+ public bool ClearOutputDirectory { get; }
+ ///
+ /// TeamCity formatting on/off
+ ///
+ public bool TeamCityFormattingOn { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNodeTestRunner/Properties/AssemblyInfo.cs b/src/Akka.MultiNode.TestRunner.Shared/Properties/AssemblyInfo.cs
similarity index 54%
rename from src/Akka.MultiNodeTestRunner/Properties/AssemblyInfo.cs
rename to src/Akka.MultiNode.TestRunner.Shared/Properties/AssemblyInfo.cs
index 46a4a3d..1262693 100644
--- a/src/Akka.MultiNodeTestRunner/Properties/AssemblyInfo.cs
+++ b/src/Akka.MultiNode.TestRunner.Shared/Properties/AssemblyInfo.cs
@@ -5,19 +5,9 @@
//
//-----------------------------------------------------------------------
-using System.Reflection;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-
-[assembly: InternalsVisibleTo("Akka.MultiNodeTestRunner.Shared.Tests")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("4442771d-674d-45ad-8e13-ffdc6b442716")]
+[assembly: InternalsVisibleTo("Akka.MultiNode.Shared.Tests")]
diff --git a/src/Akka.MultiNode.TestRunner.Shared/TcpLoggingServer.cs b/src/Akka.MultiNode.TestRunner.Shared/TcpLoggingServer.cs
new file mode 100644
index 0000000..a5592ad
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner.Shared/TcpLoggingServer.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Immutable;
+using System.Net;
+using System.Threading;
+using Akka.Actor;
+using Akka.Event;
+using Akka.IO;
+using Akka.Util;
+using Akka.Util.Internal;
+
+namespace Akka.MultiNode.TestRunner.Shared
+{
+ internal class TcpLoggingServer : ReceiveActor
+ {
+ private readonly ILoggingAdapter _log = Context.GetLogger();
+ private IActorRef _tcpManager = Nobody.Instance;
+ private IActorRef _abortSender;
+
+ private Option _boundPort;
+ private IImmutableSet _boundPortSubscribers = ImmutableHashSet.Empty;
+
+ public TcpLoggingServer(IActorRef sinkCoordinator)
+ {
+ Receive(bound =>
+ {
+ // When bound, save port and notify requestors if any
+ _boundPort = (bound.LocalAddress as IPEndPoint).Port;
+ _boundPortSubscribers.ForEach(s => s.Tell(_boundPort.Value));
+
+ _tcpManager = Sender;
+ });
+
+ Receive(_ =>
+ {
+ // If bound port is not received yet, just save subscriber and send respose later
+ if (_boundPort.HasValue)
+ Sender.Tell(_boundPort.Value);
+ else
+ _boundPortSubscribers = _boundPortSubscribers.Add(Sender);
+ });
+
+ Receive(connected =>
+ {
+ _log.Info($"Node connected on {Sender}");
+ Sender.Tell(new Tcp.Register(Self));
+ });
+
+ Receive(
+ closed => _log.Info($"Node disconnected on {Sender}{Environment.NewLine}"));
+
+ Receive(received =>
+ {
+ var message = received.Data.ToString();
+ sinkCoordinator.Tell(message);
+ });
+
+ Receive(_ =>
+ {
+ _abortSender = Sender;
+ _tcpManager.Tell(Tcp.Unbind.Instance);
+ });
+ Receive(_ => _abortSender.Tell(new ListenerStopped()));
+ }
+
+ public class StopListener { }
+ public class ListenerStopped { }
+
+ public class GetBoundPort
+ {
+ private GetBoundPort() { }
+ public static readonly GetBoundPort Instance = new GetBoundPort();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.csproj b/src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.csproj
similarity index 58%
rename from src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.csproj
rename to src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.csproj
index 0315c6d..56e17b2 100644
--- a/src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.csproj
+++ b/src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.csproj
@@ -2,25 +2,21 @@
- Akka.MultiNodeTestRunner
+ Akka.MultiNode.TestRunner
Akka.NET Multi-node Test Runner; used for executing tests written with Akka.Remote.TestKit
$(NetFrameworkTestVersion);$(NetCoreTestVersion)
Exe
$(AkkaPackageTags)
- Akka.MultiNodeTestRunner.nuspec
+ Akka.MultiNode.TestRunner.nuspec
+ Akka.MultiNode.TestRunner
-
+
-
-
-
-
-
-
+
diff --git a/src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec.template b/src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.nuspec.template
similarity index 100%
rename from src/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec.template
rename to src/Akka.MultiNode.TestRunner/Akka.MultiNode.TestRunner.nuspec.template
diff --git a/src/Akka.MultiNode.TestRunner/Program.cs b/src/Akka.MultiNode.TestRunner/Program.cs
new file mode 100644
index 0000000..cc782bf
--- /dev/null
+++ b/src/Akka.MultiNode.TestRunner/Program.cs
@@ -0,0 +1,136 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (C) 2009-2019 Lightbend Inc.
+// Copyright (C) 2013-2019 .NET Foundation
+//
+//-----------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Akka.Actor;
+using Akka.Event;
+using Akka.IO;
+using Akka.MultiNode.Shared;
+using Akka.MultiNode.Shared.Persistence;
+using Akka.MultiNode.Shared.Sinks;
+using Akka.MultiNode.Shared.TrxReporter;
+using Akka.MultiNode.TestRunner.Shared;
+using Akka.Remote.TestKit;
+using Xunit;
+
+#if CORECLR
+using System.Runtime.Loader;
+#endif
+
+namespace Akka.MultiNode.TestRunner
+{
+ ///
+ /// Entry point for the MultiNodeTestRunner
+ ///
+ class Program
+ {
+ ///
+ /// MultiNodeTestRunner takes the following :
+ ///
+ /// C:\> Akka.MultiNode.TestRunner.exe [assembly name] [-Dmultinode.enable-filesink=on] [-Dmultinode.output-directory={dir path}] [-Dmultinode.spec={spec name}]
+ ///
+ ///
+ ///
+ /// Argument
+ /// The name and possible value of a given Akka.MultiNode.TestRunner.exe argument.
+ ///
+ /// -
+ /// AssemblyName
+ ///
+ /// The full path or name of an assembly containing as least one MultiNodeSpec in the current working directory.
+ ///
+ /// i.e. "Akka.Cluster.Tests.MultiNode.dll"
+ /// "C:\akka.net\src\Akka.Cluster.Tests\bin\Debug\Akka.Cluster.Tests.MultiNode.dll"
+ ///
+ ///
+ /// -
+ /// -Dmultinode.enable-filesink
+ /// Having this flag set means that the contents of this test run will be saved in the
+ /// current working directory as a .JSON file.
+ ///
+ ///
+ /// -
+ /// -Dmultinode.multinode.output-directory
+ /// Setting this flag means that any persistent multi-node test runner output files
+ /// will be written to this directory instead of the default, which is the same folder
+ /// as the test binary.
+ ///
+ ///
+ /// -
+ /// -Dmultinode.listen-address={ip}
+ ///
+ /// Determines the address that this multi-node test runner will use to listen for log messages from
+ /// individual NodeTestRunner.exe processes.
+ ///
+ /// Defaults to 127.0.0.1
+ ///
+ ///
+ /// -
+ /// -Dmultinode.listen-port={port}
+ ///
+ /// Determines the port number that this multi-node test runner will use to listen for log messages from
+ /// individual NodeTestRunner.exe processes.
+ ///
+ /// Defaults to 6577
+ ///
+ ///
+ /// -
+ /// -Dmultinode.spec={spec name}
+ ///
+ /// Setting this flag means that only tests which contains the spec name will be executed
+ /// otherwise all tests will be executed
+ ///
+ ///
+ ///
+ ///
+ static void Main(string[] args)
+ {
+ var assemblyPath = Path.GetFullPath(args[0].Trim('"')); // unquote the string first
+ var outputDirectory = CommandLine.GetPropertyOrDefault("multinode.output-directory", string.Empty);
+ var failedSpecsDirectory = CommandLine.GetPropertyOrDefault("multinode.failed-specs-directory", "FAILED_SPECS_LOGS");
+ var listenAddress = CommandLine.GetPropertyOrDefault("multinode.listen-address", "127.0.0.1");
+ var listenPort = CommandLine.GetInt32OrDefault("multinode.listen-port", 6577);
+ var specName = CommandLine.GetPropertyOrDefault("multinode.spec", "");
+ var platform = CommandLine.GetPropertyOrDefault("multinode.platform", "net");
+ var reporter = CommandLine.GetPropertyOrDefault("multinode.reporter", "console");
+ var clearOutputDirectory = CommandLine.GetInt32OrDefault("multinode.clear-output", 0) > 0;
+ var teamCityFormattingStr = CommandLine.GetPropertyOrDefault("multinode.teamcity", "false");
+ if (!bool.TryParse(teamCityFormattingStr, out var teamCityFormattingOn))
+ throw new ArgumentException("Invalid argument provided for -Dteamcity");
+
+ var runner = new MultiNodeTestRunner();
+ var results = runner.Execute(assemblyPath, new MultiNodeTestRunnerOptions(
+ outputDirectory: outputDirectory,
+ failedSpecsDirectory: failedSpecsDirectory,
+ teamCityFormattingOn: teamCityFormattingOn,
+ listenAddress: listenAddress,
+ listenPort: listenPort,
+ specNames: !string.IsNullOrEmpty(specName) ? new List() { specName } : null,
+ platform: platform,
+ reporter: reporter,
+ clearOutputDirectory: clearOutputDirectory
+ ));
+
+ if (Debugger.IsAttached)
+ Console.ReadLine(); // block when debugging
+
+ // Return the proper exit code
+ var retCode = results.Any(r => r.Status == MultiNodeTestResult.TestStatus.Failed) ? 1 : 0;
+ Environment.Exit(retCode);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Akka.MultiNodeTestRunner/README.md b/src/Akka.MultiNode.TestRunner/README.md
similarity index 100%
rename from src/Akka.MultiNodeTestRunner/README.md
rename to src/Akka.MultiNode.TestRunner/README.md
diff --git a/src/Akka.MultiNodeTestRunner/Class1.cs b/src/Akka.MultiNodeTestRunner/Class1.cs
deleted file mode 100644
index ab2768d..0000000
--- a/src/Akka.MultiNodeTestRunner/Class1.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System;
-
-namespace Akka.MultiNodeTestRunner
-{
- public class Class1
- {
- }
-}
diff --git a/src/Akka.MultiNodeTestRunner/Program.cs b/src/Akka.MultiNodeTestRunner/Program.cs
deleted file mode 100644
index 1b8906c..0000000
--- a/src/Akka.MultiNodeTestRunner/Program.cs
+++ /dev/null
@@ -1,530 +0,0 @@
-//-----------------------------------------------------------------------
-//
-// Copyright (C) 2009-2019 Lightbend Inc.
-// Copyright (C) 2013-2019 .NET Foundation
-//
-//-----------------------------------------------------------------------
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Akka.Actor;
-using Akka.Event;
-using Akka.IO;
-using Akka.MultiNodeTestRunner.Shared;
-using Akka.MultiNodeTestRunner.Shared.Persistence;
-using Akka.MultiNodeTestRunner.Shared.Reporting;
-using Akka.MultiNodeTestRunner.Shared.Sinks;
-using Akka.Remote.TestKit;
-using Akka.Util;
-using JetBrains.TeamCity.ServiceMessages.Write.Special;
-using JetBrains.TeamCity.ServiceMessages.Write.Special.Impl;
-using Xunit;
-#if CORECLR
-using System.Runtime.Loader;
-#endif
-
-namespace Akka.MultiNodeTestRunner
-{
- using Shared.AzureDevOps;
-
- ///
- /// Entry point for the MultiNodeTestRunner
- ///
- class Program
- {
- private static HashSet _validNetCorePlatform = new HashSet
- {
- "net",
- "netcore"
- };
-
- protected static ActorSystem TestRunSystem;
- protected static IActorRef SinkCoordinator;
-
- ///
- /// file output directory
- ///
- protected static string OutputDirectory;
- ///
- /// Subdirectory to store failed specs logs
- ///
- protected static string FailedSpecsDirectory;
-
- protected static bool TeamCityFormattingOn;
- protected static bool MultiPlatform;
-
- ///
- /// MultiNodeTestRunner takes the following :
- ///
- /// C:\> Akka.MultiNodeTestRunner.exe [assembly name] [-Dmultinode.enable-filesink=on] [-Dmultinode.output-directory={dir path}] [-Dmultinode.spec={spec name}]
- ///
- ///
- ///
- /// Argument
- /// The name and possible value of a given Akka.MultiNodeTestRunner.exe argument.
- ///
- /// -
- /// AssemblyName
- ///
- /// The full path or name of an assembly containing as least one MultiNodeSpec in the current working directory.
- ///
- /// i.e. "Akka.Cluster.Tests.MultiNode.dll"
- /// "C:\akka.net\src\Akka.Cluster.Tests\bin\Debug\Akka.Cluster.Tests.MultiNode.dll"
- ///
- ///
- /// -
- /// -Dmultinode.enable-filesink
- /// Having this flag set means that the contents of this test run will be saved in the
- /// current working directory as a .JSON file.
- ///
- ///
- /// -
- /// -Dmultinode.multinode.output-directory
- /// Setting this flag means that any persistent multi-node test runner output files
- /// will be written to this directory instead of the default, which is the same folder
- /// as the test binary.
- ///
- ///
- /// -
- /// -Dmultinode.listen-address={ip}
- ///
- /// Determines the address that this multi-node test runner will use to listen for log messages from
- /// individual NodeTestRunner.exe processes.
- ///
- /// Defaults to 127.0.0.1
- ///
- ///
- /// -
- /// -Dmultinode.listen-port={port}
- ///
- /// Determines the port number that this multi-node test runner will use to listen for log messages from
- /// individual NodeTestRunner.exe processes.
- ///
- /// Defaults to 6577
- ///
- ///
- /// -
- /// -Dmultinode.spec={spec name}
- ///
- /// Setting this flag means that only tests which contains the spec name will be executed
- /// otherwise all tests will be executed
- ///
- ///
- ///
- ///
- static void Main(string[] args)
- {
- OutputDirectory = CommandLine.GetPropertyOrDefault("multinode.output-directory", string.Empty);
- FailedSpecsDirectory = CommandLine.GetPropertyOrDefault("multinode.failed-specs-directory", "FAILED_SPECS_LOGS");
- TestRunSystem = ActorSystem.Create("TestRunnerLogging");
-
- var suiteName = Path.GetFileNameWithoutExtension(Path.GetFullPath(args[0].Trim('"')));
- var teamCityFormattingOn = CommandLine.GetPropertyOrDefault("multinode.teamcity", "false");
- if (!Boolean.TryParse(teamCityFormattingOn, out TeamCityFormattingOn))
- throw new ArgumentException("Invalid argument provided for -Dteamcity");
-
- var listenAddress = IPAddress.Parse(CommandLine.GetPropertyOrDefault("multinode.listen-address", "127.0.0.1"));
- var listenPort = CommandLine.GetInt32OrDefault("multinode.listen-port", 6577);
- var listenEndpoint = new IPEndPoint(listenAddress, listenPort);
- var specName = CommandLine.GetPropertyOrDefault("multinode.spec", "");
- var platform = CommandLine.GetPropertyOrDefault("multinode.platform", "net");
- var reporter = CommandLine.GetPropertyOrDefault("multinode.reporter", "console");
-
- var clearOutputDirectory = CommandLine.GetInt32OrDefault("multinode.clear-output", 0);
- if (clearOutputDirectory > 0 && Directory.Exists(OutputDirectory))
- Directory.Delete(OutputDirectory, true);
-
- Props coordinatorProps;
- switch (reporter.ToLowerInvariant())
- {
- case "trx":
- coordinatorProps = Props.Create(() => new SinkCoordinator(new[] { new TrxMessageSink(suiteName) }));
- break;
-
- case "teamcity":
- coordinatorProps = Props.Create(() => new SinkCoordinator(new[] { new TeamCityMessageSink(Console.WriteLine, suiteName) }));
- break;
-
- case "console":
- coordinatorProps = Props.Create(() => new SinkCoordinator(new[] { new ConsoleMessageSink() }));
- break;
-
- default:
- throw new ArgumentException($"Given reporter name '{reporter}' is not understood, valid reporters are: trx and teamcity");
- }
-
- SinkCoordinator = TestRunSystem.ActorOf(coordinatorProps, "sinkCoordinator");
-
-#if CORECLR
- if (!_validNetCorePlatform.Contains(platform))
- {
- throw new Exception($"Target platform not supported: {platform}. Supported platforms are net and netcore");
- }
-#else
- if (platform != "net")
- {
- throw new Exception($"Target platform not supported: {platform}. Supported platforms are net");
- }
-#endif
-
- var tcpLogger = TestRunSystem.ActorOf(Props.Create(() => new TcpLoggingServer(SinkCoordinator)), "TcpLogger");
- TestRunSystem.Tcp().Tell(new Tcp.Bind(tcpLogger, listenEndpoint), sender: tcpLogger);
-
- var assemblyPath = Path.GetFullPath(args[0].Trim('"')); //unquote the string first
-
- EnableAllSinks(assemblyPath, platform);
- PublishRunnerMessage($"Running MultiNodeTests for {assemblyPath}");
-#if CORECLR
- // In NetCore, if the assembly file hasn't been touched,
- // XunitFrontController would fail loading external assemblies and its dependencies.
- var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
- var asms = assembly.GetReferencedAssemblies();
- var basePath = Path.GetDirectoryName(assemblyPath);
- foreach (var asm in asms)
- {
- try
- {
- Assembly.Load(new AssemblyName(asm.FullName));
- }
- catch (Exception)
- {
- var path = Path.Combine(basePath, asm.Name + ".dll");
- try
- {
- AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
- }
- catch (Exception e)
- {
- Console.Out.WriteLine($"Failed to load dll: {path}");
- }
- }
- }
-#endif
-
- using (var controller = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyPath))
- {
- using (var discovery = new Discovery())
- {
- controller.Find(false, discovery, TestFrameworkOptions.ForDiscovery());
- discovery.Finished.WaitOne();
-
- if (discovery.WasSuccessful)
- {
- foreach (var test in discovery.Tests.Reverse())
- {
- if (!string.IsNullOrEmpty(test.Value.First().SkipReason))
- {
- PublishRunnerMessage($"Skipping test {test.Value.First().MethodName}. Reason - {test.Value.First().SkipReason}");
- continue;
- }
-
- if (!string.IsNullOrWhiteSpace(specName) &&
- CultureInfo.InvariantCulture.CompareInfo.IndexOf(test.Value.First().TestName,
- specName,
- CompareOptions.IgnoreCase) < 0)
- {
- PublishRunnerMessage($"Skipping [{test.Value.First().MethodName}] (Filtering)");
- continue;
- }
-
- var processes = new List();
-
- PublishRunnerMessage($"Starting test {test.Value.First().MethodName}");
- Console.Out.WriteLine($"Starting test {test.Value.First().MethodName}");
-
- StartNewSpec(test.Value);
-#if CORECLR
- var ntrNetPath = Path.Combine(AppContext.BaseDirectory, "Akka.NodeTestRunner.exe");
- var ntrNetCorePath = Path.Combine(AppContext.BaseDirectory, "Akka.NodeTestRunner.dll");
- var alternateIndex = 0;
-#endif
- var timelineCollector = TestRunSystem.ActorOf(Props.Create(() => new TimelineLogCollectorActor()));
- string testOutputDir = null;
- string runningSpecName = null;
-
- foreach (var nodeTest in test.Value)
- {
- //Loop through each test, work out number of nodes to run on and kick off process
- var sbArguments = new StringBuilder()
- //.Append($@"-Dmultinode.test-assembly=""{assemblyPath}"" ")
- .Append($@"-Dmultinode.test-class=""{nodeTest.TypeName}"" ")
- .Append($@"-Dmultinode.test-method=""{nodeTest.MethodName}"" ")
- .Append($@"-Dmultinode.max-nodes={test.Value.Count} ")
- .Append($@"-Dmultinode.server-host=""{"localhost"}"" ")
- .Append($@"-Dmultinode.host=""{"localhost"}"" ")
- .Append($@"-Dmultinode.index={nodeTest.Node - 1} ")
- .Append($@"-Dmultinode.role=""{nodeTest.Role}"" ")
- .Append($@"-Dmultinode.listen-address={listenAddress} ")
- .Append($@"-Dmultinode.listen-port={listenPort} ");
-
-#if CORECLR
- string fileName = null;
- switch (platform)
- {
- case "net":
- fileName = ntrNetPath;
- sbArguments.Insert(0, $@" -Dmultinode.test-assembly=""{assemblyPath}"" ");
- break;
- case "netcore":
- fileName = "dotnet";
- sbArguments.Insert(0, $@" -Dmultinode.test-assembly=""{assemblyPath}"" ");
- sbArguments.Insert(0, ntrNetCorePath);
- break;
- }
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = fileName,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- Arguments = sbArguments.ToString(),
- WorkingDirectory = Path.GetDirectoryName(assemblyPath)
- }
- };
-#else
- sbArguments.Insert(0, $@"-Dmultinode.test-assembly=""{assemblyPath}"" ");
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = "Akka.NodeTestRunner.exe",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- Arguments = sbArguments.ToString()
- }
- };
-#endif
-
- processes.Add(process);
- var nodeIndex = nodeTest.Node;
- var nodeRole = nodeTest.Role;
-
-#if CORECLR
- if (platform == "netcore")
- {
- process.StartInfo.FileName = "dotnet";
- process.StartInfo.Arguments = ntrNetCorePath + " " + process.StartInfo.Arguments;
- process.StartInfo.WorkingDirectory = Path.GetDirectoryName(assemblyPath);
- }
-#endif
-
- //TODO: might need to do some validation here to avoid the 260 character max path error on Windows
- var folder = Directory.CreateDirectory(Path.Combine(OutputDirectory, nodeTest.TestName));
- testOutputDir = testOutputDir ?? folder.FullName;
- var logFilePath = Path.Combine(folder.FullName, $"node{nodeIndex}__{nodeRole}__{platform}.txt");
- runningSpecName = nodeTest.TestName;
- var nodeInfo = new TimelineLogCollectorActor.NodeInfo(nodeIndex, nodeRole, platform, nodeTest.TestName);
- var fileActor = TestRunSystem.ActorOf(Props.Create(() => new FileSystemAppenderActor(logFilePath)));
- process.OutputDataReceived += (sender, eventArgs) =>
- {
- if (eventArgs?.Data != null)
- {
- fileActor.Tell(eventArgs.Data);
- timelineCollector.Tell(new TimelineLogCollectorActor.LogMessage(nodeInfo, eventArgs.Data));
- if (TeamCityFormattingOn)
- {
- // teamCityTest.WriteStdOutput(eventArgs.Data); TODO: open flood gates
- }
- }
- };
- var closureTest = nodeTest;
- process.Exited += (sender, eventArgs) =>
- {
- if (process.ExitCode == 0)
- {
- ReportSpecPassFromExitCode(nodeIndex, nodeRole, closureTest.TestName);
- }
- };
-
- process.Start();
- process.BeginOutputReadLine();
- PublishRunnerMessage($"Started node {nodeIndex} : {nodeRole} on pid {process.Id}");
- }
-
- var specFailed = false;
- foreach (var process in processes)
- {
- process.WaitForExit();
- specFailed = specFailed || process.ExitCode > 0;
- process.Dispose();
- }
-
- PublishRunnerMessage("Waiting 3 seconds for all messages from all processes to be collected.");
- Thread.Sleep(TimeSpan.FromSeconds(3));
-
- if (testOutputDir != null)
- {
- var dumpTasks = new List()
- {
- // Dump aggregated timeline to file for this test
- timelineCollector.Ask(new TimelineLogCollectorActor.DumpToFile(Path.Combine(testOutputDir, "aggregated.txt"))),
- // Print aggregated timeline into the console
- timelineCollector.Ask(new TimelineLogCollectorActor.PrintToConsole())
- };
-
- if (specFailed)
- {
- var dumpFailureArtifactTask = timelineCollector.Ask(
- new TimelineLogCollectorActor.DumpToFile(Path.Combine(Path.GetFullPath(OutputDirectory), FailedSpecsDirectory, $"{runningSpecName}.txt")));
- dumpTasks.Add(dumpFailureArtifactTask);
- }
- Task.WaitAll(dumpTasks.ToArray());
- }
-
- FinishSpec(test.Value, timelineCollector);
- }
- Console.WriteLine("Complete");
- PublishRunnerMessage("Waiting 5 seconds for all messages from all processes to be collected.");
- Thread.Sleep(TimeSpan.FromSeconds(5));
- }
- else
- {
- var sb = new StringBuilder();
- sb.AppendLine("One or more exception was thrown while discovering test cases. Test Aborted.");
- foreach (var err in discovery.Errors)
- {
- for (int i = 0; i < err.ExceptionTypes.Length; ++i)
- {
- sb.AppendLine();
- sb.Append($"{err.ExceptionTypes[i]}: {err.Messages[i]}");
- sb.Append(err.StackTraces[i]);
- }
- }
- PublishRunnerMessage(sb.ToString());
- Console.Out.WriteLine(sb.ToString());
- }
- }
- }
-
- AbortTcpLoggingServer(tcpLogger);
- CloseAllSinks();
-
- //Block until all Sinks have been terminated.
- TestRunSystem.WhenTerminated.Wait(TimeSpan.FromMinutes(1));
-
- if (Debugger.IsAttached)
- Console.ReadLine(); //block when debugging
-
- //Return the proper exit code
- Environment.Exit(ExitCodeContainer.ExitCode);
- }
-
- static string ChangeDllPathPlatform(string path, string targetPlatform)
- {
- return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), "..", targetPlatform, Path.GetFileName(path)));
- }
-
- static void EnableAllSinks(string assemblyName, string platform)
- {
- var now = DateTime.UtcNow;
-
- // if multinode.output-directory wasn't specified, the results files will be written
- // to the same directory as the test assembly.
- var outputDirectory = OutputDirectory;
-
- MessageSink CreateJsonFileSink()
- {
- var fileName = FileNameGenerator.GenerateFileName(outputDirectory, assemblyName, platform, ".json", now);
- var jsonStoreProps = Props.Create(() => new FileSystemMessageSinkActor(new JsonPersistentTestRunStore(), fileName, !TeamCityFormattingOn, true));
- return new FileSystemMessageSink(jsonStoreProps);
- }
-
- MessageSink CreateVisualizerFileSink()
- {
- var fileName = FileNameGenerator.GenerateFileName(outputDirectory, assemblyName, platform, ".html", now);
- var visualizerProps = Props.Create(() => new FileSystemMessageSinkActor(new VisualizerPersistentTestRunStore(), fileName, !TeamCityFormattingOn, true));
- return new FileSystemMessageSink(visualizerProps);
- }
-
- var fileSystemSink = CommandLine.GetProperty("multinode.enable-filesink");
- if (!string.IsNullOrEmpty(fileSystemSink))
- {
- SinkCoordinator.Tell(new SinkCoordinator.EnableSink(CreateJsonFileSink()));
- SinkCoordinator.Tell(new SinkCoordinator.EnableSink(CreateVisualizerFileSink()));
- }
- }
-
- private static void AbortTcpLoggingServer(IActorRef tcpLogger)
- {
- tcpLogger.Ask(new TcpLoggingServer.StopListener(), TimeSpan.FromMinutes(1)).Wait();
- }
-
- private static void CloseAllSinks()
- {
- SinkCoordinator.Tell(new SinkCoordinator.CloseAllSinks());
- }
-
- private static void StartNewSpec(IList tests)
- {
- SinkCoordinator.Tell(tests);
- }
-
- private static void ReportSpecPassFromExitCode(int nodeIndex, string nodeRole, string testName)
- {
- SinkCoordinator.Tell(new NodeCompletedSpecWithSuccess(nodeIndex, nodeRole, testName + " passed."));
- }
-
- private static void FinishSpec(IList tests, IActorRef timelineCollector)
- {
- var spec = tests.First();
- var log = timelineCollector.Ask(new TimelineLogCollectorActor.GetSpecLog(), TimeSpan.FromMinutes(1)).Result;
- SinkCoordinator.Tell(new EndSpec(spec.TestName, spec.MethodName, log));
- }
-
- private static void PublishRunnerMessage(string message)
- {
- SinkCoordinator.Tell(new SinkCoordinator.RunnerMessage(message));
- }
-
- private static void PublishToAllSinks(string message)
- {
- SinkCoordinator.Tell(message, ActorRefs.NoSender);
- }
- }
-
- internal class TcpLoggingServer : ReceiveActor
- {
- private readonly ILoggingAdapter _log = Context.GetLogger();
- private IActorRef _tcpManager = Nobody.Instance;
- private IActorRef _abortSender;
-
- public TcpLoggingServer(IActorRef sinkCoordinator)
- {
- Receive(_ => _tcpManager = Sender);
- Receive(connected =>
- {
- _log.Info($"Node connected on {Sender}");
- Sender.Tell(new Tcp.Register(Self));
- });
-
- Receive(
- closed => _log.Info($"Node disconnected on {Sender}{Environment.NewLine}"));
-
- Receive(received =>
- {
- var message = received.Data.ToString();
- sinkCoordinator.Tell(message);
- });
-
- Receive(_ =>
- {
- _abortSender = Sender;
- _tcpManager.Tell(Tcp.Unbind.Instance);
- });
- Receive(_ => _abortSender.Tell(new ListenerStopped()));
- }
-
- public class StopListener { }
- public class ListenerStopped { }
- }
-}
\ No newline at end of file
diff --git a/src/common.props b/src/common.props
index a4c47f4..297aa17 100644
--- a/src/common.props
+++ b/src/common.props
@@ -18,7 +18,7 @@
netcoreapp3.0
net472
netstandard2.0
- 4.14.0
+ 5.10.0
2.9.0
1.4.0-beta4
akka;actors;actor model;Akka;concurrency
diff --git a/update-sample-test-nuget.cmd b/update-sample-test-nuget.cmd
new file mode 100644
index 0000000..5ccaed5
--- /dev/null
+++ b/update-sample-test-nuget.cmd
@@ -0,0 +1,22 @@
+git commit -a -m "Updated package version"
+
+cd C:\Projects\Upwork\Aaron\Akka.MultiNodeTestRunner\src\Akka.MultiNodeTestRunner.VisualStudio\bin\Debug
+del /s *.nupkg
+del /s *.snupkg
+
+cd C:\Projects\Upwork\Aaron\Akka.MultiNodeTestRunner
+dotnet pack src\Akka.MultiNodeTestRunner.VisualStudio\Akka.MultiNodeTestRunner.VisualStudio.csproj
+
+cd C:\LocalNuget
+del /s *.nupkg
+
+cd C:\Projects\Upwork\Aaron\Akka.MultiNodeTestRunner\src\Akka.MultiNodeTestRunner.VisualStudio\bin\Debug
+dotnet nuget push *.nupkg --source c:\LocalNuget
+
+cd ..\..\..\Akka.MultiNodeTestRunner.SampleTests
+dotnet remove package Akka.MultiNodeTestRunner.VisualStudio
+dotnet add package Akka.MultiNodeTestRunner.VisualStudio -v 2.4.2-*
+
+cd C:\Projects\Upwork\Aaron\Akka.MultiNodeTestRunner
+
+pause
\ No newline at end of file
diff --git a/version.json b/version.json
new file mode 100644
index 0000000..b899a86
--- /dev/null
+++ b/version.json
@@ -0,0 +1,11 @@
+{
+ "version": "2.4.2-preview.{height}",
+ "publicReleaseRefSpec": [
+ "^refs/heads/master$", // we release out of master
+ "^refs/tags/v\\d+\\.\\d+", // we also release tags starting with vN.N
+ "^refs/heads/rel/*" // we also release branches starting with rel/
+ ],
+ "nugetPackageVersion": {
+ "semVer": 2
+ }
+}
diff --git a/visualstudio.xunit.ChildProcessDbgSettings b/visualstudio.xunit.ChildProcessDbgSettings
new file mode 100644
index 0000000..156463f
--- /dev/null
+++ b/visualstudio.xunit.ChildProcessDbgSettings
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file