From 20ba5ae84107168d9e83ede9ac693ee0c6731c7b Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 30 Sep 2021 02:29:23 +0700 Subject: [PATCH 1/3] Merge Master to Dev (#92) * initial commit (#1) * Post merge cleanup * Fix bash script EOL * Fix build script Co-authored-by: Aaron Stannard --- build-system/windows-release.yaml | 4 +- build.fsx | 70 ++----------------------------- 2 files changed, 7 insertions(+), 67 deletions(-) diff --git a/build-system/windows-release.yaml b/build-system/windows-release.yaml index 0d1b870..1c75500 100644 --- a/build-system/windows-release.yaml +++ b/build-system/windows-release.yaml @@ -10,13 +10,15 @@ trigger: include: - refs/tags/* +pr: none + variables: - group: signingSecrets #create this group with SECRET variables `signingUsername` and `signingPassword` - group: nugetKeys #create this group with SECRET variables `nugetKey` - name: githubConnectionName value: AkkaDotNet_Releases - name: projectName - value: Akka.MultiNodeTestRunner + value: Akka.MultiNode.TestAdapter - name: githubRepositoryName value: akkadotnet/Akka.MultiNodeTestRunner diff --git a/build.fsx b/build.fsx index ec0dd06..d855663 100644 --- a/build.fsx +++ b/build.fsx @@ -224,13 +224,7 @@ let overrideVersionSuffix (project:string) = | _ -> versionSuffix // add additional matches to publish different versions for different projects in solution Target "CreateNuget" (fun _ -> - let projects = !! "src/**/*.csproj" - -- "src/**/*Tests.csproj" // Don't publish unit tests - -- "src/**/*Tests*.csproj" - -- "src/**/*.MultiNode.TestAdapter.csproj" // Do not publish MNTR nuget packages - -- "src/**/*.MultiNode.NodeRunner.csproj" - -- "src/**/*.MultiNode.Shared.csproj" - -- "src/**/*.MultiNode.TestRunner.Shared.csproj" + let projects = !! "src/**/*.MultiNode.TestAdapter.csproj" let runSingleProject project = DotNetCli.Pack @@ -238,68 +232,13 @@ Target "CreateNuget" (fun _ -> { p with Project = project Configuration = configuration - AdditionalArgs = ["--include-symbols --no-build"] + AdditionalArgs = ["--include-symbols"] VersionSuffix = overrideVersionSuffix project OutputPath = outputNuGet }) projects |> Seq.iter (runSingleProject) ) -Target "PublishMntr" (fun _ -> - let executableProjects = !! "./src/**/Akka.MultiNode.TestAdapter.csproj" - let additionalArgs = if versionSuffix.Length > 0 then [sprintf "/p:VersionSuffix=%s" versionSuffix] else [] - - executableProjects |> Seq.iter (fun project -> - DotNetCli.Restore - (fun p -> - { p with - Project = project - AdditionalArgs = additionalArgs }) - ) - - executableProjects |> Seq.iter (fun project -> - DotNetCli.Publish - (fun p -> - { p with - Project = project - Configuration = configuration - Framework = "netstandard2.0" - VersionSuffix = versionSuffix })) -) - -Target "CreateMntrNuget" (fun _ -> - - let commonPropsVersionPrefix = XMLRead true "./src/common.props" "" "" "//Project/PropertyGroup/VersionPrefix" |> Seq.head - let versionReplacement = List.ofSeq [ "@version@", commonPropsVersionPrefix + (if (not (versionSuffix = "")) then ("-" + versionSuffix) else "") ] - - // uses the template file to create a temporary .nuspec file with the correct version - let generateNuspec (nuspecTemplatePath : string) = - let nuspecPath = nuspecTemplatePath.Replace(".template", "") - CopyFile nuspecPath nuspecTemplatePath - TemplateHelper.processTemplates versionReplacement [ nuspecPath ] - nuspecPath - - let nuspecTemplates = [ - "./src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.nuspec.template" - ] - let nuspecFiles = List.map (generateNuspec) nuspecTemplates - - let executableProjects = !! "./src/**/Akka.MultiNode.TestAdapter.csproj" - - executableProjects |> Seq.iter (fun project -> - DotNetCli.Pack - (fun p -> - { p with - Project = project - Configuration = configuration - AdditionalArgs = ["--include-symbols"] - VersionSuffix = versionSuffix - OutputPath = "\"" + outputNuGet + "\"" } ) - ) - - nuspecFiles |> Seq.iter (DeleteFile) -) - Target "PublishNuget" (fun _ -> let projects = !! "./bin/nuget/*.nupkg" let apiKey = getBuildParamOrDefault "nugetkey" "" @@ -377,15 +316,14 @@ Target "All" DoNothing Target "Nuget" DoNothing // build dependencies -"Clean" ==> "AssemblyInfo" ==> "Build" -"Build" ==> "PublishMntr" ==> "BuildRelease" +"Clean" ==> "AssemblyInfo" ==> "Build" ==> "BuildRelease" // tests dependencies "Build" ==> "RunTests" "Build" ==> "RunTestsNet" // nuget dependencies -"BuildRelease" ==> "CreateMntrNuget" ==> "CreateNuget" +"Clean" ==> "Build" ==> "CreateNuget" "CreateNuget" ==> "SignPackages" ==> "PublishNuget" ==> "Nuget" // docs From 5ccaf0ff200510cc2dd56f6cd58770e92ade282a Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Tue, 12 Oct 2021 02:05:56 +0700 Subject: [PATCH 2/3] Node runner should ignore runs that are not started by MNTR (#93) Node runner should ignore runs that are not being called by MNTR --- .../MultiNodeTestExecutorSpec.cs | 2 + .../Akka.MultiNode.TestAdapter.csproj | 1 + .../Environment/MultiNodeEnvironment.cs | 18 ---- .../Internal/NodeTest.cs | 2 +- .../MultiNodeTestAdapter.cs | 6 -- .../MultiNodeTestResult.cs | 9 +- .../MultiNodeTestRunner.cs | 94 ++++++++++++------- .../NodeRunner/Executor.cs | 12 ++- src/common.props | 2 +- 9 files changed, 80 insertions(+), 66 deletions(-) delete mode 100644 src/Akka.MultiNode.TestAdapter/Internal/Environment/MultiNodeEnvironment.cs diff --git a/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs b/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs index 85a2608..a0e2f23 100644 --- a/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs +++ b/src/Akka.MultiNode.TestAdapter.Tests/MultiNodeTestExecutorSpec.cs @@ -2,6 +2,7 @@ using Akka.MultiNode.TestAdapter.SampleTests; using Akka.MultiNode.TestAdapter.SampleTests.Metadata; using Akka.MultiNode.TestAdapter.Tests.Helpers; +using Akka.Remote.TestKit; using FluentAssertions; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Xunit; @@ -17,6 +18,7 @@ public MultiNodeTestExecutorSpec() { _sampleTestsAssemblyPath = Path.GetFullPath(SampleTestsMetadata.AssemblyFileName); File.Exists(_sampleTestsAssemblyPath).Should().BeTrue($"Assemblies with samples should exist at {_sampleTestsAssemblyPath}"); + CommandLine.Initialize(new []{"-Dmultinode.test-runner=\"multinode\""}); } [Fact] diff --git a/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj b/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj index d4408a7..96124f9 100644 --- a/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj +++ b/src/Akka.MultiNode.TestAdapter/Akka.MultiNode.TestAdapter.csproj @@ -6,6 +6,7 @@ $(NetStandardLibVersion) true true + 8.0 diff --git a/src/Akka.MultiNode.TestAdapter/Internal/Environment/MultiNodeEnvironment.cs b/src/Akka.MultiNode.TestAdapter/Internal/Environment/MultiNodeEnvironment.cs deleted file mode 100644 index 84953e9..0000000 --- a/src/Akka.MultiNode.TestAdapter/Internal/Environment/MultiNodeEnvironment.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Akka.Remote.TestKit; - -namespace Akka.MultiNode.TestAdapter.Internal.Environment -{ - /// - /// MultiNodeEnvironment - /// - public static class MultiNodeEnvironment - { - /// - /// Initializes multi-node test environment. Used by and NodeRunner. - /// - public static void Initialize() - { - System.Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, "1"); - } - } -} \ No newline at end of file diff --git a/src/Akka.MultiNode.TestAdapter/Internal/NodeTest.cs b/src/Akka.MultiNode.TestAdapter/Internal/NodeTest.cs index 5046a79..5006a9c 100644 --- a/src/Akka.MultiNode.TestAdapter/Internal/NodeTest.cs +++ b/src/Akka.MultiNode.TestAdapter/Internal/NodeTest.cs @@ -13,7 +13,7 @@ public class NodeTest public string Role { get; set; } public MultiNodeTest Test { get; set; } - public string Name => $"{Test.TestName}_node{Node}[{Role}]"; + public string Name => $"{Test.MethodName}_node{Node}[{Role}]"; } } diff --git a/src/Akka.MultiNode.TestAdapter/MultiNodeTestAdapter.cs b/src/Akka.MultiNode.TestAdapter/MultiNodeTestAdapter.cs index 416e570..e447634 100644 --- a/src/Akka.MultiNode.TestAdapter/MultiNodeTestAdapter.cs +++ b/src/Akka.MultiNode.TestAdapter/MultiNodeTestAdapter.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Xml; using Akka.MultiNode.TestAdapter.Internal; -using Akka.MultiNode.TestAdapter.Internal.Environment; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; @@ -27,11 +26,6 @@ namespace Akka.MultiNode.TestAdapter [ExtensionUri(Constants.ExecutorUriString)] public class MultiNodeTestAdapter : ITestDiscoverer, ITestExecutor { - public MultiNodeTestAdapter() - { - MultiNodeEnvironment.Initialize(); - } - /// /// Discovers the tests available from the provided container. /// diff --git a/src/Akka.MultiNode.TestAdapter/MultiNodeTestResult.cs b/src/Akka.MultiNode.TestAdapter/MultiNodeTestResult.cs index 3806c27..285e569 100644 --- a/src/Akka.MultiNode.TestAdapter/MultiNodeTestResult.cs +++ b/src/Akka.MultiNode.TestAdapter/MultiNodeTestResult.cs @@ -42,7 +42,12 @@ public TestStatus Status { { if (!string.IsNullOrWhiteSpace(Test.SkipReason)) return TestStatus.Skipped; - return NodeResults.Any(result => result.Result == TestStatus.Failed) ? TestStatus.Failed : TestStatus.Passed; + + if(NodeResults.Any(result => result.Result == TestStatus.Failed)) + return TestStatus.Failed; + if (NodeResults.Any(result => result.Result == TestStatus.Skipped)) + return TestStatus.Skipped; + return TestStatus.Passed; } } /// @@ -57,7 +62,7 @@ public TestStatus Status { /// public override string ToString() { - var sb = new StringBuilder($"Test {Test.TestName}: {Status}"); + var sb = new StringBuilder($"Test {Test.MethodName}: {Status}"); if (Test.SkipReason != null) sb.Append(" Skipped: ").Append(Test.SkipReason); foreach (var node in NodeResults) diff --git a/src/Akka.MultiNode.TestAdapter/MultiNodeTestRunner.cs b/src/Akka.MultiNode.TestAdapter/MultiNodeTestRunner.cs index 73b46b5..8d623d0 100644 --- a/src/Akka.MultiNode.TestAdapter/MultiNodeTestRunner.cs +++ b/src/Akka.MultiNode.TestAdapter/MultiNodeTestRunner.cs @@ -19,15 +19,12 @@ using System.Threading.Tasks; using Akka.Actor; using Akka.IO; -using Akka.MultiNode.TestAdapter.Helpers; using Akka.MultiNode.TestAdapter.Internal; -using Akka.MultiNode.TestAdapter.Internal.Environment; using Akka.MultiNode.TestAdapter.Internal.Persistence; using Akka.MultiNode.TestAdapter.Internal.Sinks; using Akka.MultiNode.TestAdapter.Internal.TrxReporter; using Akka.MultiNode.TestAdapter.NodeRunner; using Akka.Remote.TestKit; -using Akka.Util; using Xunit; using ErrorMessage = Xunit.Sdk.ErrorMessage; @@ -100,7 +97,6 @@ private void Initialize(string assemblyPath, MultiNodeTestRunnerOptions options) EnableAllSinks(assemblyPath, options); // Set MNTR environment for correct tests discovery - MultiNodeEnvironment.Initialize(); } public MultiNodeTestResult ExecuteSpec(MultiNodeTest test, MultiNodeTestRunnerOptions options) @@ -113,6 +109,7 @@ public MultiNodeTestResult ExecuteSpec(MultiNodeTest test, MultiNodeTestRunnerOp : _tcpLogger.Ask(TcpLoggingServer.GetBoundPort.Instance).Result; TestStarted?.Invoke(test); + Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, "1"); try { if (options.SpecNames != null && @@ -132,10 +129,19 @@ public MultiNodeTestResult ExecuteSpec(MultiNodeTest test, MultiNodeTestRunnerOp var nodes = test.Nodes; var result = RunSpec(options, test, listenPort); - if(result.Status == MultiNodeTestResult.TestStatus.Failed) - TestFailed?.Invoke(result); - else - TestPassed?.Invoke(result); + switch (result.Status) + { + case MultiNodeTestResult.TestStatus.Passed: + TestPassed?.Invoke(result); + return result; + case MultiNodeTestResult.TestStatus.Failed: + TestFailed?.Invoke(result); + return result; + case MultiNodeTestResult.TestStatus.Skipped: + TestSkipped?.Invoke(test, "Must be run using Akka.MultiNode.TestAdapter"); + return null; + } + return result; } catch (Exception e) @@ -144,6 +150,10 @@ public MultiNodeTestResult ExecuteSpec(MultiNodeTest test, MultiNodeTestRunnerOp PublishRunnerMessage(e.Message); return null; } + finally + { + Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, null); + } } /// @@ -173,17 +183,23 @@ public void Dispose() /// public static (List Tests, List Errors) DiscoverSpecs(string assemblyPath) { - MultiNodeEnvironment.Initialize(); - - using (var controller = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyPath)) + Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, "1"); + try { - using (var discovery = new Discovery(assemblyPath)) + using (var controller = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyPath)) { - controller.Find(false, discovery, TestFrameworkOptions.ForDiscovery()); - discovery.Finished.WaitOne(); - return (discovery.MultiNodeTests, discovery.Errors); + using (var discovery = new Discovery(assemblyPath)) + { + controller.Find(false, discovery, TestFrameworkOptions.ForDiscovery()); + discovery.Finished.WaitOne(); + return (discovery.MultiNodeTests, discovery.Errors); + } } } + finally + { + Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, null); + } } private List DiscoverAndRunSpecs(string assemblyPath, MultiNodeTestRunnerOptions options) @@ -226,12 +242,20 @@ private List DiscoverAndRunSpecs(string assemblyPath, Multi // Run test on several nodes and report results var result = RunSpec(options, test, listenPort); - if(result.Status == MultiNodeTestResult.TestStatus.Failed) - TestFailed?.Invoke(result); - else - TestPassed?.Invoke(result); - - testResults.Add(result); + switch (result.Status) + { + case MultiNodeTestResult.TestStatus.Failed: + TestFailed?.Invoke(result); + testResults.Add(result); + break; + case MultiNodeTestResult.TestStatus.Passed: + TestPassed?.Invoke(result); + testResults.Add(result); + break; + case MultiNodeTestResult.TestStatus.Skipped: + TestSkipped?.Invoke(test, test.SkipReason); + continue; + } } catch (Exception e) { @@ -250,7 +274,7 @@ private MultiNodeTestResult RunSpec(MultiNodeTestRunnerOptions options, MultiNod var timelineCollector = TestRunSystem.ActorOf(Props.Create(() => new TimelineLogCollectorActor())); //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, test.TestName)); + var folder = Directory.CreateDirectory(Path.Combine(options.OutputDirectory, test.MethodName)); var testOutputDir = folder.FullName; var testResult = new MultiNodeTestResult(test); @@ -270,7 +294,8 @@ private MultiNodeTestResult RunSpec(MultiNodeTestRunnerOptions options, MultiNod $@"-Dmultinode.role=""{nodeTest.Role}""", $@"-Dmultinode.listen-address={options.ListenAddress}", $@"-Dmultinode.listen-port={listenPort}", - $@"-Dmultinode.test-assembly=""{test.AssemblyPath}""" + $@"-Dmultinode.test-assembly=""{test.AssemblyPath}""", + "-Dmultinode.test-runner=\"multinode\"" }; // Configure process for node @@ -319,7 +344,7 @@ private void DumpAggregatedSpecLogs( if (result.Status == MultiNodeTestResult.TestStatus.Failed) { - var failedSpecPath = Path.GetFullPath(Path.Combine(options.OutputDirectory, options.FailedSpecsDirectory, $"{result.Test.TestName}.txt")); + var failedSpecPath = Path.GetFullPath(Path.Combine(options.OutputDirectory, options.FailedSpecsDirectory, $"{result.Test.MethodName}.txt")); var dumpFailureArtifactTask = timelineCollector.Ask(new TimelineLogCollectorActor.DumpToFile(failedSpecPath)); dumpTasks.Add(dumpFailureArtifactTask); result.Attachments.Add(new MultiNodeTestResult.Attachment{Title = "Fail log", Path = failedSpecPath}); @@ -339,9 +364,12 @@ private void WaitForNodeExit(MultiNodeTestResult result, List<(NodeTest, Process process.WaitForExit(); Console.WriteLine($"Process for test {test.Name} finished with code {process.ExitCode}"); var nodeResult = result.NodeResults.First(n => n.Index == test.Node); - nodeResult.Result = process.ExitCode == 0 - ? MultiNodeTestResult.TestStatus.Passed - : MultiNodeTestResult.TestStatus.Failed; + nodeResult.Result = process.ExitCode switch + { + 0 => MultiNodeTestResult.TestStatus.Passed, + 2 => MultiNodeTestResult.TestStatus.Skipped, + _ => MultiNodeTestResult.TestStatus.Failed + }; } } finally @@ -366,7 +394,7 @@ private Process StartNodeProcess( var nodeIndex = nodeTest.Node; var nodeRole = nodeTest.Role; var logFilePath = Path.GetFullPath(Path.Combine(specFolder.FullName, $"node{nodeIndex}__{nodeRole}__{_platformName}.txt")); - var nodeInfo = new TimelineLogCollectorActor.NodeInfo(nodeIndex, nodeRole, _platformName, nodeTest.Test.TestName); + var nodeInfo = new TimelineLogCollectorActor.NodeInfo(nodeIndex, nodeRole, _platformName, nodeTest.Test.MethodName); var fileActor = TestRunSystem.ActorOf(Props.Create(() => new FileSystemAppenderActor(logFilePath))); result.Attachments.Add(new MultiNodeTestResult.Attachment{Title = $"Node {nodeIndex} [{nodeRole}]", Path = logFilePath}); @@ -377,7 +405,7 @@ private Process StartNodeProcess( { if (p.ExitCode == 0) { - ReportSpecPassFromExitCode(nodeIndex, nodeRole, closureTest.Test.TestName); + ReportSpecPassFromExitCode(nodeIndex, nodeRole, closureTest.Test.MethodName); } }; opt.OutputDataReceived = (sender, eventArgs) => @@ -493,12 +521,8 @@ MessageSink CreateVisualizerFileSink() 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())); - } + SinkCoordinator.Tell(new SinkCoordinator.EnableSink(CreateJsonFileSink())); + SinkCoordinator.Tell(new SinkCoordinator.EnableSink(CreateVisualizerFileSink())); } private void AbortTcpLoggingServer() diff --git a/src/Akka.MultiNode.TestAdapter/NodeRunner/Executor.cs b/src/Akka.MultiNode.TestAdapter/NodeRunner/Executor.cs index 65733ac..5ddde1f 100644 --- a/src/Akka.MultiNode.TestAdapter/NodeRunner/Executor.cs +++ b/src/Akka.MultiNode.TestAdapter/NodeRunner/Executor.cs @@ -14,7 +14,6 @@ using System.Threading; using Akka.Actor; using Akka.IO; -using Akka.MultiNode.TestAdapter.Internal.Environment; using Akka.MultiNode.TestAdapter.Internal.Sinks; using Akka.Remote.TestKit; using Xunit; @@ -32,10 +31,15 @@ public int Execute(string[] args) var maxProcessWaitTimeout = TimeSpan.FromMinutes(5); IActorRef logger = null; + Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, "1"); try { CommandLine.Initialize(args); + var runner = CommandLine.GetPropertyOrDefault("multinode.test-runner", null); + if (runner != "multinode") + return 2; + var nodeIndex = CommandLine.GetInt32("multinode.index"); var nodeRole = CommandLine.GetProperty("multinode.role"); var assemblyFileName = CommandLine.GetProperty("multinode.test-assembly"); @@ -53,8 +57,6 @@ public int Execute(string[] args) var tcpClient = logger = system.ActorOf(); system.Tcp().Tell(new Tcp.Connect(listenEndpoint), tcpClient); - MultiNodeEnvironment.Initialize(); - // In NetCore, if the assembly file hasn't been touched, // XunitFrontController would fail loading external assemblies and its dependencies. @@ -182,6 +184,10 @@ public int Execute(string[] args) Environment.Exit(1); //signal failure return 1; } + finally + { + Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, null); + } void FlushLogMessages() { diff --git a/src/common.props b/src/common.props index 0714fad..921a580 100644 --- a/src/common.props +++ b/src/common.props @@ -24,7 +24,7 @@ netstandard2.0 6.1.0 2.9.0 - 1.4.26 + 1.4.27 akka;actors;actor model;Akka;concurrency From 58c270618bc8dd1618013eb515211575c1cfe88e Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Tue, 12 Oct 2021 02:43:37 +0700 Subject: [PATCH 3/3] Update RELEASE_NOTES.md for 1.0.0-beta2 release (#94) --- RELEASE_NOTES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 830c9c1..f7440d4 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,6 @@ +#### 1.0.0-beta2 October 05 2019 #### +- Fix, [node runner should ignore runs not started by MNTR](https://github.com/akkadotnet/Akka.MultiNodeTestRunner/pull/93) + #### 1.0.0-beta1 October 05 2019 #### First beta release