Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runsettings compat fix with testsettings #1364

Merged
merged 1 commit into from
Jan 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,7 @@ public static DataCollectionRunSettings GetDataCollectionRunSettings(string runS
reader.ReadToNextElement();

// Read till we reach DC element or reach EOF
while (!string.Equals(reader.Name, Constants.DataCollectionRunSettingsName)
&&
!reader.EOF)
while (!string.Equals(reader.Name, Constants.DataCollectionRunSettingsName) && !reader.EOF)
{
reader.SkipToNextElement();
}
Expand All @@ -302,9 +300,7 @@ public static DataCollectionRunSettings GetDataCollectionRunSettings(string runS
}
catch (XmlException ex)
{
throw new SettingsException(
string.Format(CultureInfo.CurrentCulture, "{0} {1}", Resources.CommonResources.MalformedRunSettingsFile, ex.Message),
ex);
throw new SettingsException(string.Format(CultureInfo.CurrentCulture, "{0} {1}", Resources.CommonResources.MalformedRunSettingsFile, ex.Message), ex);
}
}

Expand All @@ -320,37 +316,35 @@ public static DataCollectionRunSettings GetDataCollectionRunSettings(string runS
public static DataCollectionRunSettings GetInProcDataCollectionRunSettings(string runSettingsXml)
{
// use XmlReader to avoid loading of the plugins in client code (mainly from VS).
if (!string.IsNullOrWhiteSpace(runSettingsXml))
if (string.IsNullOrWhiteSpace(runSettingsXml))
{
runSettingsXml = runSettingsXml.Trim();
using (StringReader stringReader1 = new StringReader(runSettingsXml))
{
XmlReader reader = XmlReader.Create(stringReader1, ReaderSettings);
return null;
}

// read to the fist child
XmlReaderUtilities.ReadToRootNode(reader);
reader.ReadToNextElement();
runSettingsXml = runSettingsXml.Trim();
using (StringReader stringReader1 = new StringReader(runSettingsXml))
{
XmlReader reader = XmlReader.Create(stringReader1, ReaderSettings);

// Read till we reach In Proc IDC element or reach EOF
while (!string.Equals(reader.Name, Constants.InProcDataCollectionRunSettingsName)
&&
!reader.EOF)
{
reader.SkipToNextElement();
}
// read to the fist child
XmlReaderUtilities.ReadToRootNode(reader);
reader.ReadToNextElement();

// If reached EOF => IDC element not there
if (reader.EOF)
{
return null;
}
// Read till we reach In Proc IDC element or reach EOF
while (!string.Equals(reader.Name, Constants.InProcDataCollectionRunSettingsName) && !reader.EOF)
{
reader.SkipToNextElement();
}

// Reached here => In Proc IDC element present.
return DataCollectionRunSettings.FromXml(reader, Constants.InProcDataCollectionRunSettingsName, Constants.InProcDataCollectorsSettingName, Constants.InProcDataCollectorSettingName);
// If reached EOF => IDC element not there
if (reader.EOF)
{
return null;
}
}

return null;
// Reached here => In Proc IDC element present.
return DataCollectionRunSettings.FromXml(reader, Constants.InProcDataCollectionRunSettingsName, Constants.InProcDataCollectorsSettingName, Constants.InProcDataCollectorSettingName);
}
}

/// <summary>
Expand Down
155 changes: 113 additions & 42 deletions src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ namespace Microsoft.VisualStudio.TestPlatform.Utilities
{
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using OMResources = Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources.CommonResources;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using OMResources = Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources.CommonResources;
using UtilitiesResources = Microsoft.VisualStudio.TestPlatform.Utilities.Resources.Resources;

/// <summary>
Expand Down Expand Up @@ -42,6 +41,10 @@ public class InferRunSettingsHelper
// To make things compatible for older runsettings
private const string MsTestTargetDeviceNodePath = @"/RunSettings/MSPhoneTest/TargetDevice";

private const string CodeCoverageCollectorUri = @"datacollector://microsoft/CodeCoverage/2.0";
private const string FakesCollectorUri = @"datacollector://microsoft/unittestisolation/1.0";
private const string CodeCoverageFriendlyName = "Code Coverage";
private const string FakesFriendlyName = "UnitTestIsolation";

/// <summary>
/// Make runsettings compatible with testhost of version 15.0.0-preview
Expand Down Expand Up @@ -213,7 +216,73 @@ public static void UpdateTargetDevice(XmlDocument runSettingsDocument, string ta
/// <param name="overwrite">Overwrite option.</param>
public static void UpdateTargetFramework(XmlDocument runSettingsDocument, string framework, bool overwrite = false)
{
AddNodeIfNotPresent<string>(runSettingsDocument, TargetFrameworkNodePath, TargetFrameworkNodeName, framework, overwrite);
AddNodeIfNotPresent(runSettingsDocument, TargetFrameworkNodePath, TargetFrameworkNodeName, framework, overwrite);
}

/// <summary>
/// Validates the collectors in runsettings when an inlined testsettings is specified
/// </summary>
/// <param name="runsettings">RunSettings used for the run</param>
/// <returns>True if an incompatible collector is found</returns>
public static bool AreRunSettingsCollectorsInCompatibleWithTestSettings(string runsettings)
{
// If there's no embedded testsettings.. bail out
if (!IsTestSettingsEnabled(runsettings))
{
return false;
}

// Explicitly blocking usage of data collectors through modes runsettings and testsettings except
// for couple of scenarios where the IDE generates the collector settings in the runsettings file even when
// it has an embedded testsettings file. Longterm runsettings will be the single run configuration source
// Inproc collectos are incompatible with testsettings
var inprocDataCollectionSettings = XmlRunSettingsUtilities.GetInProcDataCollectionRunSettings(runsettings);
if (inprocDataCollectionSettings != null && inprocDataCollectionSettings.IsCollectionEnabled && inprocDataCollectionSettings.DataCollectorSettingsList != null)
{
foreach (var collectorSettings in inprocDataCollectionSettings.DataCollectorSettingsList)
{
if (collectorSettings.IsEnabled)
{
EqtTrace.Warning($"Incompatible collector found. {collectorSettings.FriendlyName} : {collectorSettings.Uri}");
return true;
}
}
}

// TestSettings and collection is enabled in runsetttings.. the only allowed collectors are codecoverage and fakes
var datacollectionSettings = XmlRunSettingsUtilities.GetDataCollectionRunSettings(runsettings);
if (datacollectionSettings != null && datacollectionSettings.IsCollectionEnabled && datacollectionSettings.DataCollectorSettingsList != null)
{
foreach (var collectorRef in datacollectionSettings.DataCollectorSettingsList)
{
// Ignore disabled collector
if (!collectorRef.IsEnabled)
{
continue;
}

// If the configured collector is code coverage or fakes.. ignore
if (!string.IsNullOrWhiteSpace(collectorRef.FriendlyName) &&
(FakesFriendlyName.Equals(collectorRef.FriendlyName, StringComparison.OrdinalIgnoreCase) ||
CodeCoverageFriendlyName.Equals(collectorRef.FriendlyName, StringComparison.OrdinalIgnoreCase)))
{
continue;
}

// If the configured collector is code coverage or fakes.. ignore
if (collectorRef.Uri != null &&
(CodeCoverageCollectorUri.Equals(collectorRef.Uri.ToString(), StringComparison.OrdinalIgnoreCase) ||
FakesCollectorUri.Equals(collectorRef.Uri.ToString(), StringComparison.OrdinalIgnoreCase)))
{
continue;
}

EqtTrace.Warning($"Incompatible collector found. {collectorRef.FriendlyName} : {collectorRef.Uri}");
return true;
}
}

return false;
}

/// <summary>
Expand Down Expand Up @@ -248,29 +317,31 @@ public static bool TryGetDeviceXml(XPathNavigator runSettingsNavigator, out Stri
/// <returns></returns>
public static bool IsTestSettingsEnabled(string runsettingsXml)
{
if (!string.IsNullOrWhiteSpace(runsettingsXml))
if (string.IsNullOrWhiteSpace(runsettingsXml))
{
using (var stream = new StringReader(runsettingsXml))
using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings))
{
var document = new XmlDocument();
document.Load(reader);
return false;
}

var runSettingsNavigator = document.CreateNavigator();
using (var stream = new StringReader(runsettingsXml))
using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings))
{
var document = new XmlDocument();
document.Load(reader);

// Move navigator to MSTest node
if (!runSettingsNavigator.MoveToChild(RunSettingsNodeName, string.Empty) ||
!runSettingsNavigator.MoveToChild("MSTest", string.Empty))
{
EqtTrace.Info("InferRunSettingsHelper.IsTestSettingsEnabled: Unable to navigate to RunSettings/MSTest. Current node: " + runSettingsNavigator.LocalName);
return false;
}
var runSettingsNavigator = document.CreateNavigator();

var node = runSettingsNavigator.SelectSingleNode(@"/RunSettings/MSTest/SettingsFile");
if (node != null && !string.IsNullOrEmpty(node.InnerXml))
{
return true;
}
// Move navigator to MSTest node
if (!runSettingsNavigator.MoveToChild(RunSettingsNodeName, string.Empty) ||
!runSettingsNavigator.MoveToChild("MSTest", string.Empty))
{
EqtTrace.Info("InferRunSettingsHelper.IsTestSettingsEnabled: Unable to navigate to RunSettings/MSTest. Current node: " + runSettingsNavigator.LocalName);
return false;
}

var node = runSettingsNavigator.SelectSingleNode(@"/RunSettings/MSTest/SettingsFile");
if (node != null && !string.IsNullOrEmpty(node.InnerXml))
{
return true;
}
}

Expand Down Expand Up @@ -398,16 +469,16 @@ public static bool TryGetPlatformXml(XPathNavigator runSettingsNavigator, out st
}

Func<string, bool> validator = (string xml) =>
{
var value = (Architecture)Enum.Parse(typeof(Architecture), xml, true);
{
var value = (Architecture)Enum.Parse(typeof(Architecture), xml, true);

if (!Enum.IsDefined(typeof(Architecture), value) || value == Architecture.Default || value == Architecture.AnyCPU)
{
return false;
}
if (!Enum.IsDefined(typeof(Architecture), value) || value == Architecture.Default || value == Architecture.AnyCPU)
{
return false;
}

return true;
};
return true;
};

return XmlUtilities.IsValidNodeXmlValue(platformXml, validator);
}
Expand All @@ -425,22 +496,22 @@ public static bool TryGetFrameworkXml(XPathNavigator runSettingsNavigator, out s
}

Func<string, bool> validator = (string xml) =>
{
if (Framework.FromString(xml) != null)
{
if (Framework.FromString(xml) != null)
{
// Allow TargetFrameworkMoniker values like .NETFramework,Version=v4.5, ".NETCoreApp,Version=v1.0
return true;
}
// Allow TargetFrameworkMoniker values like .NETFramework,Version=v4.5, ".NETCoreApp,Version=v1.0
return true;
}

var value = (FrameworkVersion)Enum.Parse(typeof(FrameworkVersion), xml, true);
var value = (FrameworkVersion)Enum.Parse(typeof(FrameworkVersion), xml, true);

if (!Enum.IsDefined(typeof(FrameworkVersion), value) || value == FrameworkVersion.None)
{
return false;
}
if (!Enum.IsDefined(typeof(FrameworkVersion), value) || value == FrameworkVersion.None)
{
return false;
}

return true;
};
return true;
};

return XmlUtilities.IsValidNodeXmlValue(frameworkXml, validator);
}
Expand Down
2 changes: 1 addition & 1 deletion src/vstest.console/Resources/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,6 @@
<value>--Collect|/Collect:"{0}" is not supported if test run is configured using testsettings.</value>
</data>
<data name="RunsettingsWithDCErrorMessage" xml:space="preserve">
<value>Data collectors configured via run settings are not supported with embedded test settings. Please see https://aka.ms/vstest-configure-datacollector for more information. Run settings: {0}.</value>
<value>Data collectors other than Code Coverage and Microsoft Fakes configured via run settings are not supported with embedded test settings. Please see https://aka.ms/vstest-configure-datacollector for more information. Run settings: {0}.</value>
</data>
</root>
26 changes: 3 additions & 23 deletions src/vstest.console/TestPlatformHelpers/TestRequestManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers
using System.Threading.Tasks;
using System.Xml;
using System.Xml.XPath;

using Microsoft.VisualStudio.TestPlatform.Client;
using Microsoft.VisualStudio.TestPlatform.Client.RequestHelper;
using Microsoft.VisualStudio.TestPlatform.CommandLine.Internal;
using Microsoft.VisualStudio.TestPlatform.CommandLine.Processors.Utilities;
using Microsoft.VisualStudio.TestPlatform.CommandLine.Publisher;
using Microsoft.VisualStudio.TestPlatform.CommandLine.Resources;
using Microsoft.VisualStudio.TestPlatform.CommandLineUtilities;
using Microsoft.VisualStudio.TestPlatform.Common;
using Microsoft.VisualStudio.TestPlatform.Common.Interfaces;
Expand All @@ -30,8 +30,6 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using System.Text;
using Microsoft.VisualStudio.TestPlatform.CommandLine.Resources;

/// <summary>
/// Defines the TestRequestManger which can fire off discovery and test run requests
Expand Down Expand Up @@ -260,27 +258,9 @@ public bool RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLaunc
runsettings = updatedRunsettings;
}

if (InferRunSettingsHelper.IsTestSettingsEnabled(runsettings))
if (InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings(runsettings))
{
bool throwException = false;
if (this.commandLineOptions.EnableCodeCoverage)
{
var dataCollectorsFriendlyNames = XmlRunSettingsUtilities.GetDataCollectorsFriendlyName(runsettings);
if (dataCollectorsFriendlyNames.Count >= 2)
{
throwException = true;
}

}
else if (XmlRunSettingsUtilities.IsDataCollectionEnabled(runsettings))
{
throwException = true;
}

if (throwException)
{
throw new SettingsException(string.Format(Resources.RunsettingsWithDCErrorMessage, runsettings));
}
throw new SettingsException(string.Format(Resources.RunsettingsWithDCErrorMessage, runsettings));
}

var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettings);
Expand Down
Loading