[xharness] Add support for running the generator tests in .NET mode.

This also meant adding support for running .NET tests in xharness. Some
refactoring was done to extract common code to shared members, in order to
avoid duplicating a lot of code.
This commit is contained in:
Rolf Bjarne Kvinge 2020-03-09 12:56:38 +01:00
Родитель 7a1a8bbf0b
Коммит 1fc2f8e3c2
9 изменённых файлов: 171 добавлений и 56 удалений

Просмотреть файл

@ -740,6 +740,7 @@ namespace Xharness.Jenkins
"src/generator.cs", "src/generator.cs",
"src/generator-", "src/generator-",
"src/Makefile.generator", "src/Makefile.generator",
"tests/bgen",
"tests/generator", "tests/generator",
"tests/common", "tests/common",
}; };
@ -1093,11 +1094,28 @@ namespace Xharness.Jenkins
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "generator", "generator-tests.csproj"))), TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "generator", "generator-tests.csproj"))),
Platform = TestPlatform.iOS, Platform = TestPlatform.iOS,
TestName = "Generator tests", TestName = "Generator tests",
Mode = "NUnit",
Timeout = TimeSpan.FromMinutes (10), Timeout = TimeSpan.FromMinutes (10),
Ignored = !IncludeBtouch, Ignored = !IncludeBtouch,
}; };
Tasks.Add (runGenerator); Tasks.Add (runGenerator);
var buildDotNetGenerator = new DotNetBuildTask {
Jenkins = this,
TestProject = new TestProject (Path.GetFullPath (Path.Combine (Harness.RootDirectory, "bgen", "bgen-tests.csproj"))),
SpecifyPlatform = false,
SpecifyConfiguration = false,
Platform = TestPlatform.iOS,
};
var runDotNetGenerator = new DotNetTestTask (buildDotNetGenerator) {
TestProject = buildDotNetGenerator.TestProject,
Platform = TestPlatform.iOS,
TestName = "Generator tests",
Mode = ".NET",
Ignored = !IncludeBtouch,
};
Tasks.Add (runDotNetGenerator);
var run_mmp = new MakeTask var run_mmp = new MakeTask
{ {
Jenkins = this, Jenkins = this,
@ -1748,6 +1766,7 @@ namespace Xharness.Jenkins
var allNUnitTasks = new List<NUnitExecuteTask> (); var allNUnitTasks = new List<NUnitExecuteTask> ();
var allMakeTasks = new List<MakeTask> (); var allMakeTasks = new List<MakeTask> ();
var allDeviceTasks = new List<RunDeviceTask> (); var allDeviceTasks = new List<RunDeviceTask> ();
var allDotNetTestTasks = new List<DotNetTestTask> ();
foreach (var task in Tasks) { foreach (var task in Tasks) {
var aggregated = task as AggregatedRunSimulatorTask; var aggregated = task as AggregatedRunSimulatorTask;
if (aggregated != null) { if (aggregated != null) {
@ -1779,6 +1798,11 @@ namespace Xharness.Jenkins
continue; continue;
} }
if (task is DotNetTestTask dotnet) {
allDotNetTestTasks.Add (dotnet);
continue;
}
throw new NotImplementedException (); throw new NotImplementedException ();
} }
@ -1789,6 +1813,7 @@ namespace Xharness.Jenkins
allTasks.AddRange (allNUnitTasks); allTasks.AddRange (allNUnitTasks);
allTasks.AddRange (allMakeTasks); allTasks.AddRange (allMakeTasks);
allTasks.AddRange (allDeviceTasks); allTasks.AddRange (allDeviceTasks);
allTasks.AddRange (allDotNetTestTasks);
} }
var failedTests = allTasks.Where ((v) => v.Failed); var failedTests = allTasks.Where ((v) => v.Failed);

Просмотреть файл

@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace Xharness.Jenkins.TestTasks {
class DotNetBuildTask : MSBuildTask {
protected override string ToolName {
get { return "dotnet"; }
}
protected override List<string> ToolArguments {
get {
var args = base.ToolArguments;
// 'dotnet build' takes almost the same arguments as 'msbuild', so just massage a little bit.
args.Remove ("--");
args.Insert (0, "build");
return args;
}
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Xamarin.Utils;
using Xharness.Execution;
using Xharness.Logging;
namespace Xharness.Jenkins.TestTasks {
class DotNetTestTask : RunTestTask {
public DotNetTestTask (DotNetBuildTask build_task)
: base (build_task)
{
}
protected override async Task RunTestAsync ()
{
using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) {
var trx = Logs.Create ($"results-{Timestamp}.trx", LogType.TrxLog.ToString ());
var html = Logs.Create ($"results-{Timestamp}.html", LogType.HtmlLog.ToString ());
var args = new List<string> {
"test",
BuildTask.ProjectFile,
"--results-directory:" + Logs.Directory,
"--logger:console;verbosity=detailed",
"--logger:trx;LogFileName=" + Path.GetFileName (trx.FullPath),
"--logger:html;LogFileName=" + Path.GetFileName (html.FullPath)
};
await ExecuteProcessAsync ("dotnet", args);
}
}
}
}

Просмотреть файл

@ -13,26 +13,37 @@ namespace Xharness.Jenkins.TestTasks
{ {
public ILog BuildLog; public ILog BuildLog;
protected virtual string ToolName {
get { return Harness.XIBuildPath; }
}
protected virtual List<string> ToolArguments {
get {
var binlogPath = BuildLog.FullPath.Replace (".txt", ".binlog");
var args = new List<string> ();
args.Add ("--");
args.Add ("/verbosity:diagnostic");
args.Add ($"/bl:{binlogPath}");
if (SpecifyPlatform)
args.Add ($"/p:Platform={ProjectPlatform}");
if (SpecifyConfiguration)
args.Add ($"/p:Configuration={ProjectConfiguration}");
args.Add (ProjectFile);
return args;
}
}
protected override async Task ExecuteAsync () protected override async Task ExecuteAsync ()
{ {
using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) { using (var resource = await NotifyAndAcquireDesktopResourceAsync ()) {
BuildLog = Logs.Create ($"build-{Platform}-{Timestamp}.txt", LogType.BuildLog.ToString ()); BuildLog = Logs.Create ($"build-{Platform}-{Timestamp}.txt", LogType.BuildLog.ToString ());
var binlogPath = BuildLog.FullPath.Replace (".txt", ".binlog");
await RestoreNugetsAsync (BuildLog, resource, useXIBuild: true); await RestoreNugetsAsync (BuildLog, resource, useXIBuild: true);
using (var xbuild = new Process ()) { using (var xbuild = new Process ()) {
xbuild.StartInfo.FileName = Harness.XIBuildPath; xbuild.StartInfo.FileName = ToolName;
var args = new List<string> (); xbuild.StartInfo.Arguments = StringUtils.FormatArguments (ToolArguments);
args.Add ("--");
args.Add ("/verbosity:diagnostic");
args.Add ($"/bl:{binlogPath}");
if (SpecifyPlatform)
args.Add ($"/p:Platform={ProjectPlatform}");
if (SpecifyConfiguration)
args.Add ($"/p:Configuration={ProjectConfiguration}");
args.Add (ProjectFile);
xbuild.StartInfo.Arguments = StringUtils.FormatArguments (args);
SetEnvironmentVariables (xbuild); SetEnvironmentVariables (xbuild);
xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null; xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null;
LogEvent (BuildLog, "Building {0} ({1})", TestName, Mode); LogEvent (BuildLog, "Building {0} ({1})", TestName, Mode);

Просмотреть файл

@ -17,11 +17,8 @@ namespace Xharness.Jenkins.TestTasks
{ {
public string TestLibrary; public string TestLibrary;
public string TestExecutable; public string TestExecutable;
public string WorkingDirectory;
public bool ProduceHtmlReport = true; public bool ProduceHtmlReport = true;
public bool InProcess; public bool InProcess;
public TimeSpan Timeout = TimeSpan.FromMinutes (10);
IProcessManager ProcessManager { get; set; } = new ProcessManager ();
public NUnitExecuteTask (BuildToolTask build_task) public NUnitExecuteTask (BuildToolTask build_task)
: base (build_task) : base (build_task)
@ -120,45 +117,22 @@ namespace Xharness.Jenkins.TestTasks
var xmlLog = Logs.CreateFile ($"log-{Timestamp}.xml", LogType.XmlLog.ToString ()); var xmlLog = Logs.CreateFile ($"log-{Timestamp}.xml", LogType.XmlLog.ToString ());
var log = Logs.Create ($"execute-{Timestamp}.txt", LogType.ExecutionLog.ToString ()); var log = Logs.Create ($"execute-{Timestamp}.txt", LogType.ExecutionLog.ToString ());
FindNUnitConsoleExecutable (log); FindNUnitConsoleExecutable (log);
using (var proc = new Process ()) {
proc.StartInfo.WorkingDirectory = WorkingDirectory; var args = new List<string> ();
proc.StartInfo.FileName = Harness.XIBuildPath; args.Add ("-t");
var args = new List<string> (); args.Add ("--");
args.Add ("-t"); args.Add (Path.GetFullPath (TestExecutable));
args.Add ("--"); args.Add (Path.GetFullPath (TestLibrary));
args.Add (Path.GetFullPath (TestExecutable)); if (IsNUnit3) {
args.Add (Path.GetFullPath (TestLibrary)); args.Add ("-result=" + xmlLog + ";format=nunit2");
if (IsNUnit3) { args.Add ("--labels=All");
args.Add ("-result=" + xmlLog + ";format=nunit2"); if (InProcess)
args.Add ("--labels=All"); args.Add ("--inprocess");
if (InProcess) } else {
args.Add ("--inprocess"); args.Add ("-xml=" + xmlLog);
} else { args.Add ("-labels");
args.Add ("-xml=" + xmlLog);
args.Add ("-labels");
}
proc.StartInfo.Arguments = StringUtils.FormatArguments (args);
SetEnvironmentVariables (proc);
foreach (DictionaryEntry de in proc.StartInfo.EnvironmentVariables)
log.WriteLine ($"export {de.Key}={de.Value}");
Jenkins.MainLog.WriteLine ("Executing {0} ({1})", TestName, Mode);
if (!Harness.DryRun) {
ExecutionResult = TestExecutingResult.Running;
var result = await ProcessManager.RunAsync (proc, log, Timeout);
if (result.TimedOut) {
FailureMessage = $"Execution timed out after {Timeout.TotalMinutes} minutes.";
log.WriteLine (FailureMessage);
ExecutionResult = TestExecutingResult.TimedOut;
} else if (result.Succeeded) {
ExecutionResult = TestExecutingResult.Succeeded;
} else {
ExecutionResult = TestExecutingResult.Failed;
FailureMessage = $"Execution failed with exit code {result.ExitCode}";
}
}
Jenkins.MainLog.WriteLine ("Executed {0} ({1})", TestName, Mode);
} }
await ExecuteProcessAsync (log, Harness.XIBuildPath, args);
if (ProduceHtmlReport) { if (ProduceHtmlReport) {
try { try {

Просмотреть файл

@ -1,6 +1,11 @@
using System.Collections.Generic; using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xamarin.Utils;
using Xharness.Execution;
using Xharness.Logging; using Xharness.Logging;
namespace Xharness.Jenkins.TestTasks namespace Xharness.Jenkins.TestTasks
@ -8,7 +13,10 @@ namespace Xharness.Jenkins.TestTasks
internal abstract class RunTestTask : TestTask internal abstract class RunTestTask : TestTask
{ {
public readonly BuildToolTask BuildTask; public readonly BuildToolTask BuildTask;
public TimeSpan Timeout = TimeSpan.FromMinutes (10);
public double TimeoutMultiplier { get; set; } = 1; public double TimeoutMultiplier { get; set; } = 1;
IProcessManager ProcessManager { get; } = new ProcessManager ();
public string WorkingDirectory;
public RunTestTask (BuildToolTask build_task) public RunTestTask (BuildToolTask build_task)
{ {
@ -105,5 +113,41 @@ namespace Xharness.Jenkins.TestTasks
base.Reset (); base.Reset ();
BuildTask.Reset (); BuildTask.Reset ();
} }
protected Task ExecuteProcessAsync (string filename, List<string> arguments)
{
return ExecuteProcessAsync (null, filename, arguments);
}
protected async Task ExecuteProcessAsync (ILog log, string filename, List<string> arguments)
{
if (log == null)
log = Logs.Create ($"execute-{Timestamp}.txt", LogType.ExecutionLog.ToString ());
using var proc = new Process ();
proc.StartInfo.FileName = filename;
proc.StartInfo.Arguments = StringUtils.FormatArguments (arguments);
if (!string.IsNullOrEmpty (WorkingDirectory))
proc.StartInfo.WorkingDirectory = WorkingDirectory;
SetEnvironmentVariables (proc);
foreach (DictionaryEntry de in proc.StartInfo.EnvironmentVariables)
log.WriteLine ($"export {de.Key}={de.Value}");
Jenkins.MainLog.WriteLine ("Executing {0} ({1})", TestName, Mode);
if (!Harness.DryRun) {
ExecutionResult = TestExecutingResult.Running;
var result = await ProcessManager.RunAsync (proc, log, Timeout);
if (result.TimedOut) {
FailureMessage = $"Execution timed out after {Timeout.TotalMinutes} minutes.";
log.WriteLine (FailureMessage);
ExecutionResult = TestExecutingResult.TimedOut;
} else if (result.Succeeded) {
ExecutionResult = TestExecutingResult.Succeeded;
} else {
ExecutionResult = TestExecutingResult.Failed;
FailureMessage = $"Execution failed with exit code {result.ExitCode}";
}
}
Jenkins.MainLog.WriteLine ("Executed {0} ({1})", TestName, Mode);
}
} }
} }

Просмотреть файл

@ -7,9 +7,6 @@ namespace Xharness.Jenkins.TestTasks
{ {
class RunXtroTask : MacExecuteTask class RunXtroTask : MacExecuteTask
{ {
public string WorkingDirectory;
public RunXtroTask (BuildToolTask build_task) : base (build_task) public RunXtroTask (BuildToolTask build_task) : base (build_task)
{ {
} }

Просмотреть файл

@ -14,6 +14,8 @@ namespace Xharness.Logging {
TestLog, TestLog,
ExtensionTestLog, ExtensionTestLog,
ExecutionLog, ExecutionLog,
TrxLog,
HtmlLog,
} }
public static class LogTypeExtensions { public static class LogTypeExtensions {
@ -37,6 +39,10 @@ namespace Xharness.Logging {
return "Extension test log"; return "Extension test log";
case LogType.ExecutionLog: case LogType.ExecutionLog:
return "Execution log"; return "Execution log";
case LogType.TrxLog:
return "Test log (trx)";
case LogType.HtmlLog:
return "Test log (html)";
default: default:
throw new ArgumentException ($"Unknown type for {nameof (type)}"); throw new ArgumentException ($"Unknown type for {nameof (type)}");
} }

Просмотреть файл

@ -10,6 +10,7 @@
<RootNamespace>xharness</RootNamespace> <RootNamespace>xharness</RootNamespace>
<AssemblyName>xharness</AssemblyName> <AssemblyName>xharness</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<LangVersion>8.0</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -145,6 +146,8 @@
<Compile Include="Listeners\SimpleListenerFactory.cs" /> <Compile Include="Listeners\SimpleListenerFactory.cs" />
<Compile Include="Execution\IProcessManager.cs" /> <Compile Include="Execution\IProcessManager.cs" />
<Compile Include="Execution\ProcessManager.cs" /> <Compile Include="Execution\ProcessManager.cs" />
<Compile Include="Jenkins\TestTasks\DotNetTestTask.cs" />
<Compile Include="Jenkins\TestTasks\DotNetBuildTask.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="BCLTestImporter\" /> <Folder Include="BCLTestImporter\" />