-
Notifications
You must be signed in to change notification settings - Fork 326
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
Add a tool to migrate testsettings to runsettings #1600
Changes from 2 commits
f6d11dc
2188d5c
6922920
dab18be
528f31a
29649c1
d67f77b
2e1b318
acce98b
3aaa2fb
645273c
09226c5
4c5d7c3
67f2cd3
07a5ba7
e38c75b
c7ce3c4
fc16f53
204fa47
b31a07a
107c88d
5d67152
acece85
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<configuration> | ||
<startup> | ||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> | ||
</startup> | ||
</configuration> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
using System.IO; | ||
using System.Xml; | ||
|
||
namespace Microsoft.VisualStudio.TestPlatform.CommandLine | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we rename Microsoft.VisualStudio.TestPlatform.SettingsMigrator? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
public class Migrator | ||
{ | ||
/// <summary> | ||
/// Given a runsettings with an embedded testsettings, converts it to runsettings. | ||
/// </summary> | ||
/// <param name="oldRunsettingsPath"></param> | ||
/// <param name="newRunsettingsPath"></param> | ||
public void MigrateRunsettings(string oldRunsettingsPath, string newRunsettingsPath) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: RunSettings* There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
string testsettingsPath = null; | ||
using (XmlTextReader reader = new XmlTextReader(oldRunsettingsPath)) | ||
{ | ||
reader.Namespaces = false; | ||
|
||
var document = new XmlDocument(); | ||
document.Load(reader); | ||
var root = document.DocumentElement; | ||
|
||
var testsettingsNode = root.SelectSingleNode(@"/RunSettings/MSTest/SettingsFile"); | ||
|
||
if (testsettingsNode != null) | ||
{ | ||
testsettingsPath = testsettingsNode.InnerText; | ||
} | ||
if (!string.IsNullOrWhiteSpace(testsettingsPath)) | ||
{ | ||
// Expand path relative to runsettings location. | ||
if (!Path.IsPathRooted(testsettingsPath)) | ||
{ | ||
testsettingsPath = Path.Combine(oldRunsettingsPath, testsettingsPath); | ||
} | ||
|
||
MigrateTestsettings(testsettingsPath, newRunsettingsPath, File.ReadAllText(oldRunsettingsPath)); | ||
} | ||
else | ||
{ | ||
Console.WriteLine("Runsettings does not contain an embedded testsettings, not migrating."); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Given a testsettings, converts it to runsettings | ||
/// </summary> | ||
/// <param name="testsettingsPath"></param> | ||
/// <param name="newRunsettingsPath"></param> | ||
/// <param name="oldRunSettingsContent"></param> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be private. |
||
public void MigrateTestsettings(string testsettingsPath, string newRunsettingsPath, string oldRunSettingsContent = null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's refactor this to create file separately, and have a common api for translating testsettings xml to required runsettings xml There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
using (XmlTextReader reader = new XmlTextReader(testsettingsPath)) | ||
{ | ||
reader.Namespaces = false; | ||
|
||
var document = new XmlDocument(); | ||
document.Load(reader); | ||
var root = document.DocumentElement; | ||
|
||
// Select the interesting nodes from the xml. | ||
var deploymentNode = root.SelectSingleNode(@"/TestSettings/Deployment"); | ||
var scriptnode = root.SelectSingleNode(@"/TestSettings/Scripts"); | ||
var websettingsNode = root.SelectSingleNode(@"/TestSettings/Execution/TestTypeSpecific/WebTestRunConfiguration"); | ||
var oldDatacollectorNodes = root.SelectNodes(@"/TestSettings/AgentRule/DataCollectors/DataCollector"); | ||
var timeoutNode = root.SelectSingleNode(@"/TestSettings/Execution/Timeouts"); | ||
var assemblyresolutionNode = root.SelectSingleNode(@"/TestSettings/Execution/TestTypeSpecific/UnitTestRunConfig"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
unitTestConfigNode There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
var hostsNode = root.SelectSingleNode(@"/TestSettings/Execution/Hosts"); | ||
var executionNode = root.SelectSingleNode(@"/TestSettings/Execution"); | ||
|
||
string testTimeout = null; | ||
if (timeoutNode != null && timeoutNode.Attributes[TestTimeoutAttributeName] != null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add warning for deployment and script timeout There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
testTimeout = timeoutNode.Attributes[TestTimeoutAttributeName].Value; | ||
} | ||
|
||
string runTimeout = null; | ||
if (timeoutNode != null && timeoutNode.Attributes[RunTimeoutAttributeName] != null) | ||
{ | ||
runTimeout = timeoutNode.Attributes[RunTimeoutAttributeName].Value; | ||
} | ||
|
||
string parallelTestCount = null; | ||
if (executionNode != null && executionNode.Attributes[ParallelTestCountAttributeName] != null) | ||
{ | ||
parallelTestCount = executionNode.Attributes[ParallelTestCountAttributeName].Value; | ||
} | ||
|
||
if(string.IsNullOrEmpty(oldRunSettingsContent)) | ||
{ | ||
oldRunSettingsContent = sampleRunsettingsContent; | ||
} | ||
var newXmlDoc = new XmlDocument(); | ||
newXmlDoc.LoadXml(oldRunSettingsContent); | ||
|
||
// Remove the embedded testsettings node if it exists. | ||
RemoveEmbeddedTestsettings(newXmlDoc); | ||
|
||
// WebTestRunConfiguration node. | ||
if (websettingsNode != null) | ||
{ | ||
newXmlDoc.DocumentElement.AppendChild(newXmlDoc.ImportNode(websettingsNode, deep: true)); | ||
} | ||
|
||
// LegacySettings node. | ||
if (deploymentNode != null || scriptnode != null || assemblyresolutionNode != null || | ||
!string.IsNullOrEmpty(parallelTestCount) || !string.IsNullOrEmpty(testTimeout) || hostsNode != null) | ||
{ | ||
AddLegacyNodes(deploymentNode, scriptnode, testTimeout, assemblyresolutionNode, hostsNode, parallelTestCount, newXmlDoc); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Create a class for all these nodes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
|
||
// TestSessionTimeout node. | ||
if (!string.IsNullOrEmpty(runTimeout)) | ||
{ | ||
AddRunTimeoutNode(runTimeout, newXmlDoc); | ||
} | ||
|
||
// DataCollectors node. | ||
if (oldDatacollectorNodes != null && oldDatacollectorNodes.Count > 0) | ||
{ | ||
AddDataCollectorNodes(oldDatacollectorNodes, newXmlDoc); | ||
} | ||
|
||
newXmlDoc.Save(newRunsettingsPath); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Removes the embedded testsettings node if present. | ||
/// </summary> | ||
/// <param name="newXmlDoc"></param> | ||
private void RemoveEmbeddedTestsettings(XmlDocument newXmlDoc) | ||
{ | ||
var testsettingsNode = newXmlDoc.DocumentElement.SelectSingleNode(@"/RunSettings/MSTest/SettingsFile"); | ||
if (testsettingsNode != null) | ||
{ | ||
testsettingsNode.ParentNode.RemoveChild(testsettingsNode); | ||
} | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Adds the legacy nodes to runsettings xml. | ||
/// </summary> | ||
/// <param name="deploymentNode"></param> | ||
/// <param name="scriptnode"></param> | ||
/// <param name="testTimeout"></param> | ||
/// <param name="assemblyresolutionNode"></param> | ||
/// <param name="hostsNode"></param> | ||
/// <param name="parallelTestCount"></param> | ||
/// <param name="newXmlDoc"></param> | ||
private void AddLegacyNodes(XmlNode deploymentNode, XmlNode scriptnode, string testTimeout, XmlNode assemblyresolutionNode, XmlNode hostsNode, string parallelTestCount, XmlDocument newXmlDoc) | ||
{ | ||
//Remove if the legacy node already exists. | ||
var legacyNode = newXmlDoc.DocumentElement.SelectSingleNode(@"/RunSettings/LegacySettings"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's put a warning for exist There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
if (legacyNode != null) | ||
{ | ||
legacyNode.ParentNode.RemoveChild(legacyNode); | ||
} | ||
|
||
legacyNode = newXmlDoc.CreateNode(XmlNodeType.Element, LegacySettingsNodeName, null); | ||
|
||
if (deploymentNode != null) | ||
{ | ||
legacyNode.AppendChild(newXmlDoc.ImportNode(deploymentNode, deep: true)); | ||
} | ||
if (scriptnode != null) | ||
{ | ||
legacyNode.AppendChild(newXmlDoc.ImportNode(scriptnode, deep: true)); | ||
} | ||
|
||
// Execution node. | ||
if (assemblyresolutionNode != null || !string.IsNullOrEmpty(parallelTestCount) || !string.IsNullOrEmpty(testTimeout) || hostsNode != null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Nit: Resolution* There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
var newExecutionNode = newXmlDoc.CreateNode(XmlNodeType.Element, ExecutionNodeName, null); | ||
|
||
if (string.IsNullOrEmpty(parallelTestCount)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
{ | ||
var paralellAttribute = newXmlDoc.CreateAttribute(ParallelTestCountAttributeName); | ||
paralellAttribute.Value = parallelTestCount; | ||
newExecutionNode.Attributes.Append(paralellAttribute); | ||
} | ||
if (!string.IsNullOrEmpty(testTimeout)) | ||
{ | ||
var newTimeoutsNode = newXmlDoc.CreateNode(XmlNodeType.Element, TimeoutsNodeName, null); | ||
var testtimeoutattribute = newXmlDoc.CreateAttribute(TestTimeoutAttributeName); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Nit: camelCase There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
testtimeoutattribute.Value = testTimeout; | ||
newTimeoutsNode.Attributes.Append(testtimeoutattribute); | ||
newExecutionNode.AppendChild(newXmlDoc.ImportNode(newTimeoutsNode, deep: true)); | ||
} | ||
if (hostsNode != null) | ||
{ | ||
newExecutionNode.AppendChild(newXmlDoc.ImportNode(hostsNode, deep: true)); | ||
} | ||
if (assemblyresolutionNode != null) | ||
{ | ||
var testTypeSpecificNode = newXmlDoc.CreateNode(XmlNodeType.Element, TestTypeSpecificNodeName, null); | ||
testTypeSpecificNode.AppendChild(newXmlDoc.ImportNode(assemblyresolutionNode, deep: true)); | ||
newExecutionNode.AppendChild(newXmlDoc.ImportNode(testTypeSpecificNode, deep: true)); | ||
} | ||
legacyNode.AppendChild(newXmlDoc.ImportNode(newExecutionNode, deep: true)); | ||
} | ||
newXmlDoc.DocumentElement.AppendChild(legacyNode); | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Adds the datacollector nodes to the runsettings xml. | ||
/// </summary> | ||
/// <param name="oldDatacollectorNodes"></param> | ||
/// <param name="newXmlDoc"></param> | ||
private void AddDataCollectorNodes(XmlNodeList oldDatacollectorNodes, XmlDocument newXmlDoc) | ||
{ | ||
var dataCollectionRunSettingsNode = newXmlDoc.DocumentElement.SelectSingleNode(@"/RunSettings/DataCollectionRunSettings"); | ||
if (dataCollectionRunSettingsNode == null) | ||
{ | ||
dataCollectionRunSettingsNode = newXmlDoc.CreateNode(XmlNodeType.Element, DataCollectionRunSettingsNodeName, null); | ||
} | ||
|
||
var dataCollectorsNode = newXmlDoc.DocumentElement.SelectSingleNode(@"/RunSettings/DataCollectionRunSettings/DataCollectors"); | ||
if (dataCollectorsNode == null) | ||
{ | ||
dataCollectorsNode = newXmlDoc.CreateNode(XmlNodeType.Element, DataCollectorsNodeName, null); | ||
dataCollectionRunSettingsNode.AppendChild(newXmlDoc.ImportNode(dataCollectorsNode, deep: true)); | ||
dataCollectorsNode = newXmlDoc.DocumentElement.SelectSingleNode(@"/RunSettings/DataCollectionRunSettings/DataCollectors"); | ||
} | ||
|
||
foreach (XmlNode datacollector in oldDatacollectorNodes) | ||
{ | ||
dataCollectorsNode.AppendChild(newXmlDoc.ImportNode(datacollector, deep: true)); | ||
} | ||
newXmlDoc.DocumentElement.AppendChild(dataCollectionRunSettingsNode); | ||
} | ||
|
||
/// <summary> | ||
/// Adds run session timeout node. | ||
/// </summary> | ||
/// <param name="runTimeout"></param> | ||
/// <param name="newXmlDoc"></param> | ||
private void AddRunTimeoutNode(string runTimeout, XmlDocument newXmlDoc) | ||
{ | ||
var runConfigurationNode = newXmlDoc.DocumentElement.SelectSingleNode(@"/RunSettings/RunConfiguration"); | ||
if (runConfigurationNode == null) | ||
{ | ||
runConfigurationNode = newXmlDoc.CreateNode(XmlNodeType.Element, RunConfigurationNodeName, null); | ||
} | ||
|
||
var testSessionTimeoutNode = newXmlDoc.CreateNode(XmlNodeType.Element, TestSessionTimeoutNodeName, null); | ||
testSessionTimeoutNode.InnerText = runTimeout; | ||
runConfigurationNode.AppendChild(newXmlDoc.ImportNode(testSessionTimeoutNode, deep: true)); | ||
|
||
newXmlDoc.DocumentElement.AppendChild(runConfigurationNode); | ||
} | ||
|
||
const string TestTimeoutAttributeName = "testTimeout"; | ||
const string ParallelTestCountAttributeName = "testTimeout"; | ||
const string RunTimeoutAttributeName = "runTimeout"; | ||
const string LegacySettingsNodeName = "LegacySettings"; | ||
const string ExecutionNodeName = "Execution"; | ||
const string TimeoutsNodeName = "Timeouts"; | ||
const string TestTypeSpecificNodeName = "TestTypeSpecific"; | ||
const string RunConfigurationNodeName = "RunConfiguration"; | ||
const string TestSessionTimeoutNodeName = "TestSessionTimeout"; | ||
const string DataCollectionRunSettingsNodeName = "DataCollectionRunSettings"; | ||
const string DataCollectorsNodeName = "DataCollectors"; | ||
const string sampleRunsettingsContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + | ||
"<RunSettings></RunSettings>"; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is
.NETFramework,Version=v4.6.1
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WE can remove app.config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done