jenkinsci/hpe-application-automation-tools-plugin

View on GitHub
HpToolsLauncher/Utils/Helper.cs

Summary

Maintainability
B
4 hrs
Test Coverage
/*
 * Certain versions of software accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company.
 * This software was acquired by Micro Focus on September 1, 2017, and is now offered by OpenText.
 * Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.
 * __________________________________________________________________
 * MIT License
 *
 * Copyright 2012-2024 Open Text
 *
 * The only warranties for products and services of Open Text and
 * its affiliates and licensors ("Open Text") are as may be set forth
 * in the express warranty statements accompanying such products and services.
 * Nothing herein should be construed as constituting an additional warranty.
 * Open Text shall not be liable for technical or editorial errors or
 * omissions contained herein. The information contained herein is subject
 * to change without notice.
 *
 * Except as specifically indicated otherwise, this document contains
 * confidential information and a valid license is required for possession,
 * use or copying. If this work is provided to the U.S. Government,
 * consistent with FAR 12.211 and 12.212, Commercial Computer Software,
 * Computer Software Documentation, and Technical Data for Commercial Items are
 * licensed to the U.S. Government under vendor's standard commercial license.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ___________________________________________________________________
 */

using HpToolsLauncher.Properties;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.UI;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace HpToolsLauncher.Utils
{
    public enum TestType
    {
        Unknown,
        QTP,
        ST,
        LoadRunner,
        ParallelRunner
    }

    public enum TestState
    {
        Waiting,
        Running,
        NoRun,
        Passed,
        Failed,
        Error,
        Warning,
        Unknown,
    }

    public enum TestResult
    {
        Passed,
        Failed,
        Warning,
        Done,
    }

    public static class Helper
    {
        #region Constants

        public const string FT_REG_ROOT = @"SOFTWARE\Mercury Interactive\QuickTest Professional\CurrentVersion";

        internal const string FT_REG_ROOT_64_BIT = @"SOFTWARE\Wow6432Node\Mercury Interactive\QuickTest Professional\CurrentVersion";

        public const string FT_ROOT_PATH_KEY = "QuickTest Professional";
        private const string QTP_ROOT_ENV_VAR_NAME = "QTP_TESTS_ROOT";

        public const string ServiceTestRegistryKey = @"SOFTWARE\Hewlett-Packard\HP Service Test";
        public const string ServiceTesCurrentVersionRegistryKey = ServiceTestRegistryKey + @"\CurrentVersion";

        public const string ServiceTesWOW64RegistryKey = @"SOFTWARE\Wow6432Node\Hewlett-Packard\HP Service Test";
        public const string ServiceTesCurrentVersionWOW64RegistryKey = ServiceTesWOW64RegistryKey + @"\CurrentVersion";

        public const string LoadRunnerRegistryKey = @"SOFTWARE\Mercury Interactive\LoadRunner";
        public const string LoadRunner64RegisryKey = @"SOFTWARE\Wow6432Node\Mercury Interactive\LoadRunner";
        public const string LoadRunnerControllerRegistryKey = @"CustComponent\Controller\CurrentVersion";
        public const string LoadRunnerControllerDirRegistryKey = @"\CurrentVersion";

        public const string LoadRunnerControllerDirRegistryValue = @"\Controller";

        public static readonly System.Collections.ObjectModel.ReadOnlyCollection<string> LoadRunnerENVVariables =
            new System.Collections.ObjectModel.ReadOnlyCollection<string>(new[] { "LG_PATH", "LR_PATH" });

        public const string InstalltionFolderValue = "LOCAL_MLROOT";

        public const string UftViewerInstalltionFolderRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{E86D56AE-6660-4357-890F-8B79AB7A8F7B}";

        public const string UftViewerInstalltionFolderRegistryKey64Bit = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{E86D56AE-6660-4357-890F-8B79AB7A8F7B}";

        public const string ResultsFileName = "Results.xml";
        public const string QTPReportProcessPath = @"bin\reportviewer.exe";

        public const string STFileExt = ".st";
        public const string QTPFileExt = ".tsp";
        public const string LoadRunnerFileExt = ".lrs";
        public const string MtbFileExt = ".mtb";
        public const string MtbxFileExt = ".mtbx";

        private const string SOFTWARE_Classes_AppID_A67EB23A = @"SOFTWARE\Classes\AppID\{A67EB23A-1B8F-487D-8E38-A6A3DD150F0B}";

        private const string SYSTEM_CURRENTCONTROLSET_CONTROL = @"SYSTEM\CurrentControlSet\Control";
        private const string INTERACTIVE_USER = "Interactive User";
        private const string RUN_AS = "RunAs";
        private const string CONTAINER_TYPE = "ContainerType";
        private const string UNABLE_TO_CHANGE_DCOM_SETTINGS = "Unable to change DCOM settings. To change it manually: run dcomcnfg.exe -> My Computer -> DCOM Config -> QuickTest Professional Automation -> Identity -> and select The Interactive User.";
        private const string BYPASS_DCOM_SETTINGS_CHECK = "Bypass DCOM settings check, since the process runs inside a Docker container.";

        #endregion

        public static Assembly HPToolsAssemblyResolver(object sender, ResolveEventArgs args)
        {
            AssemblyName asmName = new AssemblyName(args.Name);
            if (asmName == null) return null;

            string assemblyName = asmName.Name;
            if (assemblyName.EndsWith(".resources")) return null;

            if (assemblyName == "HpToolsLauncher.XmlSerializers") return null;

            string installtionPath = null;
            installtionPath = Helper.getLRInstallPath();
            if (installtionPath == null)
            {
                ConsoleWriter.WriteErrLine(string.Format(Resources.LoadRunnerNotInstalled,
                    System.Environment.MachineName));
                Environment.Exit((int)Launcher.ExitCodeEnum.Aborted);
            }

            installtionPath = Path.Combine(installtionPath, "bin");

            Assembly ans;
            if (!File.Exists(Path.Combine(installtionPath, assemblyName + ".dll")))
            {
                //resource!
                ConsoleWriter.WriteErrLine("cannot locate " + assemblyName + ".dll in installation directory");
                Environment.Exit((int)Launcher.ExitCodeEnum.Aborted);
            }
            else
            {
                //Console.WriteLine("loading " + assemblyName + " from " + Path.Combine(installtionPath, assemblyName + ".dll"));
                ans = Assembly.LoadFrom(Path.Combine(installtionPath, assemblyName + ".dll"));

                AssemblyName loadedName = ans.GetName();
                if (loadedName.Name == "Interop.Wlrun")
                {
                    if (loadedName.Version.Major > 11 ||
                        (loadedName.Version.Major == 11 && loadedName.Version.Minor >= 52))
                    {
                        return ans;
                    }
                    else
                    {
                        ConsoleWriter.WriteErrLine(string.Format(Resources.HPToolsAssemblyResolverWrongVersion,
                            Environment.MachineName));
                        Environment.Exit((int)Launcher.ExitCodeEnum.Aborted);
                    }
                }
                else
                {
                    return ans;
                }
            }
            return null;
        }

        public static string GetRootDirectoryPath()
        {
            string directoryPath;
            RegistryKey regkey = Registry.LocalMachine.OpenSubKey(FT_REG_ROOT);

            if (regkey != null)
                directoryPath = (string)regkey.GetValue(FT_ROOT_PATH_KEY);
            else
            {
                //TRY 64 bit REG path
                regkey = Registry.LocalMachine.OpenSubKey(FT_REG_ROOT_64_BIT);
                if (regkey != null)
                    directoryPath = (string)regkey.GetValue(FT_ROOT_PATH_KEY);
                else
                    directoryPath = GetRootFromEnvironment();
            }

            return directoryPath;
        }

        // verify that files/folders exist (does not recurse into folders)
        public static List<TestData> ValidateFiles(IEnumerable<TestData> tests)
        {
            List<TestData> validTests = new List<TestData>();
            string testPath = string.Empty;

            foreach (TestData test in tests)
            {
                // If for FS tests params are specified, it should like this: <testPath> <paramList> separated by one or more spaces,
                // we should only validate the path, otherwise failure
                testPath = GetTestPathWithoutParams(test.Tests);

                if (!File.Exists(testPath) && !Directory.Exists(testPath))
                {
                    ConsoleWriter.WriteErrLine(string.Format("File/Folder not found: '{0}'", test.Tests));
                    Launcher.ExitCode = Launcher.ExitCodeEnum.Failed;
                }
                else
                {
                    validTests.Add(test);
                }
            }
            return validTests;
        }

        public static string GetTestPathWithoutParams(string test)
        {
            int quotationMarkIndex = test.IndexOf(" \"", StringComparison.Ordinal);
            return quotationMarkIndex == -1 ? test : test.Substring(0, quotationMarkIndex).Trim();
        }

        public static bool FileExists(string filePath)
        {
            bool isFileValid = true;
            if (!File.Exists(filePath))
            {
                ConsoleWriter.WriteLine(string.Format(">>>> File not found: '{0}'", filePath));
                isFileValid = false;
                Launcher.ExitCode = Launcher.ExitCodeEnum.Failed;
            }

            return isFileValid;
        }

        /// <summary>
        /// Checks if test parameters list is valid or not
        /// </summary>
        /// <param name="params"></param>
        /// <param name="paramNames"></param>
        /// <param name="paramValues"></param>
        /// <returns>true if parameters the list of parameters is valid, false otherwise</returns>
        public static bool ValidateInlineParams(string[] @params, out IList<string> paramNames, out IList<string> paramValues)
        {
            if (@params == null) throw new ArgumentNullException("Parameters are missing");
            paramNames = new List<string>();
            paramValues = new List<string>();

            if (@params.Any())
            {
                foreach (var parameterPair in @params)
                {
                    if (!string.IsNullOrWhiteSpace(parameterPair))
                    {
                        string[] pair = parameterPair.Split(':');

                        string paramName = pair[0].Trim();
                        if (!CheckParamFormat(paramName))
                        {
                            ConsoleWriter.WriteLine(string.Format(Resources.MissingQuotesInParamFormat, "parameter name"));
                            return false;
                        }

                        paramName = NormalizeParam(paramName);
                        if (string.IsNullOrWhiteSpace(paramName))
                        {
                            ConsoleWriter.WriteLine(Resources.MissingParameterName);
                            return false;
                        }
                        paramNames.Add(paramName);

                        string paramValue = pair[1].Trim();
                        if (!CheckParamFormat(paramValue))
                        {
                            ConsoleWriter.WriteLine(string.Format(Resources.MissingQuotesInParamFormat, "parameter value"));
                            return false;
                        }

                        paramValue = NormalizeParam(paramValue);
                        if (paramValue == null)
                        {
                            ConsoleWriter.WriteLine(Resources.MissingParameterValue);
                            return false;
                        }
                        paramValues.Add(paramValue);
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        private static bool CheckParamFormat(string param)
        {
            long _unused;
            if (!string.IsNullOrEmpty(param) && long.TryParse(param, out _unused))
            {
                return true;
            }
            else
            {
                // must be at least 2 characters wide, containing at least 2 double quotes
                if (param.Length < 2) return false;

                // first and at last characters have to be double quotes
                if (!param.StartsWith("\"") && !param.EndsWith("\"")) return false;

                return true;
            }
        }

        /// <summary>
        /// Normalizes test parameter, by removing the double quotes
        /// </summary>
        /// <param name="param"></param>
        /// <returns>true if parameter is valid, false otherwise</returns>
        private static string NormalizeParam(string param)
        {
            if (!string.IsNullOrWhiteSpace(param))
            {
                long n = long.MaxValue;
                bool isNumeric = !string.IsNullOrEmpty(param) && long.TryParse(param, out n);

                if (isNumeric)
                {
                    return n.ToString();
                }
                else
                {
                    if (param.Length >= 2)
                    {
                        return param.Substring(1, param.Length - 2);
                    }
                }
            }

            return null;
        }

        public static bool IsTestingToolsInstalled(TestStorageType type)
        {
            //we want to check if we have Service Test, QTP installed on a machine

            return IsQtpInstalled() || IsServiceTestInstalled() || isLoadRunnerInstalled();

        }

        public static bool isLoadRunnerInstalled()
        {
            //try 32 bit
            RegistryKey regkey = Registry.LocalMachine.OpenSubKey(LoadRunnerRegistryKey);

            if (regkey == null)
            {
                //try 64-bit
                regkey = Registry.LocalMachine.OpenSubKey(LoadRunner64RegisryKey);

            }

            if (regkey != null)
            {

                //LoadRunner Exist.
                //check if Controller is installed (not SA version)

                if (regkey.OpenSubKey(LoadRunnerControllerRegistryKey) != null)
                {
                    return true;
                }

            }
            return false;

        }

        public static bool IsQtpInstalled()
        {
            RegistryKey regkey;
            string value;
            regkey = Registry.LocalMachine.OpenSubKey(FT_REG_ROOT);
            if (regkey == null)
            {
                //try 64 bit
                regkey = Registry.LocalMachine.OpenSubKey(FT_REG_ROOT_64_BIT);
            }

            if (regkey != null)
            {
                value = (string)regkey.GetValue(FT_ROOT_PATH_KEY);
                if (!string.IsNullOrEmpty(value))
                {
                    return true;
                }
            }
            return false;
        }

        public static bool IsServiceTestInstalled()
        {
            RegistryKey regkey;
            string value;
            regkey = Registry.LocalMachine.OpenSubKey(ServiceTesCurrentVersionRegistryKey);
            if (regkey == null)
            {
                //try 64 bit
                regkey = Registry.LocalMachine.OpenSubKey(ServiceTesCurrentVersionWOW64RegistryKey);
            }

            if (regkey != null)
            {
                value = (string)regkey.GetValue(InstalltionFolderValue);
                if (!string.IsNullOrEmpty(value))
                {
                    return true;
                }
            }
            return false;
        }

        private static string GetRootFromEnvironment()
        {
            string qtpRoot = Environment.GetEnvironmentVariable(QTP_ROOT_ENV_VAR_NAME, EnvironmentVariableTarget.Process);

            if (string.IsNullOrEmpty(qtpRoot))
            {
                qtpRoot = Environment.GetEnvironmentVariable(QTP_ROOT_ENV_VAR_NAME, EnvironmentVariableTarget.User);

                if (string.IsNullOrEmpty(qtpRoot))
                {
                    qtpRoot = Environment.GetEnvironmentVariable(QTP_ROOT_ENV_VAR_NAME,
                        EnvironmentVariableTarget.Machine);

                    if (string.IsNullOrEmpty(qtpRoot))
                    {
                        qtpRoot = Environment.CurrentDirectory;
                    }
                }
            }

            return qtpRoot;
        }

        public static string GetSTInstallPath()
        {
            string ret = string.Empty;
            var regKey = Registry.LocalMachine.OpenSubKey(ServiceTesCurrentVersionRegistryKey);
            if (regKey != null)
            {
                var val = regKey.GetValue(InstalltionFolderValue);
                if (null != val)
                {
                    ret = val.ToString();
                }
            }
            else
            {
                regKey = Registry.LocalMachine.OpenSubKey(ServiceTesCurrentVersionWOW64RegistryKey);
                if (regKey != null)
                {
                    var val = regKey.GetValue(InstalltionFolderValue);
                    if (null != val)
                    {
                        ret = val.ToString();
                    }
                }
                else
                {
                    ret = GetRootDirectoryPath() ?? string.Empty;
                }
            }

            if (!string.IsNullOrEmpty(ret))
            {
                ret = ret.EndsWith("\\") ? ret : (ret + "\\");
                if (ret.EndsWith("\\bin\\"))
                {
                    int endIndex = ret.LastIndexOf("\\bin\\");
                    if (endIndex != -1)
                    {
                        ret = ret.Substring(0, endIndex) + "\\";
                    }
                }
            }

            return ret;
        }

        public static string getLRInstallPath()
        {
            string installPath = null;
            System.Collections.IDictionary envVariables = Environment.GetEnvironmentVariables();

            //try to find LoadRunner install path in environment vars
            foreach (string variable in LoadRunnerENVVariables)
            {
                if (envVariables.Contains(variable))
                    return envVariables[variable] as string;
            }

            //Fallback to registry
            //try 32 bit
            RegistryKey regkey = Registry.LocalMachine.OpenSubKey(LoadRunnerRegistryKey);

            if (regkey == null)
            {
                //try 64-bit
                regkey = Registry.LocalMachine.OpenSubKey(LoadRunner64RegisryKey);
            }

            if (regkey != null)
            {
                //LoadRunner Exists. check if Controller is installed (not SA version)
                regkey = regkey.OpenSubKey(LoadRunnerControllerDirRegistryKey);
                if (regkey != null)
                    return regkey.GetValue("Controller").ToString();
            }

            return installPath;
        }

        public static List<string> GetTestsLocations(string baseDir)
        {
            var testsLocations = new List<string>();
            if (string.IsNullOrEmpty(baseDir) || !Directory.Exists(baseDir))
            {
                return testsLocations;
            }

            WalkDirectoryTree(new DirectoryInfo(baseDir), ref testsLocations);
            return testsLocations;
        }

        public static TestType GetTestType(string path)
        {
            if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory)
            {
                //ST and QTP uses folder as test locations
                var stFiles = Directory.GetFiles(path,
                    @"*.st?",
                    SearchOption.TopDirectoryOnly);

                return (stFiles.Count() > 0) ? TestType.ST : TestType.QTP;
            }
            else //not directory
            {
                //loadrunner is a path to file...
                return TestType.LoadRunner;
            }
        }

        public static bool IsDirectory(string path)
        {
            var fa = File.GetAttributes(path);
            var isDirectory = false;
            if ((fa & FileAttributes.Directory) != 0)
            {
                isDirectory = true;
            }
            return isDirectory;
        }

        static void WalkDirectoryTree(DirectoryInfo root, ref List<string> results)
        {
            FileInfo[] files = null;
            DirectoryInfo[] subDirs;

            // First, process all the files directly under this folder
            try
            {

                files = root.GetFiles("*" + STFileExt);
                files = files.Union(root.GetFiles("*" + QTPFileExt)).ToArray();
                files = files.Union(root.GetFiles("*" + LoadRunnerFileExt)).ToArray();
            }
            catch (Exception)
            {
                // This code just writes out the message and continues to recurse.
                // You may decide to do something different here. For example, you
                // can try to elevate your privileges and access the file again.
                //log.Add(e.Message);
            }

            if (files != null)
            {
                foreach (FileInfo fi in files)
                {
                    if (fi.Extension == LoadRunnerFileExt)
                        results.Add(fi.FullName);
                    else
                        results.Add(fi.Directory.FullName);

                    // In this example, we only access the existing FileInfo object. If we
                    // want to open, delete or modify the file, then
                    // a try-catch block is required here to handle the case
                    // where the file has been deleted since the call to TraverseTree().
                }

                // Now find all the subdirectories under this directory.
                subDirs = root.GetDirectories();

                foreach (DirectoryInfo dirInfo in subDirs)
                {
                    // Recursive call for each subdirectory.
                    WalkDirectoryTree(dirInfo, ref results);
                }
            }
        }

        public static string GetTempDir()
        {
            string baseTemp = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            string dirName = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 6);
            string tempDirPath = Path.Combine(baseTemp, dirName);

            return tempDirPath;
        }

        public static string CreateTempDir()
        {
            string tempDirPath = GetTempDir();

            Directory.CreateDirectory(tempDirPath);

            return tempDirPath;
        }

        public static bool IsNetworkPath(string path)
        {
            if (path.StartsWith(@"\\"))
                return true;
            var dir = new DirectoryInfo(path);
            var drive = new DriveInfo(dir.Root.ToString());
            return drive.DriveType == DriveType.Network;
        }

        public static bool IsLeanFTRunning()
        {
            bool bRet = false;
            Process[] procArray = Process.GetProcessesByName("LFTRuntime");
            // Hardcoded temporarily since LeanFT does not store the process name anywhere
            if (procArray.Length != 0)
            {
                bRet = true;
            }
            return bRet;
        }

        public static bool IsSprinterRunning()
        {
            RegistryKey key =
                Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Hewlett-Packard\\Manual Runner\\Process");
            if (key == null)
                return false;

            var arrayName = key.GetSubKeyNames();
            if (arrayName.Length == 0)
                return false;
            foreach (string s in arrayName)
            {
                Process[] sprinterProcArray = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(s));
                if (sprinterProcArray.Length != 0)
                    return true;

            }
            return false;
        }

        public static bool CanUftProcessStart(out string reason)
        {
            //Close UFT when some of the Sprinter processes is running
            if (IsSprinterRunning())
            {
                reason = Resources.UFT_Sprinter_Running;
                return false;
            }

            //Close UFT when LeanFT engine is running
            if (IsLeanFTRunning())
            {
                reason = Resources.UFT_LeanFT_Running;
                return false;
            }
            reason = string.Empty;
            return true;
        }

        public static string GetParallelRunnerDirectory(string parallelRunnerExecutable)
        {
            if (parallelRunnerExecutable == null) return null;

            var uftFolder = GetSTInstallPath();

            if (uftFolder == null) return null;

            return uftFolder + @"bin\" + parallelRunnerExecutable;
        }

        /// <summary>
        /// Why we need this? If we run jenkins in a master slave node where there is a jenkins service installed in the slave machine, we need to change the DCOM settings as follow:
        /// dcomcnfg.exe -> My Computer -> DCOM Config -> QuickTest Professional Automation -> Identity -> and select The Interactive User
        /// </summary>
        public static void ChangeDCOMSettingToInteractiveUser()
        {
            if (IsInDocker())
            {
                ConsoleWriter.WriteLine(BYPASS_DCOM_SETTINGS_CHECK);
                return;
            }
            try
            {
                var regKey = GetQuickTestProfessionalAutomationRegKey(RegistryView.Registry32);

                if (regKey == null)
                {
                    regKey = GetQuickTestProfessionalAutomationRegKey(RegistryView.Registry64);
                }

                if (regKey == null)
                    throw new Exception(string.Format("Unable to find in registry key {0}", SOFTWARE_Classes_AppID_A67EB23A));

                object runAsKey = regKey.GetValue(RUN_AS);

                if (runAsKey == null || !runAsKey.ToString().Equals(INTERACTIVE_USER))
                {
                    regKey.SetValue(RUN_AS, INTERACTIVE_USER);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("{0}. Error: ", UNABLE_TO_CHANGE_DCOM_SETTINGS, ex.Message));
            }
        }

        private static bool IsInDocker()
        {
            int containerType = 0;
            try
            {
                RegistryKey regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
                regKey = regKey.OpenSubKey(SYSTEM_CURRENTCONTROLSET_CONTROL, false);
                containerType = (regKey.GetValue(CONTAINER_TYPE) as int?).GetValueOrDefault();
            }
            catch (Exception ex)
            {
                ConsoleWriter.WriteErrLine(string.Format("IsInDocker() function error: {0}", ex.Message));
            }
            return containerType > 0;
        }

        public static RegistryKey GetQuickTestProfessionalAutomationRegKey(RegistryView registry32)
        {
            RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
            localKey = localKey.OpenSubKey(SOFTWARE_Classes_AppID_A67EB23A, true);

            return localKey;
        }

        /// <summary>
        /// Return the path of the available results folder for the parallel runner.
        /// </summary>
        /// <param name="testInfo"> The test information. </param>
        /// <returns>
        /// the path to the results folder 
        /// </returns>
        public static string GetNextResFolder(string reportPath, string resultFolderName)
        {
            // since ParallelRunner will store the report as "Res1...ResN"
            // we need to know before parallel runner creates the result folder
            // what the folder name will be
            // so we know which result is ours(or if there was any result)
            int resultFolderIndex = 1;

            while (Directory.Exists(Path.Combine(reportPath, resultFolderName + resultFolderIndex)))
            {
                resultFolderIndex += 1;
            }

            return reportPath + "\\" + resultFolderName + resultFolderIndex;
        }

        #region Report Related

        /// <summary>
        /// Set the error for a test when the report path is invalid.
        /// </summary>
        /// <param name="runResults"> The test run results </param>
        /// <param name="errorReason"> The error reason </param>
        /// <param name="testInfo"> The test informatio </param>
        public static void SetTestReportPathError(TestRunResults runResults, ref string errorReason, TestInfo testInfo)
        {
            // Invalid path was provided, return useful description
            errorReason = string.Format(Resources.InvalidReportPath, runResults.ReportLocation);

            // since the report path is invalid, the test should fail
            runResults.TestState = TestState.Error;
            runResults.ErrorDesc = errorReason;

            // output the error for the current test run
            ConsoleWriter.WriteErrLine(runResults.ErrorDesc);

            // include the error in the summary
            ConsoleWriter.ErrorSummaryLines.Add(runResults.ErrorDesc);

            // provide the appropriate exit code for the launcher
            Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed;
        }

        /// <summary>
        /// Try to set the custom report path for a given test.
        /// </summary>
        /// <param name="runResults"> The test run results </param>
        /// <param name="testInfo"> The test information </param>
        /// <param name="errorReason"> The error reason </param>
        /// <returns> True if the report path was set, false otherwise </returns>
        public static bool TrySetTestReportPath(TestRunResults runResults, TestInfo testInfo, ref string errorReason)
        {
            string testName = testInfo.TestName.Substring(testInfo.TestName.LastIndexOf('\\') + 1) + "_";
            string reportLocation = Helper.GetNextResFolder(testInfo.ReportPath, testName);

            // set the report location for the run results
            runResults.ReportLocation = reportLocation;
            try
            {
                Directory.CreateDirectory(runResults.ReportLocation);
            }
            catch (Exception)
            {
                SetTestReportPathError(runResults, ref errorReason, testInfo);
                return false;
            }

            return true;
        }

        public static string GetUftViewerInstallPath()
        {
            string ret = string.Empty;
            var regKey = Registry.LocalMachine.OpenSubKey(UftViewerInstalltionFolderRegistryKey) ??
                         Registry.LocalMachine.OpenSubKey(UftViewerInstalltionFolderRegistryKey64Bit);

            if (regKey != null)
            {
                var val = regKey.GetValue("InstallLocation");
                if (null != val)
                {
                    ret = val.ToString();
                }
            }

            if (!string.IsNullOrEmpty(ret))
            {
                ret = ret.EndsWith("\\") ? ret : (ret + "\\");
            }

            return ret;
        }

        public static string GetLastRunFromReport(string reportPath)
        {
            if (!Directory.Exists(reportPath))
                return null;
            string resultsFileFullPath = reportPath + @"\" + ResultsFileName;
            if (!File.Exists(resultsFileFullPath))
                return null;
            try
            {
                var root = XElement.Load(resultsFileFullPath);

                var element = root.XPathSelectElement("//Doc/Summary");
                var lastStartRun = element.Attribute("sTime");
                return lastStartRun.Value.Split(new char[] { ' ' })[0];

            }
            catch (Exception)
            {
                return null;
            }
        }

        public static TestState GetTestStateFromUFTReport(TestRunResults runDesc, string[] resultFiles)
        {
            try
            {
                TestState finalState = TestState.Unknown;

                foreach (string resultsFileFullPath in resultFiles)
                {
                    finalState = TestState.Unknown;
                    string desc = string.Empty;
                    TestState state = GetStateFromUFTResultsFile(resultsFileFullPath, out desc);
                    if (finalState == TestState.Unknown || finalState == TestState.Passed)
                    {
                        finalState = state;
                        if (!string.IsNullOrWhiteSpace(desc))
                        {
                            if (finalState == TestState.Error)
                            {
                                runDesc.ErrorDesc = desc;
                            }
                            if (finalState == TestState.Failed)
                            {
                                runDesc.FailureDesc = desc;
                            }
                        }
                    }
                }

                if (finalState == TestState.Unknown)
                    finalState = TestState.Passed;

                if (finalState == TestState.Failed && string.IsNullOrWhiteSpace(runDesc.FailureDesc))
                    runDesc.FailureDesc = "Test failed";

                runDesc.TestState = finalState;
                return runDesc.TestState;
            }
            catch (Exception)
            {
                return TestState.Unknown;
            }

        }

        public static TestState GetTestStateFromLRReport(TestRunResults runDesc, string[] resultFiles)
        {

            foreach (string resultFileFullPath in resultFiles)
            {
                string desc = string.Empty;
                runDesc.TestState = GetTestStateFromLRReport(resultFileFullPath, out desc);
                if (runDesc.TestState == TestState.Failed)
                {
                    runDesc.ErrorDesc = desc;
                    break;
                }
            }

            return runDesc.TestState;
        }

        public static TestState GetTestStateFromReport(TestRunResults runDesc)
        {
            try
            {
                if (!Directory.Exists(runDesc.ReportLocation))
                {
                    runDesc.ErrorDesc = string.Format(Resources.DirectoryNotExistError, runDesc.ReportLocation);

                    runDesc.TestState = TestState.Error;
                    return runDesc.TestState;
                }
                //if there is Result.xml -> UFT
                //if there is sla.xml file -> LR
                //if there is parallelrun_results.xml -> ParallelRunner

                string[] resultFiles = Directory.GetFiles(runDesc.ReportLocation, "Results.xml",
                    SearchOption.TopDirectoryOnly);
                if (resultFiles.Length == 0)
                    resultFiles = Directory.GetFiles(runDesc.ReportLocation, "run_results.xml",
                        SearchOption.TopDirectoryOnly);
                //resultFiles = Directory.GetFiles(Path.Combine(runDesc.ReportLocation, "Report"), "Results.xml", SearchOption.TopDirectoryOnly);

                if (resultFiles != null && resultFiles.Length > 0)
                    return GetTestStateFromUFTReport(runDesc, resultFiles);

                resultFiles = Directory.GetFiles(runDesc.ReportLocation, "SLA.xml", SearchOption.AllDirectories);

                if (resultFiles != null && resultFiles.Length > 0)
                {
                    return GetTestStateFromLRReport(runDesc, resultFiles);
                }

                resultFiles = Directory.GetFiles(runDesc.ReportLocation, "parallelrun_results.html", SearchOption.TopDirectoryOnly);

                // the overall status is given by parallel runner
                // at the end of the run
                if (resultFiles != null && resultFiles.Length > 0)
                {
                    return runDesc.TestState;
                }

                //no LR or UFT => error
                runDesc.ErrorDesc = string.Format("no results file found for " + runDesc.TestName);
                runDesc.TestState = TestState.Error;
                return runDesc.TestState;
            }
            catch (Exception)
            {
                return TestState.Unknown;
            }

        }

        private static TestState GetTestStateFromLRReport(string resultFileFullPath, out string desc)
        {
            XmlDocument xdoc = new XmlDocument();
            xdoc.Load(resultFileFullPath);
            return CheckNodeStatus(xdoc.DocumentElement, out desc);
        }

        private static TestState CheckNodeStatus(XmlNode node, out string desc)
        {
            desc = string.Empty;
            if (node == null)
                return TestState.Failed;

            if (node.ChildNodes.Count == 1 && node.ChildNodes[0].NodeType == XmlNodeType.Text)
            {
                if (node.InnerText.ToLowerInvariant() == "failed")
                {
                    if (node.Attributes != null && node.Attributes["FullName"] != null)
                    {
                        desc = string.Format(Resources.LrSLARuleFailed, node.Attributes["FullName"].Value,
                            node.Attributes["GoalValue"].Value, node.Attributes["ActualValue"].Value);
                        ConsoleWriter.WriteLine(desc);
                    }
                    return TestState.Failed;
                }
                else
                {
                    return TestState.Passed;
                }
            }
            //node has children
            foreach (XmlNode childNode in node.ChildNodes)
            {
                TestState res = CheckNodeStatus(childNode, out desc);
                if (res == TestState.Failed)
                {
                    if (string.IsNullOrEmpty(desc) && node.Attributes != null && node.Attributes["FullName"] != null)
                    {
                        desc = string.Format(Resources.LrSLARuleFailed, node.Attributes["FullName"].Value,
                            node.Attributes["GoalValue"].Value, node.Attributes["ActualValue"].Value);
                        ConsoleWriter.WriteLine(desc);
                    }
                    return TestState.Failed;
                }
            }
            return TestState.Passed;
        }

        private static TestState GetStateFromUFTResultsFile(string resultsFileFullPath, out string desc)
        {
            TestState finalState = TestState.Unknown;
            desc = string.Empty;
            string status;
            var doc = new XmlDocument { PreserveWhitespace = true };
            doc.Load(resultsFileFullPath);
            string strFileName = Path.GetFileName(resultsFileFullPath);
            if (strFileName.Equals("run_results.xml"))
            {
                XmlNodeList rNodeList = doc.SelectNodes("/Results/ReportNode/Data");
                if (rNodeList == null)
                {
                    desc = string.Format(Resources.XmlNodeNotExistError, "/Results/ReportNode/Data");
                    finalState = TestState.Error;
                }

                var node = rNodeList.Item(0);
                XmlNode resultNode = ((XmlElement)node).GetElementsByTagName("Result").Item(0);

                status = resultNode.InnerText;
            }
            else
            {
                var testStatusPathNode = doc.SelectSingleNode("//Report/Doc/NodeArgs");
                if (testStatusPathNode == null)
                {
                    desc = string.Format(Resources.XmlNodeNotExistError, "//Report/Doc/NodeArgs");
                    finalState = TestState.Error;
                }

                if (!testStatusPathNode.Attributes["status"].Specified)
                    finalState = TestState.Unknown;

                status = testStatusPathNode.Attributes["status"].Value;
            }

            var result = (TestResult)Enum.Parse(typeof(TestResult), status);
            if (result == TestResult.Passed || result == TestResult.Done)
            {
                finalState = TestState.Passed;
            }
            else if (result == TestResult.Warning)
            {
                finalState = TestState.Warning;
            }
            else
            {
                finalState = TestState.Failed;
            }

            return finalState;
        }

        public static string GetUnknownStateReason(string reportPath)
        {
            if (!Directory.Exists(reportPath))
            {
                return string.Format("Directory '{0}' doesn't exist", reportPath);
            }
            string resultsFileFullPath = reportPath + @"\" + ResultsFileName;
            if (!File.Exists(resultsFileFullPath))
            {
                return string.Format("Could not find results file '{0}'", resultsFileFullPath);
            }

            var doc = new XmlDocument { PreserveWhitespace = true };
            doc.Load(resultsFileFullPath);
            var testStatusPathNode = doc.SelectSingleNode("//Report/Doc/NodeArgs");
            if (testStatusPathNode == null)
            {
                return string.Format("XML node '{0}' could not be found", "//Report/Doc/NodeArgs");
            }
            return string.Empty;
        }

        public static void OpenReport(string reportDirectory, ref string optionalReportViewerPath)
        {
            Process p = null;
            try
            {
                string viewerPath = optionalReportViewerPath;
                string reportPath = reportDirectory;
                string resultsFilePath = reportPath + "\\" + ResultsFileName;

                if (!File.Exists(resultsFilePath))
                {
                    return;
                }

                var si = new ProcessStartInfo();
                if (string.IsNullOrEmpty(viewerPath))
                {
                    viewerPath = GetUftViewerInstallPath();
                    optionalReportViewerPath = viewerPath;
                }
                si.Arguments = " -r \"" + reportPath + "\"";

                si.FileName = Path.Combine(viewerPath, QTPReportProcessPath);
                si.WorkingDirectory = Path.Combine(viewerPath, @"bin" + @"\");

                p = Process.Start(si);
                if (p != null)
                {
                }
                return;
            }
            catch (Exception)
            {
            }
            finally
            {
                if (p != null)
                {
                    p.Close();
                }
            }
            return;
        }

        #endregion

        #region Export Related

        /// <summary>
        /// Copy directories from source to target
        /// </summary>
        /// <param name="sourceDir">full path source directory</param>
        /// <param name="targetDir">full path target directory</param>
        /// <param name="includeSubDirectories">if true, all subdirectories and contents will be copied</param>
        /// <param name="includeRoot">if true, the source directory will be created too</param>
        public static void CopyDirectories(string sourceDir, string targetDir,
            bool includeSubDirectories = false, bool includeRoot = false)
        {
            var source = new DirectoryInfo(sourceDir);
            var target = new DirectoryInfo(targetDir);
            DirectoryInfo workingTarget = target;

            if (includeRoot)
                workingTarget = Directory.CreateDirectory(target.FullName);

            CopyContents(source, workingTarget, includeSubDirectories);
        }

        private static void CopyContents(DirectoryInfo source, DirectoryInfo target, bool includeSubDirectories)
        {
            if (!Directory.Exists(target.FullName))
            {
                Directory.CreateDirectory(target.FullName);
            }


            foreach (FileInfo fi in source.GetFiles())
            {
                string targetFile = Path.Combine(target.ToString(), fi.Name);

                fi.CopyTo(targetFile, true);
            }

            if (includeSubDirectories)
            {
                DirectoryInfo[] subDirectories = source.GetDirectories();
                foreach (DirectoryInfo diSourceSubDir in subDirectories)
                {
                    DirectoryInfo nextTargetSubDir =
                        target.CreateSubdirectory(diSourceSubDir.Name);
                    CopyContents(diSourceSubDir, nextTargetSubDir, true);
                }
            }
        }

        public static void CopyFilesFromFolder(string sourceFolder, IEnumerable<string> fileNames, string targetFolder)
        {
            foreach (var fileName in fileNames)
            {
                var sourceFullPath = Path.Combine(sourceFolder, fileName);
                var targetFullPath = Path.Combine(targetFolder, fileName);
                File.Copy(sourceFullPath, targetFullPath, true);
            }
        }

        /// <summary>
        /// Create html file according to a matching xml
        /// </summary>
        /// <param name="xmlPath">the values xml</param>
        /// <param name="xslPath">the xml transformation file</param>
        /// <param name="targetFile">the full file name - where to save the product</param>
        public static void CreateHtmlFromXslt(string xmlPath, string xslPath, string targetFile)
        {
            var xslTransform = new XslCompiledTransform();
            //xslTransform.Load(xslPath);
            xslTransform.Load(xslPath, new XsltSettings(false, true), null);

            var sb = new StringBuilder();
            var sw = new StringWriter(sb);
            var xmlWriter = new XhtmlTextWriter(sw);
            xslTransform.Transform(xmlPath, null, xmlWriter);


            File.WriteAllText(targetFile, sb.ToString());
        }

        #endregion

        public static void DeleteDirectory(string dirPath)
        {
            DirectoryInfo directory = Directory.CreateDirectory(dirPath);
            foreach (FileInfo file in directory.GetFiles()) file.Delete();
            foreach (DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);
            Directory.Delete(dirPath);
        }
    }

    public class Stopper
    {
        private readonly int _milliSeconds;

        public Stopper(int milliSeconds)
        {
            this._milliSeconds = milliSeconds;
        }

        /// <summary>
        /// Creates timer in seconds to replace thread.sleep due to ui freezes in jenkins. 
        /// Should be replaced in the future with ASync tasks
        /// </summary>
        public void Start()
        {
            if (_milliSeconds < 1)
            {
                return;
            }
            DateTime desired = DateTime.Now.AddMilliseconds(_milliSeconds);
            var a = 0;
            while (DateTime.Now < desired)
            {
                a += 1;
            }
        }
    }

}