public override async Task ExecuteAsync(IOperationExecutionContext context) { var fileOps = context.Agent.GetService<IFileOperationsExecuter>(); var testFilePath = context.ResolvePath(this.TestFile); this.LogDebug("Test file: " + testFilePath); var exePath = context.ResolvePath(this.ExePath); this.LogDebug("Exe path: " + exePath); if (!fileOps.FileExists(testFilePath)) { this.LogError($"Test file {testFilePath} does not exist."); return; } if (!fileOps.FileExists(exePath)) { this.LogError($"NUnit runner not found at {exePath}."); return; } string outputPath; if (string.IsNullOrEmpty(this.CustomXmlOutputPath)) outputPath = context.WorkingDirectory; else outputPath = context.ResolvePath(this.CustomXmlOutputPath); this.LogDebug("Output directory: " + outputPath); var testResultsXmlFile = fileOps.CombinePath(outputPath, "TestResult.xml"); this.LogDebug("Output file: " + testResultsXmlFile); var args = this.IsNUnit3 ? $"\"{testFilePath}\" --work:\"{outputPath}\"" : $"\"{testFilePath}\" /xml:\"{outputPath}\""; if (!string.IsNullOrEmpty(this.AdditionalArguments)) { this.LogDebug("Additional arguments: " + this.AdditionalArguments); args += " " + this.AdditionalArguments; } try { this.LogDebug("Run tests"); await this.ExecuteCommandLineAsync( context, new RemoteProcessStartInfo { FileName = exePath, Arguments = args, WorkingDirectory = context.WorkingDirectory } ); this.LogDebug($"Read file: {testResultsXmlFile}"); XDocument xdoc; using (var stream = fileOps.OpenFile(testResultsXmlFile, FileMode.Open, FileAccess.Read)) { xdoc = XDocument.Load(stream); this.LogDebug("File read"); } this.LogDebug($"Parse results"); string resultsNodeName = this.IsNUnit3 ? "test-run" : "test-results"; var testResultsElement = xdoc.Element(resultsNodeName); var startTime = this.TryParseStartTime(testResultsElement); var failures = 0; using (var db = new DB.Context()) { foreach (var testCaseElement in xdoc.Descendants("test-case")) { var testName = (string)testCaseElement.Attribute("name"); // skip tests that weren't actually run if (TestCaseWasSkipped(testCaseElement)) { this.LogInformation($"NUnit test: {testName} (skipped)"); continue; } var result = GetTestCaseResult(testCaseElement); if (result == Domains.TestStatusCodes.Failed) failures++; var testDuration = this.TryParseTestTime((string)testCaseElement.Attribute("time")); this.LogInformation($"NUnit test: {testName}, Result: {Domains.TestStatusCodes.GetName(result)}, Test length: {testDuration}"); db.BuildTestResults_RecordTestResult( Execution_Id: context.ExecutionId, Group_Name: AH.NullIf(this.GroupName, string.Empty) ?? "NUnit", Test_Name: testName, TestStatus_Code: result, TestResult_Text: result == Domains.TestStatusCodes.Passed ? result : testCaseElement.ToString(), TestStarted_Date: startTime, TestEnded_Date: startTime + testDuration ); startTime += testDuration; } } if (failures > 0) this.LogError($"{0} test failures were reported."); } finally { if (string.IsNullOrEmpty(this.CustomXmlOutputPath)) { this.LogDebug($"Deleting temp output file ({testResultsXmlFile})..."); try { fileOps.DeleteFile(testResultsXmlFile); } catch { this.LogWarning($"Could not delete {testResultsXmlFile}."); } } } }
public override async Task ExecuteAsync(IOperationExecutionContext context) { var fileOps = context.Agent.GetService <IFileOperationsExecuter>(); var testFilePath = context.ResolvePath(this.TestFile); this.LogDebug("Test file: " + testFilePath); var exePath = context.ResolvePath(this.ExePath); this.LogDebug("Exe path: " + exePath); if (!fileOps.FileExists(testFilePath)) { this.LogError($"Test file {testFilePath} does not exist."); return; } if (!fileOps.FileExists(exePath)) { this.LogError($"NUnit runner not found at {exePath}."); return; } string outputFilePath; if (string.IsNullOrEmpty(this.CustomXmlOutputPath)) { outputFilePath = fileOps.CombinePath(context.WorkingDirectory, Guid.NewGuid().ToString("N") + ".xml"); } else { outputFilePath = context.ResolvePath(this.CustomXmlOutputPath); } this.LogDebug("Output file: " + outputFilePath); var args = this.IsNUnit3 ? $"\"{testFilePath}\" --result:\"{outputFilePath}\";format=nunit2" : $"\"{testFilePath}\" /xml:\"{outputFilePath}\""; if (!string.IsNullOrEmpty(this.AdditionalArguments)) { this.LogDebug("Additional arguments: " + this.AdditionalArguments); args += " " + this.AdditionalArguments; } try { await this.ExecuteCommandLineAsync( context, new RemoteProcessStartInfo { FileName = exePath, Arguments = args, WorkingDirectory = context.WorkingDirectory } ); XDocument xdoc; using (var stream = fileOps.OpenFile(outputFilePath, FileMode.Open, FileAccess.Read)) { xdoc = XDocument.Load(stream); } var testResultsElement = xdoc.Element("test-results"); var startTime = this.TryParseStartTime((string)testResultsElement.Attribute("date"), (string)testResultsElement.Attribute("time")) ?? DateTime.UtcNow; var failures = 0; using (var db = new DB.Context()) { foreach (var testCaseElement in xdoc.Descendants("test-case")) { var testName = (string)testCaseElement.Attribute("name"); // skip tests that weren't actually run if (string.Equals((string)testCaseElement.Attribute("executed"), "False", StringComparison.OrdinalIgnoreCase)) { this.LogInformation($"NUnit test: {testName} (skipped)"); continue; } var result = AH.Switch <string, string>((string)testCaseElement.Attribute("success"), StringComparer.OrdinalIgnoreCase) .Case("True", Domains.TestStatusCodes.Passed) .Case("Inconclusive", Domains.TestStatusCodes.Inconclusive) .Default(Domains.TestStatusCodes.Failed) .End(); if (result == Domains.TestStatusCodes.Failed) { failures++; } var testDuration = this.TryParseTestTime((string)testCaseElement.Attribute("time")); this.LogInformation($"NUnit test: {testName}, Result: {Domains.TestStatusCodes.GetName(result)}, Test length: {testDuration}"); db.BuildTestResults_RecordTestResult( Execution_Id: context.ExecutionId, Group_Name: AH.NullIf(this.GroupName, string.Empty) ?? "NUnit", Test_Name: testName, TestStatus_Code: result, TestResult_Text: testCaseElement.ToString(), TestStarted_Date: startTime, TestEnded_Date: startTime + testDuration ); startTime += testDuration; } } if (failures > 0) { this.LogError($"{failures} test failures were reported."); } } finally { if (string.IsNullOrEmpty(this.CustomXmlOutputPath)) { this.LogDebug($"Deleting temp output file ({outputFilePath})..."); try { fileOps.DeleteFile(outputFilePath); } catch { this.LogWarning($"Could not delete {outputFilePath}."); } } } }