From b8c948b063402d42ec513084c8b8f4628c2f3993 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Tue, 1 Aug 2017 13:56:28 +0700 Subject: [PATCH] Add initial cross-platform spec support - Change build script for Net Core MNTR, copy node runner net and net core binaries to mntr/runner --- build.fsx | 51 ++++++++++ .../Sinks/TeamCityMessageSinkActor.cs | 6 +- src/core/Akka.MultiNodeTestRunner/Program.cs | 94 +++++++++++++++---- src/core/Akka.NodeTestRunner/Program.cs | 12 ++- 4 files changed, 141 insertions(+), 22 deletions(-) diff --git a/build.fsx b/build.fsx index c786b275067..cb31039f083 100644 --- a/build.fsx +++ b/build.fsx @@ -78,6 +78,17 @@ Target "Build" (fun _ -> Project = solution Configuration = configuration AdditionalArgs = additionalArgs }) + + let sourceBasePath = __SOURCE_DIRECTORY__ @@ "src" @@ "core" + let ntrBasePath = sourceBasePath @@ "Akka.NodeTestRunner" @@ "bin" @@ "Release" + let ntrNetPath = ntrBasePath @@ "net452" + let ntrNetCorePath = ntrBasePath @@ "netcoreapp1.1" + let mntrPath = sourceBasePath @@ "Akka.MultiNodeTestRunner" @@ "bin" @@ "Release" @@ "netcoreapp1.1" + let copyNtrNetToMntrTargetPath = mntrPath @@ "runner" @@ "net" + let copyNtrNetCoreToMntrTargetPath = mntrPath @@ "runner" @@ "netcore" + + CopyDir (copyNtrNetToMntrTargetPath) (ntrNetPath) allFiles + CopyDir (copyNtrNetCoreToMntrTargetPath) (ntrNetCorePath) allFiles ) //-------------------------------------------------------------------------------- @@ -194,6 +205,46 @@ Target "MultiNodeTestsNetCore" (fun _ -> multiNodeTestAssemblies |> Seq.iter (runMultiNodeSpec) ) +Target "MultiNodeTestsMultiPlatform" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + let multiNodeTestPath = findToolInSubPath "Akka.MultiNodeTestRunner.dll" (currentDirectory @@ "src" @@ "core" @@ "Akka.MultiNodeTestRunner" @@ "bin" @@ "Release" @@ "netcoreapp1.1") + + let multiNodeTestAssemblies = + match getBuildParamOrDefault "incremental" "" with + | "true" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalNetCoreMNTRTests() |> Seq.map (fun x -> printfn "\t%s" x; x) + | "experimental" -> log "The following MNTR specs would be run under Incremental Test config..." + getIncrementalNetCoreMNTRTests() |> Seq.iter log + getAllMntrTestNetCoreAssemblies() + | _ -> log "All test projects will be run" + getAllMntrTestNetCoreAssemblies() + + printfn "Using MultiNodeTestRunner: %s" multiNodeTestPath + + let runMultiNodeSpec assembly = + match assembly with + | null -> () + | _ -> + let spec = getBuildParam "spec" + + let args = StringBuilder() + |> append multiNodeTestPath + |> append assembly + |> append "-Dmultinode.teamcity=true" + |> append "-Dmultinode.enable-filesink=on" + |> append (sprintf "-Dmultinode.output-directory=\"%s\"" outputMultiNode) + |> append "-Dmultinode.platform=multi" + |> appendIfNotNullOrEmpty spec "-Dmultinode.spec=" + |> toText + + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- (Path.GetDirectoryName (FullName multiNodeTestPath)) + info.Arguments <- args) (System.TimeSpan.FromMinutes 60.0) (* This is a VERY long running task. *) + if result <> 0 then failwithf "MultiNodeTestRunner failed. %s %s" multiNodeTestPath args + + multiNodeTestAssemblies |> Seq.iter (runMultiNodeSpec) +) Target "MultiNodeTests" (fun _ -> ActivateFinalTarget "KillCreatedProcesses" diff --git a/src/core/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs b/src/core/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs index 347f70f695e..a2042df64c8 100644 --- a/src/core/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs +++ b/src/core/Akka.MultiNodeTestRunner.Shared/Sinks/TeamCityMessageSinkActor.cs @@ -67,16 +67,20 @@ protected override void HandleNodeMessageFragment(LogMessageFragmentForNode logM protected override void HandleNodeSpecPass(NodeCompletedSpecWithSuccess nodeSuccess) { + Console.ForegroundColor = ConsoleColor.Green; _teamCityTestWriter?.WriteStdOutput( $"[NODE{nodeSuccess.NodeIndex}:{nodeSuccess.NodeRole}][{DateTime.UtcNow.ToShortTimeString()}]: SPEC PASSED: {nodeSuccess.Message}"); - + Console.ResetColor(); + base.HandleNodeSpecPass(nodeSuccess); } protected override void HandleNodeSpecFail(NodeCompletedSpecWithFail nodeFail) { + Console.ForegroundColor = ConsoleColor.Red; _teamCityTestWriter?.WriteFailed( $"[NODE{nodeFail.NodeIndex}:{nodeFail.NodeRole}][{DateTime.UtcNow.ToShortTimeString()}]: SPEC FAILED: {nodeFail.Message}", ""); + Console.ResetColor(); base.HandleNodeSpecFail(nodeFail); } diff --git a/src/core/Akka.MultiNodeTestRunner/Program.cs b/src/core/Akka.MultiNodeTestRunner/Program.cs index 1b05fea104d..db553854414 100644 --- a/src/core/Akka.MultiNodeTestRunner/Program.cs +++ b/src/core/Akka.MultiNodeTestRunner/Program.cs @@ -37,8 +37,14 @@ namespace Akka.MultiNodeTestRunner /// class Program { - protected static ActorSystem TestRunSystem; + private static HashSet _validNetCorePlatform = new HashSet + { + "net", + "netcore", + "multi" + }; + protected static ActorSystem TestRunSystem; protected static IActorRef SinkCoordinator; /// @@ -47,6 +53,7 @@ class Program protected static string OutputDirectory; protected static bool TeamCityFormattingOn; + protected static bool MultiPlatform; /// /// MultiNodeTestRunner takes the following : @@ -128,9 +135,9 @@ static void Main(string[] args) var platform = CommandLine.GetPropertyOrDefault("multinode.platform", "net"); #if CORECLR - if (platform != "net" && platform != "netcore") + if (!_validNetCorePlatform.Contains(platform)) { - throw new Exception($"Target platform not supported: {platform}. Supported platforms are net and netcore"); + throw new Exception($"Target platform not supported: {platform}. Supported platforms are net, netcore and multi"); } #else if (platform != "net") @@ -146,7 +153,6 @@ static void Main(string[] args) 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. @@ -157,11 +163,19 @@ static void Main(string[] args) { try { - assembly = Assembly.Load(new AssemblyName(asm.FullName)); + Assembly.Load(new AssemblyName(asm.FullName)); } catch (Exception) { - assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(basePath, asm.Name + ".dll")); + 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 @@ -197,11 +211,16 @@ static void Main(string[] args) PublishRunnerMessage($"Starting test {test.Value.First().MethodName}"); StartNewSpec(test.Value); +#if CORECLR + var ntrBasePath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "Akka.NodeTestRunner", "bin", "Release")); + var ntrNetPath = Path.Combine(AppContext.BaseDirectory, "runner", "net", "Akka.NodeTestRunner.exe"); + var ntrNetCorePath = Path.Combine(AppContext.BaseDirectory, "runner", "netcore", "Akka.NodeTestRunner.dll"); + var alternateIndex = 0; +#endif 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} ") @@ -210,33 +229,65 @@ static void Main(string[] args) .Append($@"-Dmultinode.index={nodeTest.Node - 1} ") .Append($@"-Dmultinode.role=""{nodeTest.Role}"" ") .Append($@"-Dmultinode.listen-address={listenAddress} ") - .Append($@"-Dmultinode.listen-port={listenPort}"); + .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; + case "multi": + if (alternateIndex % 2 == 0) + { + fileName = ntrNetPath; + sbArguments.Insert(0, $@" -Dmultinode.test-assembly=""{ChangeDllPathPlatform(assemblyPath, "net452")}"" "); + } + else + { + fileName = "dotnet"; + sbArguments.Insert(0, $@" -Dmultinode.test-assembly=""{ChangeDllPathPlatform(assemblyPath, "netcoreapp1.1")}"" "); + sbArguments.Insert(0, ntrNetCorePath); + } + ++alternateIndex; + 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"; - var ntrPath = Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "Akka.NodeTestRunner", "bin", "Release", "netcoreapp1.1", "Akka.NodeTestRunner.dll"); - process.StartInfo.Arguments = Path.GetFullPath(ntrPath) + " " + 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)); var logFilePath = Path.Combine(folder.FullName, $"node{nodeIndex}__{nodeRole}__{platform}.txt"); @@ -300,7 +351,7 @@ static void Main(string[] args) } } } - + CloseAllSinks(); //Block until all Sinks have been terminated. @@ -313,6 +364,11 @@ static void Main(string[] args) 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; diff --git a/src/core/Akka.NodeTestRunner/Program.cs b/src/core/Akka.NodeTestRunner/Program.cs index f93883cfc01..41f39158b52 100644 --- a/src/core/Akka.NodeTestRunner/Program.cs +++ b/src/core/Akka.NodeTestRunner/Program.cs @@ -59,11 +59,19 @@ static int Main(string[] args) { try { - assembly = Assembly.Load(new AssemblyName(asm.FullName)); + Assembly.Load(new AssemblyName(asm.FullName)); } catch (Exception) { - assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(basePath, asm.Name + ".dll")); + 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