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

Test run parameter added as part of CLI runsettings args #2251

Merged
merged 9 commits into from
Dec 27, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -12,6 +12,8 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.Utilities
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.Common;
using System.Collections.Generic;
using System.Text.RegularExpressions;

/// <summary>
/// Utilities to get the run settings from the provider and the commandline options specified.
Expand All @@ -20,6 +22,36 @@ internal static class RunSettingsProviderExtensions
{
public const string EmptyRunSettings = @"<RunSettings><RunConfiguration></RunConfiguration></RunSettings>";

/// <summary>
/// Pattern used to find test run parameter node.
/// </summary>
private const string TestRunParameters = "TestRunParameters";

/// <summary>
/// Pattern used to find parameter node.
/// </summary>
private const string Parameter = "Parameter";

/// <summary>
/// Pattern that indicates Attribute name.
/// </summary>
private const string AttributeName = "AttrName";

/// <summary>
/// Pattern that indicates Attribute value.
/// </summary>
private const string AttributeValue = "AttrValue";

/// <summary>
/// Attribute name key for test run parameter node
/// </summary>
private const string Name = "name";

/// <summary>
/// Attribute value key for test run parameter node
/// </summary>
private const string Value = "value";

public static void UpdateRunSettings(this IRunSettingsProvider runSettingsProvider, string runsettingsXml)
{
ValidateArg.NotNull(runSettingsProvider, nameof(runSettingsProvider));
Expand Down Expand Up @@ -62,6 +94,59 @@ public static void UpdateRunSettingsNode(this IRunSettingsProvider runSettingsPr
runSettingsProvider.UpdateRunSettings(xmlDocument.OuterXml);
}

/// <summary>
/// Matches with test run parameter node pattern and returns that match.
/// </summary>
/// <param name="runSettingsProvider"></param>
/// <param name="node"></param>
/// <returns></returns>
public static Match GetTestRunParameterNodeMatch(this IRunSettingsProvider runSettingsProvider, string node)
{
var attrName = $"(?<{AttributeName}>\\w+)";
var attrValue = $"(?<{AttributeValue}>.+)";
Regex regex = new Regex($"{TestRunParameters}.{Parameter}\\(name={attrName},value={attrValue}\\)");
Match match = regex.Match(node);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can throw exception, either catch here, or in the caller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are four argument exceptions possible
1.ArgumentOutOfRangeException : This comes if options is not a valid bitwise combination, but we have not given options in match
2.ArgumentNullException : This commes if input or pattern is null, but input is always not null and pattern is not null.
3.RegexMatchTimeoutException :This commes if timout occured,but as Pattern is fixed and we have not set timeout in match. We won't get this exceptions
4.ArgumentException : This comes if regular expression is not syntactically correct,This too not valid in our case..
so catching an exception is not that reasonable

return match;
}

/// <summary>
/// If test run parameter exists already it will override with new value otherwise this will add new test run parameter.
/// </summary>
/// <param name="runSettingsProvider"></param>
/// <param name="match"></param>
public static void UpdateTestRunParameterSettingsNode(this IRunSettingsProvider runSettingsProvider, Match match)
{
ValidateArg.NotNull(runSettingsProvider, nameof(runSettingsProvider));

var xmlDocument = runSettingsProvider.GetRunSettingXmlDocument();
XmlNode testRunParameterNode = GetXmlNode(xmlDocument, TestRunParameters) ?? xmlDocument.CreateElement(TestRunParameters);
var attrName = match.Groups[AttributeName].Value;
var attrValue = match.Groups[AttributeValue].Value;
if (!TryOverRideAttributeName(testRunParameterNode, attrName, attrValue))
hvinett marked this conversation as resolved.
Show resolved Hide resolved
{
XmlElement element = xmlDocument.CreateElement(Parameter);
element.SetAttribute(Name, attrName);
element.SetAttribute(Value, attrValue);
testRunParameterNode.AppendChild(element);
xmlDocument.DocumentElement.AppendChild(testRunParameterNode);
}

runSettingsProvider.UpdateRunSettings(xmlDocument.OuterXml);
}

private static bool TryOverRideAttributeName(XmlNode xmlNode, string attrName, string attrValue)
{
foreach (XmlNode node in xmlNode.ChildNodes)
{
if (string.Compare(node.Attributes[Name].Value, attrName) == 0)
{
node.Attributes[Value].Value = attrValue;
return true;
}
}
return false;
}

public static void UpdateRunSettingsNodeInnerXml(this IRunSettingsProvider runSettingsProvider, string key, string xml)
{
ValidateArg.NotNull(runSettingsProvider, nameof(runSettingsProvider));
Expand Down Expand Up @@ -133,7 +218,7 @@ private static XmlNode CreateNode(XmlDocument doc, string xPath)
}

return node;
}
}

private static XmlDocument GetRunSettingXmlDocument(this IRunSettingsProvider runSettingsProvider)
{
Expand Down
28 changes: 23 additions & 5 deletions src/vstest.console/Processors/CLIRunSettingsArgumentProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors
using Microsoft.VisualStudio.TestPlatform.Common.Utilities;

using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources;
using System.Text.RegularExpressions;

/// <summary>
/// The argument processor for runsettings passed as argument through cli
Expand Down Expand Up @@ -139,14 +140,20 @@ private void CreateOrOverwriteRunSettings(IRunSettingsProvider runSettingsProvid

for (int index = 0; index < length; index++)
{
var keyValuePair = args[index];
var indexOfSeparator = keyValuePair.IndexOf("=");
if (indexOfSeparator <= 0 || indexOfSeparator >= keyValuePair.Length - 1)
var arg = args[index];

if (TryUpdateTestRunParameterNode(runSettingsProvider, arg))
{
continue;
}

var indexOfSeparator = arg.IndexOf("=");
if (indexOfSeparator <= 0 || indexOfSeparator >= arg.Length - 1)
{
continue;
}
var key = keyValuePair.Substring(0, indexOfSeparator).Trim();
var value = keyValuePair.Substring(indexOfSeparator + 1);
var key = arg.Substring(0, indexOfSeparator).Trim();
var value = arg.Substring(indexOfSeparator + 1);

if (string.IsNullOrWhiteSpace(key))
{
Expand All @@ -160,6 +167,17 @@ private void CreateOrOverwriteRunSettings(IRunSettingsProvider runSettingsProvid
}
}

private bool TryUpdateTestRunParameterNode(IRunSettingsProvider runSettingsProvider, string node)
{
var match = runSettingsProvider.GetTestRunParameterNodeMatch(node);
hvinett marked this conversation as resolved.
Show resolved Hide resolved
if (string.Compare(match.Value, node) == 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compare [](start = 23, length = 7)

is this case insensitive?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it is case sensitive.

{
runSettingsProvider.UpdateTestRunParameterSettingsNode(match);
return true;
}
return false;
}

private void UpdateFrameworkAndPlatform(string key, string value)
{
if (key.Equals(FrameworkArgumentExecutor.RunSettingsPath))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
namespace Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests.Processors.Utilities
{
using System;

using Microsoft.VisualStudio.TestPlatform.Common;
using Microsoft.VisualStudio.TestPlatform.Common.Interfaces;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.Common.Utilities;
using System.Text.RegularExpressions;

[TestClass]
public class RunSettingsProviderExtensionsTests
Expand All @@ -24,7 +25,7 @@ public void Init()
{
runSettingsProvider = new TestableRunSettingsProvider();
}

[TestMethod]
public void UpdateRunSettingsShouldUpdateGivenSettingsXml()
{
Expand Down Expand Up @@ -130,6 +131,33 @@ public void UpdateRunSettingsNodeShouldAddNewKeyIfNotPresent()
Assert.AreEqual("data", this.runSettingsProvider.QueryRunSettingsNode("Key.Path"));
}

[TestMethod]
public void UpdateTetsRunParameterSettingsNodeShouldAddNewKeyIfNotPresent()
hvinett marked this conversation as resolved.
Show resolved Hide resolved
{
var match = this.runSettingsProvider.GetTestRunParameterNodeMatch("TestRunParameters.Parameter(name=weburl,value=http://localhost//abc)");
var runSettingsWithTestRunParameters = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <TestRunParameters>\r\n <Parameter name=\"weburl\" value=\"http://localhost//abc\" />\r\n </TestRunParameters>\r\n</RunSettings>";

this.runSettingsProvider.UpdateRunSettings("<RunSettings>\r\n </RunSettings>");
this.runSettingsProvider.UpdateTestRunParameterSettingsNode(match);

Assert.AreEqual(runSettingsWithTestRunParameters, this.runSettingsProvider.ActiveRunSettings.SettingsXml);

}

[TestMethod]
public void UpdateTetsRunParameterSettingsNodeShouldOverrideValueIfKeyIsAlreadyPresent()
{
var runSettingsWithTestRunParameters = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <TestRunParameters>\r\n <Parameter name=\"weburl\" value=\"http://localhost//abc\" />\r\n </TestRunParameters>\r\n</RunSettings>";
var runSettingsWithTestRunParametersOverRode = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <TestRunParameters>\r\n <Parameter name=\"weburl\" value=\"http://localhost//def\" />\r\n </TestRunParameters>\r\n</RunSettings>";

this.runSettingsProvider.UpdateRunSettings(runSettingsWithTestRunParameters);
var match = this.runSettingsProvider.GetTestRunParameterNodeMatch("TestRunParameters.Parameter(name=weburl,value=http://localhost//def)");
this.runSettingsProvider.UpdateTestRunParameterSettingsNode(match);

Assert.AreEqual(runSettingsWithTestRunParametersOverRode, this.runSettingsProvider.ActiveRunSettings.SettingsXml);

}

[TestMethod]
public void UpdateRunSettingsNodeShouldUpdateKeyIfAlreadyPresent()
{
Expand Down Expand Up @@ -203,15 +231,14 @@ public void QueryRunSettingsNodeShouldReturnCorrectValue()
this.runSettingsProvider.UpdateRunSettings("<RunSettings> <RunConfiguration> <TargetPlatform>x86</TargetPlatform></RunConfiguration> </RunSettings>");
Assert.AreEqual("x86", this.runSettingsProvider.QueryRunSettingsNode("RunConfiguration.TargetPlatform"));
}

private class TestableRunSettingsProvider : IRunSettingsProvider
{
public RunSettings ActiveRunSettings
{
get;
set;
}

public void SetActiveRunSettings(RunSettings runSettings)
{
this.ActiveRunSettings = runSettings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ public void InitializeShouldIgnoreWhiteSpaceInBeginningOrEndOfKey()
Assert.AreEqual(RunSettingsWithDeploymentDisabled, settingsProvider.ActiveRunSettings.SettingsXml);
}

[TestMethod]
public void InitializeShouldValidateTestRunParameter()
{
var args = new string[] { "TestRunParameters.Parameter(name=weburl,value=http://localhost//abc)" };

this.executor.Initialize(args);
var runSettingsWithTestRunParameters = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<RunSettings>\r\n <DataCollectionRunSettings>\r\n <DataCollectors />\r\n </DataCollectionRunSettings>\r\n <TestRunParameters>\r\n <Parameter name=\"weburl\" value=\"http://localhost//abc\" />\r\n </TestRunParameters>\r\n</RunSettings>";

Assert.IsNotNull(this.settingsProvider.ActiveRunSettings);
Assert.AreEqual(runSettingsWithTestRunParameters, settingsProvider.ActiveRunSettings.SettingsXml);
}

[TestMethod]
public void InitializeShouldIgnoreThrowExceptionIfKeyHasWhiteSpace()
{
Expand Down