Skip to content

Commit cb73ce2

Browse files
authored
Add failed logic for trx logger when TreatNoTestAsError is set to true (#2758)
* Initial implementation * changing place for outcome * Parameter send when the value is True. Tests are added * making tests only for windows * removing wrong comment
1 parent 0276237 commit cb73ce2

File tree

5 files changed

+125
-16
lines changed

5 files changed

+125
-16
lines changed

src/Microsoft.TestPlatform.Common/Utilities/RunSettingsUtilities.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,20 @@ public static int GetMaxCpuCount(RunConfiguration runConfiguration)
131131
return cpuCount;
132132
}
133133
/// <summary>
134-
/// Gets the value of FailWhenNoTestsFound parameter from runsettings file
134+
/// Gets the value of TreatNoTestsAsError parameter from runsettings file
135135
/// </summary>
136136
/// <param name="runSettings">Runsetting string value</param>
137-
/// <returns>The value of FailWhenNoTestsFound</returns>
137+
/// <returns>The value of TreatNoTestsAsError</returns>
138138
public static bool GetTreatNoTestsAsError(string runSettings)
139139
{
140-
bool failWhenNoTestFound = false;
140+
bool treatNoTestsAsError = false;
141141

142142
if (runSettings != null)
143143
{
144144
try
145145
{
146146
RunConfiguration runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runSettings);
147-
failWhenNoTestFound = GetTreatNoTestsAsError(runConfiguration);
147+
treatNoTestsAsError = GetTreatNoTestsAsError(runConfiguration);
148148
}
149149
catch (SettingsException se)
150150
{
@@ -155,7 +155,7 @@ public static bool GetTreatNoTestsAsError(string runSettings)
155155
}
156156
}
157157

158-
return failWhenNoTestFound;
158+
return treatNoTestsAsError;
159159
}
160160

161161
private static bool GetTreatNoTestsAsError(RunConfiguration runConfiguration)

src/Microsoft.TestPlatform.CrossPlatEngine/Client/TestLoggerManager.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client
2222
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
2323
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
2424
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
25-
using CommonResources = Microsoft.VisualStudio.TestPlatform.Common.Resources.Resources;
25+
using CommonResources = Common.Resources.Resources;
2626

2727
/// <summary>
2828
/// Responsible for managing logger extensions and broadcasting results
@@ -52,6 +52,11 @@ internal class TestLoggerManager : ITestLoggerManager
5252
/// </summary>
5353
private string targetFramework;
5454

55+
/// <summary>
56+
/// TreatNoTestsAsError value;
57+
/// </summary>
58+
private bool treatNoTestsAsError;
59+
5560
/// <summary>
5661
/// Test Logger Events instance which will be passed to loggers when they are initialized.
5762
/// </summary>
@@ -145,6 +150,7 @@ public void Initialize(string runSettings)
145150
// Store test run directory. This runsettings is the final runsettings merging CLI args and runsettings.
146151
this.testRunDirectory = GetResultsDirectory(runSettings);
147152
this.targetFramework = GetTargetFramework(runSettings)?.Name;
153+
this.treatNoTestsAsError = GetTreatNoTestsAsError(runSettings);
148154

149155
var loggers = XmlRunSettingsUtilities.GetLoggerRunSettings(runSettings);
150156

@@ -487,6 +493,16 @@ internal Framework GetTargetFramework(string runSettings)
487493
return targetFramework;
488494
}
489495

496+
/// <summary>
497+
/// Get TreatNoTestsAsError value of the test run
498+
/// </summary>
499+
/// <param name="runSettings"></param>
500+
/// <returns></returns>
501+
internal bool GetTreatNoTestsAsError(string runSettings)
502+
{
503+
return RunSettingsUtilities.GetTreatNoTestsAsError(runSettings);
504+
}
505+
490506
/// <summary>
491507
/// Enables sending of events to the loggers which are registered.
492508
/// </summary>
@@ -648,6 +664,13 @@ private Dictionary<string, string> UpdateLoggerParameters(Dictionary<string, str
648664
// Add default logger parameters...
649665
loggerParams[DefaultLoggerParameterNames.TestRunDirectory] = testRunDirectory;
650666
loggerParams[DefaultLoggerParameterNames.TargetFramework] = targetFramework;
667+
668+
// Add custom logger parameters
669+
if (treatNoTestsAsError)
670+
{
671+
loggerParams[Constants.TreatNoTestsAsError] = treatNoTestsAsError.ToString();
672+
}
673+
651674
return loggerParams;
652675
}
653676

src/Microsoft.TestPlatform.Extensions.TrxLogger/TrxLogger.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ namespace Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger
2020
using System.Globalization;
2121
using System.IO;
2222
using System.Text;
23-
using System.Threading;
2423
using System.Xml;
24+
using ObjectModelConstants = ObjectModel.Constants;
2525
using TrxLoggerConstants = Microsoft.TestPlatform.Extensions.TrxLogger.Utility.Constants;
2626
using TrxLoggerObjectModel = Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
27-
using TrxLoggerResources = Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger.Resources.TrxResource;
27+
using TrxLoggerResources = Resources.TrxResource;
2828

2929
/// <summary>
3030
/// Logger for Generating TRX
@@ -65,13 +65,13 @@ internal TrxLogger(IFileHelper fileHelper, TrxFileHelper trxFileHelper)
6565
// The converter class
6666
private Converter converter;
6767

68-
private TrxLoggerObjectModel.TestRun testRun;
69-
private ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestResult> results;
70-
private ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestElement> testElements;
68+
private TestRun testRun;
69+
private ConcurrentDictionary<Guid, ITestResult> results;
70+
private ConcurrentDictionary<Guid, ITestElement> testElements;
7171
private ConcurrentDictionary<Guid, TestEntry> entries;
7272

7373
// Caching results and inner test entries for constant time lookup for inner parents.
74-
private ConcurrentDictionary<Guid, TrxLoggerObjectModel.ITestResult> innerResults;
74+
private ConcurrentDictionary<Guid, ITestResult> innerResults;
7575
private ConcurrentDictionary<Guid, TestEntry> innerTestEntries;
7676

7777
private readonly TrxFileHelper trxFileHelper;
@@ -82,7 +82,7 @@ internal TrxLogger(IFileHelper fileHelper, TrxFileHelper trxFileHelper)
8282
private StringBuilder runLevelStdOut;
8383

8484
// List of run level errors and warnings generated. These are logged in the Trx in the Results Summary.
85-
private List<TrxLoggerObjectModel.RunInfo> runLevelErrorsAndWarnings;
85+
private List<RunInfo> runLevelErrorsAndWarnings;
8686

8787
private TrxLoggerObjectModel.TestOutcome testRunOutcome = TrxLoggerObjectModel.TestOutcome.Passed;
8888

@@ -230,10 +230,11 @@ internal TrxLoggerObjectModel.TestOutcome TestResultOutcome
230230
/// </param>
231231
internal void TestMessageHandler(object sender, TestRunMessageEventArgs e)
232232
{
233-
ValidateArg.NotNull<object>(sender, "sender");
234-
ValidateArg.NotNull<TestRunMessageEventArgs>(e, "e");
233+
ValidateArg.NotNull(sender, "sender");
234+
ValidateArg.NotNull(e, "e");
235235

236236
RunInfo runMessage;
237+
237238
switch (e.Level)
238239
{
239240
case TestMessageLevel.Informational:
@@ -263,7 +264,7 @@ internal void TestMessageHandler(object sender, TestRunMessageEventArgs e)
263264
/// <param name="e">
264265
/// The eventArgs.
265266
/// </param>
266-
internal void TestResultHandler(object sender, ObjectModel.Logging.TestResultEventArgs e)
267+
internal void TestResultHandler(object sender, TestResultEventArgs e)
267268
{
268269
// Create test run
269270
if (this.testRun == null)
@@ -363,6 +364,8 @@ internal void TestRunCompleteHandler(object sender, TestRunCompleteEventArgs e)
363364
this.testRunOutcome = TrxLoggerObjectModel.TestOutcome.Completed;
364365
}
365366

367+
testRunOutcome = changeTestOutcomeIfNecessary(testRunOutcome);
368+
366369
List<string> errorMessages = new List<string>();
367370
List<CollectorDataEntry> collectorEntries = this.converter.ToCollectionEntries(e.AttachmentSets, this.testRun, this.testResultsDirPath);
368371
IList<string> resultFiles = this.converter.ToResultFiles(e.AttachmentSets, this.testRun, this.testResultsDirPath, errorMessages);
@@ -760,6 +763,19 @@ private TestEntry GetTestEntry(Guid executionId)
760763
return testEntry;
761764
}
762765

766+
private TrxLoggerObjectModel.TestOutcome changeTestOutcomeIfNecessary (TrxLoggerObjectModel.TestOutcome outcome)
767+
{
768+
// If no tests discovered/executed and TreatNoTestsAsError was set to True
769+
// We will return ResultSummary as Failed
770+
// Note : we only send the value of TreatNoTestsAsError if it is "True"
771+
if (totalTests == 0 && parametersDictionary.ContainsKey(ObjectModelConstants.TreatNoTestsAsError))
772+
{
773+
outcome = TrxLoggerObjectModel.TestOutcome.Failed;
774+
}
775+
776+
return outcome;
777+
}
778+
763779
#endregion
764780
}
765781
}

src/Microsoft.TestPlatform.ObjectModel/Constants.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ public static class Constants
115115
/// </summary>
116116
public const string LoggerConfigurationNameLower = "configuration";
117117

118+
/// <summary>
119+
/// Name of TreatNoTestsAsError parameter
120+
/// </summary>
121+
public const string TreatNoTestsAsError = "TreatNoTestsAsError";
122+
118123
/// <summary>
119124
/// Name of RunConfiguration settings node in RunSettings.
120125
/// </summary>

test/Microsoft.TestPlatform.AcceptanceTests/LoggerTests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,54 @@ public void HtmlLoggerWithExecutorUriShouldProperlyOverwriteFile(RunnerInfo runn
131131
TryRemoveDirectory(testResultsDirectory);
132132
}
133133

134+
[TestMethod]
135+
[TestCategory("Windows-Review")]
136+
[NetFullTargetFrameworkDataSource]
137+
public void TrxLoggerResultSummaryOutcomeValueShouldBeFailedIfNoTestsExecutedAndTreatNoTestsAsErrorIsTrue(RunnerInfo runnerInfo)
138+
{
139+
SetTestEnvironment(this.testEnvironment, runnerInfo);
140+
141+
var arguments = PrepareArguments(this.GetSampleTestAssembly(), this.GetTestAdapterPath(), string.Empty, this.FrameworkArgValue, runnerInfo.InIsolationValue);
142+
var trxFileName = "TrxLogger.trx";
143+
144+
arguments = string.Concat(arguments, $" /logger:\"trx;LogFileName={trxFileName}\"");
145+
146+
// Setting /TestCaseFilter to the test name, which does not exists in the assembly, so we will have 0 tests executed
147+
arguments = string.Concat(arguments, " /TestCaseFilter:TestNameThatMatchesNoTestInTheAssembly");
148+
arguments = string.Concat(arguments, " -- RunConfiguration.TreatNoTestsAsError=true");
149+
150+
this.InvokeVsTest(arguments);
151+
152+
var trxLogFilePath = Path.Combine(Directory.GetCurrentDirectory(), "TestResults", trxFileName);
153+
string outcomeValue = GetElementAtributeValueFromTrx(trxLogFilePath, "ResultSummary", "outcome");
154+
155+
Assert.AreEqual("Failed", outcomeValue);
156+
}
157+
158+
[TestMethod]
159+
[TestCategory("Windows-Review")]
160+
[NetFullTargetFrameworkDataSource]
161+
public void TrxLoggerResultSummaryOutcomeValueShouldNotChangeIfNoTestsExecutedAndTreatNoTestsAsErrorIsFalse(RunnerInfo runnerInfo)
162+
{
163+
SetTestEnvironment(this.testEnvironment, runnerInfo);
164+
165+
var arguments = PrepareArguments(this.GetSampleTestAssembly(), this.GetTestAdapterPath(), string.Empty, this.FrameworkArgValue, runnerInfo.InIsolationValue);
166+
var trxFileName = "TrxLogger.trx";
167+
168+
arguments = string.Concat(arguments, $" /logger:\"trx;LogFileName={trxFileName}\"");
169+
170+
// Setting /TestCaseFilter to the test name, which does not exists in the assembly, so we will have 0 tests executed
171+
arguments = string.Concat(arguments, " /TestCaseFilter:TestNameThatMatchesNoTestInTheAssembly");
172+
arguments = string.Concat(arguments, " -- RunConfiguration.TreatNoTestsAsError=false");
173+
174+
this.InvokeVsTest(arguments);
175+
176+
var trxLogFilePath = Path.Combine(Directory.GetCurrentDirectory(), "TestResults", trxFileName);
177+
string outcomeValue = GetElementAtributeValueFromTrx(trxLogFilePath, "ResultSummary", "outcome");
178+
179+
Assert.AreEqual("Completed", outcomeValue);
180+
}
181+
134182
private bool IsValidXml(string xmlFilePath)
135183
{
136184
try
@@ -166,5 +214,22 @@ private void IsFileAndContentEqual(string filePath)
166214
StringAssert.Contains(filePathContent, str);
167215
}
168216
}
217+
218+
private static string GetElementAtributeValueFromTrx(string trxFileName, string fieldName, string attributeName)
219+
{
220+
using (FileStream file = File.OpenRead(trxFileName))
221+
using (XmlReader reader = XmlReader.Create(file))
222+
{
223+
while (reader.Read())
224+
{
225+
if (reader.Name.Equals(fieldName) && reader.NodeType == XmlNodeType.Element && reader.HasAttributes)
226+
{
227+
return reader.GetAttribute(attributeName);
228+
}
229+
}
230+
}
231+
232+
return null;
233+
}
169234
}
170235
}

0 commit comments

Comments
 (0)