// ----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using ProductStudio;
namespace TestExport
{
internal class TestExporter
{
private static readonly string[] DEFAULT_ARGS = new string[] { "-o", "BVT", "foo.tst" };
//private static readonly string[] DEFAULT_ARGS = new string[] { "-h" };
private const string TITLE_FORMAT = "{0}!{1}::{2}";
// Query in Xml Format which retrieves all unassigned bugs
private static readonly string QUERY_ACTIVE =
"" +
"Active";
private static readonly string QUERY_PROFILE =
""+
"Active" +
"Automated" +
"" +
"{0}" +
"";
// private static readonly string QUERY_PROFILEy =
// "" +
// "{0}" +
// "";
// private static readonly string QUERY_PROFILEx =
// "" +
// "{0}" +
// "";
// Fields to retrieve and fields to sort by.
private static readonly string[] TEST_CASE_FIELDS =
new string[] { "Title", "Test Module", "Test Suite", "TestCase", "Test Timeout", "Test Known Failure", "Order" };
private static readonly string[] TEST_CASE_SORT = new string[] {"Order", "Test Module", "Test Suite", "TestCase"};
private Datastore m_psDataStore;
private Directory m_psDirectory;
private string m_profile = "";
private Hashtable m_existing;
private int m_existedCount = 0;
private int m_createdCount = 0;
private TestExporter(Directory psDirectory, Datastore psDataStore)
{
m_psDataStore = psDataStore;
m_psDirectory = psDirectory;
m_existing = CurrentTests();
}
[STAThread]
private static int Main(string[] args)
{
if (args.Length == 0) {
args = DEFAULT_ARGS;
}
// Connect to the directory with your current
// domain under your credentials .
Directory psDirectory = new DirectoryClass();
try {
psDirectory.Connect("", "", "");
Product psProduct = psDirectory.GetProductByName("Singularity");
Datastore psDataStore = psProduct.Connect("", "", "");
TestExporter t = new TestExporter(psDirectory, psDataStore);
switch (args[0]) {
case "-i":
if (args.Length < 2) {
break;
}
t.ImportProfile(args[1]);
t.Report();
return 0;
case "-o":
if (args.Length < 3) {
break;
}
t.ExportProfile(args[1], args[2]);
return 0;
case "-h":
t.QueryTestCases();
return 0;
default:
break;
}
Console.WriteLine("Usage: TestExport -i | -o ");
return -1;
}
catch (Exception e) {
Console.WriteLine("Error: {0}", e.Message);
return -1;
}
finally {
psDirectory.Disconnect();
}
}
private void ImportProfile(string filename)
{
XmlReader r = XmlReader.Create(filename);
m_profile = filename;
string module = null;
string suite = null;
string testcase = null;
while (r.Read()) {
if (r.NodeType != XmlNodeType.Element) {
continue;
}
string optName = r.GetAttribute("Name");
switch (r.Name.ToLower()) {
case "suite":
suite = optName;
break;
case "module":
module = optName;
break;
case "test":
testcase = optName;
if (module != null && suite != null && testcase != null) {
MakeTestCase(module, suite, testcase);
}
break;
default:
break;
}
}
}
private void Report()
{
Console.WriteLine("Created test cases: {0}. Ignored duplicate test cases: {1}.", m_createdCount, m_existedCount);
}
private void MakeTestCase(string module, string suite, string testcase)
{
string key = TestKey(module, suite, testcase);
if (m_existing.ContainsKey(key)) {
m_existedCount++;
return;
}
// Create a new datastore instance.
DatastoreItemList psDataList = new DatastoreItemListClass();
psDataList.Datastore = m_psDataStore;
// Create a blank Test Case
psDataList.CreateBlank(PsDatastoreItemTypeEnum.psDatastoreItemTypeTestCase);
DatastoreItem psDataItem = psDataList.DatastoreItems.Add(null, PsApplyRulesMask.psApplyRulesAll);
// Set fields for the Test Case
Fields psFields = psDataItem.Fields;
psFields["Title"].Value = key;
psFields["TreeID"].Value = TreeIDFromPath(m_psDataStore.RootNode, "OS");
// psFields["TCMTreeID"].Value = -200;
psFields["Test Status"].Value = "Active";
//psFields["Test Priority"].Value = 2;
psFields["Test Module"].Value = module;
psFields["Test Suite"].Value = suite;
psFields["TestCase"].Value = testcase;
// psFields["Test Class"].Value = "Boundary";
// psFields["Test Type"].Value = "Automatic";
// psFields["Frequency"].Value = "Daily";
psFields["Owner"].Value = "Active";
psFields["Description"].Value = "A test case generated from profile " + m_profile;
// Let's make sure all fields are valid before saving
bool hasInvalidField = false;
foreach (Field psField in psDataItem.Fields) {
if (psField.Validity != PsFieldStatusEnum.psFieldStatusValid) {
hasInvalidField = true;
Console.WriteLine("Invalid Field '{0}': {1}", psField.Name, psField.Validity.ToString());
Console.WriteLine("Current Value: '{0}'", psField.Value);
Console.WriteLine();
}
}
if (hasInvalidField) {
throw (new ApplicationException("Invalid Field(s) were found. Could not update."));
}
else {
psDataItem.Save(true);
int testCaseID = Convert.ToInt32(psFields["ID"].Value);
Console.WriteLine("Test Case #{0} {1} Successfully Created.", testCaseID, key);
}
m_createdCount++;
}
private static string TestKey(object module, object suite, object testcase)
{
return string.Format(TITLE_FORMAT, module, suite, testcase);
}
private void QueryTestCases()
{
// Set up the query.
Query psQuery = new QueryClass();
psQuery.CountOnly = false;
psQuery.SelectionCriteria = QUERY_ACTIVE;
psQuery.DatastoreItemType = PsDatastoreItemTypeEnum.psDatastoreItemTypeTestCase;
// Bind the query and Datastore to our
// DatastoreItemList.
DatastoreItemList psDataList = new DatastoreItemListClass();
psDataList.Query = psQuery;
psDataList.Datastore = m_psDataStore;
// Get the field definitions so we can specify
// them in the result and sort list.
// You can also use the GetEnumerator to
// enumerate the fields.
FieldDefinitions psFields = m_psDataStore.FieldDefinitions;
foreach (FieldDefinition item in psFields) {
Console.WriteLine(item.Name);
}
// Add fields with the FieldDefinitions indexer
psQuery.QueryFields.Clear();
for (int fieldCount = 0; fieldCount < TEST_CASE_FIELDS.Length; fieldCount++) {
psQuery.QueryFields.Add(psFields[TEST_CASE_FIELDS[fieldCount]]);
}
// Add fields to sort by
for (int fieldCount = 0; fieldCount < TEST_CASE_SORT.Length; fieldCount++) {
psQuery.QuerySortFields.Add(
psFields[TEST_CASE_SORT[fieldCount]],
PsSortTypeEnum.psSortTypeAscending);
}
psDataList.Execute();
foreach (DatastoreItem psItem in psDataList.DatastoreItems) {
foreach (String name in TEST_CASE_FIELDS) {
Console.Write("{0}\t", psItem.Fields[name].Value);
}
Console.WriteLine();
}
}
private Hashtable CurrentTests()
{
// Set up the query.
Query psQuery = new QueryClass();
psQuery.CountOnly = false;
psQuery.SelectionCriteria = QUERY_ACTIVE;
psQuery.DatastoreItemType = PsDatastoreItemTypeEnum.psDatastoreItemTypeTestCase;
DatastoreItemList psDataList = new DatastoreItemListClass();
psDataList.Query = psQuery;
psDataList.Datastore = m_psDataStore;
FieldDefinitions psFields = m_psDataStore.FieldDefinitions;
// Add fields with the FieldDefinitions indexer
psQuery.QueryFields.Clear();
for (int fieldCount = 0; fieldCount < TEST_CASE_FIELDS.Length; fieldCount++) {
psQuery.QueryFields.Add(psFields[TEST_CASE_FIELDS[fieldCount]]);
}
// Add fields to sort by
for (int fieldCount = 0; fieldCount < TEST_CASE_SORT.Length; fieldCount++) {
psQuery.QuerySortFields.Add(
psFields[TEST_CASE_SORT[fieldCount]],
PsSortTypeEnum.psSortTypeAscending);
}
Hashtable res = new Hashtable();
psDataList.Execute();
foreach (DatastoreItem psItem in psDataList.DatastoreItems) {
object module = psItem.Fields["Test Module"].Value;
object suite = psItem.Fields["Test Suite"].Value;
object testcase = psItem.Fields["TestCase"].Value;
res[TestKey(module, suite, testcase)] = psItem.Fields["ID"].Value;
}
return res;
}
// Finds the ID from the Product Path.
internal static int TreeIDFromPath(Node node, string path)
{
char[] separator = {'\\'};
string[] pathLevelNames = path.Split(separator);
Node currentNode = node;
if (path.Trim().Length >= 1 && path.Trim() != "\\") {
for (int pathCount = 0; pathCount < pathLevelNames.Length; pathCount++) {
currentNode = currentNode.Nodes[pathLevelNames[pathCount]];
}
}
return currentNode.ID;
}
private void ExportProfile(string testType, string profileName)
{
// Set up the query.
Query psQuery = new QueryClass();
psQuery.CountOnly = false;
string query = string.Format(QUERY_PROFILE, testType);
//string query = QUERY_PROFILE;
psQuery.SelectionCriteria = query;
psQuery.DatastoreItemType = PsDatastoreItemTypeEnum.psDatastoreItemTypeTestCase;
DatastoreItemList psDataList = new DatastoreItemListClass();
psDataList.Query = psQuery;
psDataList.Datastore = m_psDataStore;
// Get the field definitions so we can specify
// them in the result and sort list.
FieldDefinitions psFields = m_psDataStore.FieldDefinitions;
// Add fields with the FieldDefinitions indexer
psQuery.QueryFields.Clear();
for (int fieldCount = 0; fieldCount < TEST_CASE_FIELDS.Length; fieldCount++) {
psQuery.QueryFields.Add(psFields[TEST_CASE_FIELDS[fieldCount]]);
}
// Add fields to sort by
for (int fieldCount = 0; fieldCount < TEST_CASE_SORT.Length; fieldCount++) {
psQuery.QuerySortFields.Add(psFields[TEST_CASE_SORT[fieldCount]],
PsSortTypeEnum.psSortTypeAscending);
}
psDataList.Execute();
ExportCases(testType, profileName, psDataList.DatastoreItems);
}
private void ExportCases(string testType, string profileName, DatastoreItems items)
{
XmlTextWriter oo = newXmlProfile(testType, profileName);
string prevModule = "";
string prevSuite = "";
foreach (DatastoreItem psItem in items) {
object module = psItem.Fields["Test Module"].Value;
object suite = psItem.Fields["Test Suite"].Value;
object testcase = psItem.Fields["TestCase"].Value;
if (module == null || suite == null || testcase == null) {
Console.WriteLine("Test case not prepared for automation: {0}", psItem.Fields["ID"].Value);
continue;
}
if (!module.Equals(prevModule)) {
if (prevModule != "") {
// special case the first test case
oo.WriteEndElement();
oo.WriteEndElement();
}
prevModule = module.ToString();
prevSuite = suite.ToString();
oo.WriteStartElement("Module");
oo.WriteAttributeString("Name", prevModule);
oo.WriteStartElement("Suite");
oo.WriteAttributeString("Name", prevSuite);
}
else if (!suite.Equals(prevSuite)) {
prevSuite = suite.ToString();
oo.WriteEndElement();
oo.WriteStartElement("Suite");
oo.WriteAttributeString("Name", prevSuite);
}
oo.WriteStartElement("Test");
oo.WriteAttributeString("Name", testcase.ToString());
object timeout = psItem.Fields["Test Timeout"].Value;
if (timeout != null) {
oo.WriteAttributeString("Timeout", timeout.ToString());
}
object order = psItem.Fields["Order"].Value;
if (order != null) {
oo.WriteAttributeString("Order", order.ToString());
int o;
//NOTE Magic: the 1000s digit in Order determines the pass for the test.
if (Int32.TryParse(order.ToString(), out o) && o / 1000 > 0) {
oo.WriteAttributeString("Pass", "" + (o / 1000));
}
}
object knownFailure = psItem.Fields["Test Known Failure"].Value;
if (knownFailure != null) {
oo.WriteAttributeString("KnownFailure", knownFailure.ToString());
}
oo.WriteEndElement();
}
if (prevModule != "") {
oo.WriteEndElement(); // suite
oo.WriteEndElement(); // module
}
oo.WriteEndElement();
oo.WriteEndDocument();
oo.Close();
}
private static XmlTextWriter newXmlProfile(string testType, string profileName)
{
XmlTextWriter oo = new XmlTextWriter(profileName, null);
oo.Formatting = Formatting.Indented;
oo.Indentation = 4;
oo.WriteStartDocument();
oo.WriteComment("Export of test type " + testType);
oo.WriteComment("GENERATED FILE. DO NOT EDIT. Add test cases via Product Studio, according to SDN 51");
oo.WriteStartElement("Profile");
oo.WriteAttributeString("Name", testType);
return oo;
}
}
}