Skip to content

Commit 77f351f

Browse files
authored
Passing runsettings as command line arguments. (#297)
* Allow TranslationLayer to specify Diag parameters Log message for logging file of test host * Passing runsettings as command line arguments. * Removed unused variable. * Added regex, testcases. * Added new parameter VSTestCLIRunSettings in VSTest Task. * Added htlm encoding to the RunSettings values coming as CLI arguments. * Style fixes * Fix typo * Work done under this commit: (#302) 1) Create xlf file for all language 2) Create language resx file from xlf file 3) create satellite dll * Testhost Diag log file name format change (#303) Update diag log format for testhost. New format ensures log files are unique so that we don't run multiple testhosts with same file name in case of parallel runs. * Changes for passing RunSettings args as array of string. * Doc changes. * test fixes. * Removed unused namespaces, improved documentation, added trim to key. * Removed HTML Encoding as it is already done while validating xml. * Removed ununsed namespace and package.run
1 parent fc1f7b9 commit 77f351f

File tree

15 files changed

+793
-17
lines changed

15 files changed

+793
-17
lines changed

src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Copyright (c) .NET Foundation. All rights reserved.
3939
VSTestLogger="$(VSTestLogger)"
4040
VSTestListTests="$(VSTestListTests)"
4141
VSTestDiag="$(VSTestDiag)"
42+
VSTestCLIRunSettings="$(VSTestCLIRunSettings)"
4243
/>
4344
</Target>
4445

@@ -72,6 +73,7 @@ Copyright (c) .NET Foundation. All rights reserved.
7273
<Message Text="VSTestLogger = $(VSTestLogger)" Importance="low" />
7374
<Message Text="VSTestListTests = $(VSTestListTests)" Importance="low" />
7475
<Message Text="VSTestDiag = $(VSTestDiag)" Importance="low" />
76+
<Message Text="VSTestCLIRunSettings = $(VSTestCLIRunSettings)" Importance="low" />
7577
</Target>
7678

7779
</Project>

src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public string VSTestDiag
7070
set;
7171
}
7272

73+
public string[] VSTestCLIRunSettings
74+
{
75+
get;
76+
set;
77+
}
78+
7379
public override bool Execute()
7480
{
7581
var traceEnabledValue = Environment.GetEnvironmentVariable("VSTEST_BUILD_TRACE");
@@ -159,6 +165,12 @@ private IEnumerable<string> CreateArgument()
159165
}
160166
}
161167

168+
if (this.VSTestCLIRunSettings!=null && this.VSTestCLIRunSettings.Length>0)
169+
{
170+
allArgs.Add("--");
171+
allArgs.AddRange(this.VSTestCLIRunSettings);
172+
}
173+
162174
return allArgs;
163175
}
164176
}

src/vstest.console/CommandLine/Executor.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal class Executor
5050
/// <summary>
5151
/// Default constructor.
5252
/// </summary>
53-
public Executor(IOutput output): this(output, TestPlatformEventSource.Instance)
53+
public Executor(IOutput output) : this(output, TestPlatformEventSource.Instance)
5454
{
5555
}
5656

@@ -152,8 +152,18 @@ private int GetArgumentProcessors(string[] args, out List<IArgumentProcessor> pr
152152
int result = 0;
153153
var processorFactory = ArgumentProcessorFactory.Create();
154154

155-
foreach (string arg in args)
155+
for (var index = 0; index < args.Length; index++)
156156
{
157+
var arg = args[index];
158+
159+
// If argument is '--', following arguments are key=value pairs for run settings.
160+
if (arg.Equals("--"))
161+
{
162+
var cliRunSettingsProcessor = processorFactory.CreateArgumentProcessor(arg, args.Skip(index + 1).ToArray());
163+
processors.Add(cliRunSettingsProcessor);
164+
break;
165+
}
166+
157167
var processor = processorFactory.CreateArgumentProcessor(arg);
158168

159169
if (processor != null)
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors
5+
{
6+
using System;
7+
using System.Diagnostics.Contracts;
8+
using System.IO;
9+
using System.Xml;
10+
using System.Xml.XPath;
11+
12+
using Microsoft.VisualStudio.TestPlatform.Common;
13+
using Microsoft.VisualStudio.TestPlatform.Common.Interfaces;
14+
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
15+
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
16+
17+
using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources;
18+
19+
/// <summary>
20+
/// The argument processor for runsettings passed as argument through cli
21+
/// </summary>
22+
internal class CLIRunSettingsArgumentProcessor : IArgumentProcessor
23+
{
24+
#region Constants
25+
26+
/// <summary>
27+
/// The name of the command line argument that the PortArgumentExecutor handles.
28+
/// </summary>
29+
public const string CommandName = "--";
30+
31+
#endregion
32+
33+
private Lazy<IArgumentProcessorCapabilities> metadata;
34+
35+
private Lazy<IArgumentExecutor> executor;
36+
37+
/// <summary>
38+
/// Gets the metadata.
39+
/// </summary>
40+
public Lazy<IArgumentProcessorCapabilities> Metadata
41+
{
42+
get
43+
{
44+
if (this.metadata == null)
45+
{
46+
this.metadata = new Lazy<IArgumentProcessorCapabilities>(() => new CLIRunSettingsArgumentProcessorCapabilities());
47+
}
48+
49+
return this.metadata;
50+
}
51+
}
52+
53+
/// <summary>
54+
/// Gets or sets the executor.
55+
/// </summary>
56+
public Lazy<IArgumentExecutor> Executor
57+
{
58+
get
59+
{
60+
if (this.executor == null)
61+
{
62+
this.executor = new Lazy<IArgumentExecutor>(() => new CLIRunSettingsArgumentExecutor(RunSettingsManager.Instance));
63+
}
64+
65+
return this.executor;
66+
}
67+
68+
set
69+
{
70+
this.executor = value;
71+
}
72+
}
73+
}
74+
75+
internal class CLIRunSettingsArgumentProcessorCapabilities : BaseArgumentProcessorCapabilities
76+
{
77+
public override string CommandName => CLIRunSettingsArgumentProcessor.CommandName;
78+
79+
public override bool AllowMultiple => false;
80+
81+
public override bool IsAction => false;
82+
83+
public override ArgumentProcessorPriority Priority => ArgumentProcessorPriority.CLIRunSettings;
84+
85+
public override string HelpContentResourceName => CommandLineResources.CLIRunSettingsArgumentHelp;
86+
87+
public override HelpContentPriority HelpPriority => HelpContentPriority.CLIRunSettingsArgumentProcessorHelpPriority;
88+
}
89+
90+
internal class CLIRunSettingsArgumentExecutor : IArgumentsExecutor
91+
{
92+
private IRunSettingsProvider runSettingsManager;
93+
94+
internal CLIRunSettingsArgumentExecutor(IRunSettingsProvider runSettingsManager)
95+
{
96+
this.runSettingsManager = runSettingsManager;
97+
}
98+
99+
public void Initialize(string argument)
100+
{
101+
throw new NotImplementedException();
102+
}
103+
104+
public void Initialize(string[] arguments)
105+
{
106+
// if argument is null or doesn't contain any element, don't do anything.
107+
if (arguments == null || arguments.Length == 0)
108+
{
109+
return;
110+
}
111+
112+
Contract.EndContractBlock();
113+
114+
// Load up the run settings and set it as the active run settings.
115+
try
116+
{
117+
var doc = new XmlDocument();
118+
119+
if (this.runSettingsManager.ActiveRunSettings != null && !string.IsNullOrEmpty(this.runSettingsManager.ActiveRunSettings.SettingsXml))
120+
{
121+
var settingsXml = this.runSettingsManager.ActiveRunSettings.SettingsXml;
122+
123+
#if net46
124+
using (var reader = XmlReader.Create(new StringReader(settingsXml), new XmlReaderSettings() { XmlResolver = null, CloseInput = true, DtdProcessing = DtdProcessing.Prohibit }))
125+
{
126+
#else
127+
using (var reader = XmlReader.Create(new StringReader(settingsXml), new XmlReaderSettings() { CloseInput = true, DtdProcessing = DtdProcessing.Prohibit }))
128+
{
129+
#endif
130+
doc.Load(reader);
131+
}
132+
}
133+
else
134+
{
135+
#if net46
136+
doc = (XmlDocument)XmlRunSettingsUtilities.CreateDefaultRunSettings();
137+
#else
138+
using (var reader = XmlReader.Create(new StringReader(XmlRunSettingsUtilities.CreateDefaultRunSettings().CreateNavigator().OuterXml), new XmlReaderSettings() { CloseInput = true, DtdProcessing = DtdProcessing.Prohibit }))
139+
{
140+
doc.Load(reader);
141+
}
142+
#endif
143+
}
144+
145+
// Append / Override run settings supplied in CLI
146+
CreateOrOverwriteRunSettings(doc, arguments);
147+
148+
// Set Active Run Settings.
149+
var runSettings = new RunSettings();
150+
runSettings.LoadSettingsXml(doc.OuterXml);
151+
this.runSettingsManager.SetActiveRunSettings(runSettings);
152+
}
153+
catch (XPathException exception)
154+
{
155+
throw new CommandLineException(CommandLineResources.MalformedRunSettingsKey, exception);
156+
}
157+
catch (SettingsException exception)
158+
{
159+
throw new CommandLineException(exception.Message, exception);
160+
}
161+
}
162+
163+
public ArgumentProcessorResult Execute()
164+
{
165+
// Nothing to do here, the work was done in initialization.
166+
return ArgumentProcessorResult.Success;
167+
}
168+
169+
private void CreateOrOverwriteRunSettings(XmlDocument xmlDoc, string[] args)
170+
{
171+
var length = args.Length;
172+
173+
for (int index = 0; index < length; index++)
174+
{
175+
var keyValuePair = args[index];
176+
var indexOfSeparator = keyValuePair.IndexOf("=");
177+
if (indexOfSeparator <= 0 || indexOfSeparator >= keyValuePair.Length - 1)
178+
{
179+
continue;
180+
}
181+
var key = keyValuePair.Substring(0, indexOfSeparator).Trim();
182+
var value = keyValuePair.Substring(indexOfSeparator + 1);
183+
184+
if (string.IsNullOrWhiteSpace(key))
185+
{
186+
continue;
187+
}
188+
189+
// Check if the key exists.
190+
var xPath = key.Replace('.', '/');
191+
var node = xmlDoc.SelectSingleNode(string.Format("//RunSettings/{0}", xPath));
192+
193+
if (node == null)
194+
{
195+
node = CreateNode(xmlDoc, key.Split('.'));
196+
}
197+
198+
node.InnerText = value;
199+
}
200+
}
201+
202+
private XmlNode CreateNode(XmlDocument doc, string[] xPath)
203+
{
204+
XmlNode node = null;
205+
XmlNode parent = doc.DocumentElement;
206+
207+
for (int i = 0; i < xPath.Length; i++)
208+
{
209+
node = parent.SelectSingleNode(xPath[i]);
210+
211+
if (node == null)
212+
{
213+
node = parent.AppendChild(doc.CreateElement(xPath[i]));
214+
}
215+
216+
parent = node;
217+
}
218+
219+
return node;
220+
}
221+
}
222+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors
5+
{
6+
/// <summary>
7+
/// Defines interface for interacting with a command line arguments executor.
8+
/// Items exporting this interface will be used in processing command line arguments.
9+
/// </summary>
10+
internal interface IArgumentsExecutor : IArgumentExecutor
11+
{
12+
/// <summary>
13+
/// Initializes the Argument Processor with the arguments that was provided with the command.
14+
/// </summary>
15+
/// <param name="arguments">Arguments that are provided with the command.</param>
16+
void Initialize(string[] arguments);
17+
}
18+
}

0 commit comments

Comments
 (0)