/// <summary> /// runs the given test /// </summary> /// <param name="testinf"></param> /// <param name="errorReason"></param> /// <param name="runCancelled">cancellation delegate, holds the function that checks cancellation</param> /// <returns></returns> public TestRunResults RunTest(TestInfo testinf, ref string errorReason, RunCancelledDelegate runCancelled) { TestRunResults runDesc = new TestRunResults(); ConsoleWriter.ActiveTestRun = runDesc; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Running: " + testinf.TestPath); runDesc.TestPath = testinf.TestPath; // default report location is the test path runDesc.ReportLocation = testinf.TestPath; // check if the report path has been defined if (!String.IsNullOrEmpty(testinf.ReportPath)) { if (!Helper.TrySetTestReportPath(runDesc, testinf, ref errorReason)) { return(runDesc); } } runDesc.ErrorDesc = errorReason; runDesc.TestState = TestState.Unknown; if (!Helper.IsServiceTestInstalled()) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = string.Format(Resources.LauncherStNotInstalled, System.Environment.MachineName); ConsoleWriter.WriteErrLine(runDesc.ErrorDesc); Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed; return(runDesc); } _runCancelled = runCancelled; if (!_stCanRun) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = Resources.STExecuterNotFound; return(runDesc); } string fileName = Path.Combine(_stExecuterPath, STRunnerName); if (!File.Exists(fileName)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = Resources.STExecuterNotFound; ConsoleWriter.WriteErrLine(Resources.STExecuterNotFound); return(runDesc); } //write the input parameter xml file for the API test string paramFileName = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 10); string tempPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "TestParams"); Directory.CreateDirectory(tempPath); string paramsFilePath = Path.Combine(tempPath, "params" + paramFileName + ".xml"); string paramFileContent = testinf.GenerateAPITestXmlForTest(); string argumentString = ""; if (!string.IsNullOrWhiteSpace(paramFileContent)) { File.WriteAllText(paramsFilePath, paramFileContent); argumentString = String.Format("{0} \"{1}\" {2} \"{3}\" {4} \"{5}\"", STRunnerTestArg, testinf.TestPath, STRunnerReportArg, runDesc.ReportLocation, STRunnerInputParamsArg, paramsFilePath); } else { argumentString = String.Format("{0} \"{1}\" {2} \"{3}\"", STRunnerTestArg, testinf.TestPath, STRunnerReportArg, runDesc.ReportLocation); } Stopwatch s = Stopwatch.StartNew(); runDesc.TestState = TestState.Running; if (!ExecuteProcess(fileName, argumentString, ref errorReason)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; } else { runDesc.ReportLocation = Path.Combine(runDesc.ReportLocation, "Report"); if (!File.Exists(Path.Combine(runDesc.ReportLocation, "Results.xml")) && !File.Exists(Path.Combine(runDesc.ReportLocation, "run_results.html"))) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = "No Results.xml or run_results.html file found"; } } //File.Delete(paramsFilePath); runDesc.Runtime = s.Elapsed; return(runDesc); }
/// <summary> /// runs the given test and returns resutls /// </summary> /// <param name="testPath"></param> /// <param name="errorReason"></param> /// <param name="runCanclled"></param> /// <returns></returns> public TestRunResults RunTest(TestInfo testinf, ref string errorReason, RunCancelledDelegate runCanclled) { var testPath = testinf.TestPath; TestRunResults runDesc = new TestRunResults(); ConsoleWriter.ActiveTestRun = runDesc; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Running test: " + testPath + " ..."); runDesc.TestPath = testPath; // check if the report path has been defined if (!string.IsNullOrWhiteSpace(testinf.ReportPath)) { runDesc.ReportLocation = Path.GetFullPath(testinf.ReportPath); ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Report path is set explicitly: " + runDesc.ReportLocation); } else if (!String.IsNullOrEmpty(testinf.ReportBaseDirectory)) { testinf.ReportBaseDirectory = Path.GetFullPath(testinf.ReportBaseDirectory); if (!Helper.TrySetTestReportPath(runDesc, testinf, ref errorReason)) { return(runDesc); } ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Report path is generated under base directory: " + runDesc.ReportLocation); } else { // default report location is the next available folder under test path // for example, "path\to\tests\GUITest1\Report123", the name "Report123" will also be used as the report name string reportBasePath = Path.GetFullPath(testPath); string testReportPath = Path.Combine(reportBasePath, "Report" + DateTime.Now.ToString("ddMMyyyyHHmmssfff")); int index = 0; while (index < int.MaxValue) { index++; string dir = Path.Combine(reportBasePath, "Report" + index.ToString()); if (!Directory.Exists(dir)) { testReportPath = dir; break; } } runDesc.ReportLocation = testReportPath; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Report path is automatically generated: " + runDesc.ReportLocation); } runDesc.TestState = TestState.Unknown; _runCancelled = runCanclled; if (!Helper.IsQtpInstalled()) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = string.Format(Resources.GeneralQtpNotInstalled, System.Environment.MachineName); ConsoleWriter.WriteErrLine(runDesc.ErrorDesc); Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed; return(runDesc); } string reason = string.Empty; if (!Helper.CanUftProcessStart(out reason)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = reason; ConsoleWriter.WriteErrLine(runDesc.ErrorDesc); Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed; return(runDesc); } try { ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " " + Properties.Resources.LaunchingTestingTool); ChangeDCOMSettingToInteractiveUser(); var type = Type.GetTypeFromProgID("Quicktest.Application"); lock (_lockObject) { // before creating qtp automation object which creates UFT process, // try to check if the UFT process already exists bool uftProcessExist = false; bool isNewInstance; using (Mutex m = new Mutex(true, "per_process_mutex_UFT", out isNewInstance)) { if (!isNewInstance) { uftProcessExist = true; } } // this will create UFT process _qtpApplication = Activator.CreateInstance(type) as Application; // try to get qtp status via qtp automation object // this might fail if UFT is launched and waiting for user input on addins manage window bool needKillUFTProcess = false; // status: Not launched / Ready / Busy / Running / Recording / Waiting / Paused string status = _qtpApplication.GetStatus(); switch (status) { case "Not launched": if (uftProcessExist) { // UFT process exist but the status retrieved from qtp automation object is Not launched // it means the UFT is launched but not shown the main window yet // in which case it shall be considered as UFT is not used at all // so here can kill the UFT process to continue needKillUFTProcess = true; } break; case "Ready": case "Waiting": // UFT is launched but not running or recording, shall be considered as UFT is not used // no need kill UFT process here since the qtp automation object can work properly break; case "Busy": case "Running": case "Recording": case "Paused": // UFT is launched and somehow in use now, shouldn't kill UFT process // here make the test fail errorReason = Resources.UFT_Running; runDesc.TestState = TestState.Error; runDesc.ReportLocation = ""; runDesc.ErrorDesc = errorReason; return(runDesc); default: // by default, let the tool run test, the behavior might be unexpected break; } if (needKillUFTProcess) { Process[] procs = Process.GetProcessesByName("uft"); if (procs != null) { foreach (Process proc in procs) { proc.Kill(); } } } Version qtpVersion = Version.Parse(_qtpApplication.Version); if (qtpVersion.Equals(new Version(11, 0))) { // use the defined report path if provided if (!string.IsNullOrWhiteSpace(testinf.ReportPath)) { runDesc.ReportLocation = Path.Combine(testinf.ReportPath, "Report"); } else if (!string.IsNullOrWhiteSpace(testinf.ReportBaseDirectory)) { runDesc.ReportLocation = Path.Combine(testinf.ReportBaseDirectory, "Report"); } else { runDesc.ReportLocation = Path.Combine(testPath, "Report"); } if (Directory.Exists(runDesc.ReportLocation)) { int lastIndex = runDesc.ReportLocation.IndexOf("\\"); var location = runDesc.ReportLocation.Substring(0, lastIndex); var name = runDesc.ReportLocation.Substring(lastIndex + 1); runDesc.ReportLocation = Helper.GetNextResFolder(location, name); Console.WriteLine("Report location is:" + runDesc.ReportLocation); Directory.CreateDirectory(runDesc.ReportLocation); } } // Check for required Addins LoadNeededAddins(testPath); // set Mc connection and other mobile info into rack if neccesary #region Mc connection and other mobile info // Mc Address, username and password if (!string.IsNullOrEmpty(_mcConnection.MobileHostAddress)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_HOST_ADDRESS, _mcConnection.MobileHostAddress); if (!string.IsNullOrEmpty(_mcConnection.MobileHostPort)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_HOST_PORT, _mcConnection.MobileHostPort); } } if (!string.IsNullOrEmpty(_mcConnection.MobileUserName)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_USER, _mcConnection.MobileUserName); } if (!string.IsNullOrEmpty(_mcConnection.MobileTenantId)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_TENANT, _mcConnection.MobileTenantId); } if (!string.IsNullOrEmpty(_mcConnection.MobilePassword)) { string encriptedMcPassword = WinUserNativeMethods.ProtectBSTRToBase64(_mcConnection.MobilePassword); if (encriptedMcPassword == null) { ConsoleWriter.WriteLine("ProtectBSTRToBase64 fail for mcPassword"); throw new Exception("ProtectBSTRToBase64 fail for mcPassword"); } _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PASSWORD, encriptedMcPassword); } // ssl and proxy info _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_USE_SSL, _mcConnection.MobileUseSSL); if (_mcConnection.MobileUseProxy == 1) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_USE_PROXY, _mcConnection.MobileUseProxy); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_ADDRESS, _mcConnection.MobileProxySetting_Address); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_PORT, _mcConnection.MobileProxySetting_Port); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_AUTHENTICATION, _mcConnection.MobileProxySetting_Authentication); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_USERNAME, _mcConnection.MobileProxySetting_UserName); string encriptedMcProxyPassword = WinUserNativeMethods.ProtectBSTRToBase64(_mcConnection.MobileProxySetting_Password); if (encriptedMcProxyPassword == null) { ConsoleWriter.WriteLine("ProtectBSTRToBase64 fail for mc proxy Password"); throw new Exception("ProtectBSTRToBase64 fail for mc proxy Password"); } _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_PASSWORD, encriptedMcProxyPassword); } // Mc info (device, app, launch and terminate data) if (!string.IsNullOrEmpty(_mobileInfo)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_INFO, _mobileInfo); } #endregion if (!_qtpApplication.Launched) { if (_runCancelled()) { QTPTestCleanup(); KillQtp(); runDesc.TestState = TestState.Error; return(runDesc); } // Launch application after set Addins _qtpApplication.Launch(); _qtpApplication.Visible = false; } } } catch (Exception e) { string errorMsg = e.Message; string errorStacktrace = string.IsNullOrWhiteSpace(e.StackTrace) ? string.Empty : e.StackTrace; errorReason = Resources.QtpNotLaunchedError + "\n" + string.Format(Resources.ExceptionDetails, errorMsg, errorStacktrace); if (e is SystemException) { errorReason += "\n" + Resources.QtpNotLaunchedError_PossibleSolution_RegModellib; } runDesc.TestState = TestState.Error; runDesc.ReportLocation = ""; runDesc.ErrorDesc = errorReason; return(runDesc); } if (_qtpApplication.Test != null && _qtpApplication.Test.Modified) { var message = Resources.QtpNotLaunchedError; errorReason = message; runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; return(runDesc); } _qtpApplication.UseLicenseOfType(_useUFTLicense ? tagUnifiedLicenseType.qtUnifiedFunctionalTesting : tagUnifiedLicenseType.qtNonUnified); Dictionary <string, object> paramList = testinf.GetParameterDictionaryForQTP(); if (!HandleInputParameters(testPath, ref errorReason, testinf.GetParameterDictionaryForQTP(), testinf)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; return(runDesc); } GuiTestRunResult guiTestRunResult = ExecuteQTPRun(runDesc); // consider backward compatibility, here move the report folder one outside // that is, after test run, the report file might be at "path\to\tests\GUITest1\Report123\Report\run_results.html" // here move the last directory "Report" one level outside, which is, "path\to\tests\GUITest1\Report123\run_results.html" // steps: // 1. move directory "path\to\tests\GUITest1\Report123" to "path\to\tests\GUITest1\tmp_ddMMyyyyHHmmssfff" string guiTestReportPath = guiTestRunResult.ReportPath; // guiTestReportPath: path\to\tests\GUITest1\Report123\Report string targetReportDir = Path.GetDirectoryName(guiTestReportPath); // reportDir: path\to\tests\GUITest1\Report123 string reportBaseDir = Path.GetDirectoryName(targetReportDir); // reportBaseDir: path\to\tests\GUITest1 string tmpDir = Path.Combine(reportBaseDir, "tmp_" + DateTime.Now.ToString("ddMMyyyyHHmmssfff")); // tmpDir: path\to\tests\GUITest1\tmp_ddMMyyyyHHmmssfff // 1.a) directory move may fail because UFT might still be writting report files, need retry const int maxMoveDirRetry = 30; int moveDirRetry = 0; bool dirMoved = false; do { try { Directory.Move(targetReportDir, tmpDir); dirMoved = true; break; } catch (IOException) { moveDirRetry++; if (moveDirRetry == 1) { ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + string.Format(" Report is not ready yet, wait up to {0} seconds ...", maxMoveDirRetry)); } Thread.Sleep(1000); } } while (moveDirRetry < maxMoveDirRetry); if (dirMoved) { // 2. move directory "path\to\tests\GUITest1\tmp_ddMMyyyyHHmmssfff\Report" to "path\to\tests\GUITest1\Report123" string tmpReportDir = Path.Combine(tmpDir, "Report"); // tmpReportDir: path\to\tests\GUITest1\tmp_ddMMyyyyHHmmssfff\Report Directory.Move(tmpReportDir, targetReportDir); // 3. delete the temp directory "path\to\test1\tmp_ddMMyyyyHHmmssfff" Directory.Delete(tmpDir, true); runDesc.ReportLocation = targetReportDir; } else { runDesc.ReportLocation = guiTestReportPath; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Warning: Report folder is still in use, leave it in: " + guiTestReportPath); } if (!guiTestRunResult.IsSuccess) { runDesc.TestState = TestState.Error; return(runDesc); } if (!HandleOutputArguments(ref errorReason)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; return(runDesc); } QTPTestCleanup(); return(runDesc); }
/// <summary> /// runs the given test and returns resutls /// </summary> /// <param name="testPath"></param> /// <param name="errorReason"></param> /// <param name="runCanclled"></param> /// <returns></returns> public TestRunResults RunTest(TestInfo testinf, ref string errorReason, RunCancelledDelegate runCanclled) { var testPath = testinf.TestPath; TestRunResults runDesc = new TestRunResults(); ConsoleWriter.ActiveTestRun = runDesc; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Running: " + testPath); runDesc.TestPath = testPath; // default report location is the test path runDesc.ReportLocation = testPath; // check if the report path has been defined if (!String.IsNullOrEmpty(testinf.ReportPath)) { if (!Helper.TrySetTestReportPath(runDesc, testinf, ref errorReason)) { return(runDesc); } } runDesc.TestState = TestState.Unknown; _runCancelled = runCanclled; if (!Helper.IsQtpInstalled()) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = string.Format(Resources.GeneralQtpNotInstalled, System.Environment.MachineName); ConsoleWriter.WriteErrLine(runDesc.ErrorDesc); Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed; return(runDesc); } string reason = string.Empty; if (!Helper.CanUftProcessStart(out reason)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = reason; ConsoleWriter.WriteErrLine(runDesc.ErrorDesc); Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed; return(runDesc); } try { ChangeDCOMSettingToInteractiveUser(); var type = Type.GetTypeFromProgID("Quicktest.Application"); lock (_lockObject) { _qtpApplication = Activator.CreateInstance(type) as Application; Version qtpVersion = Version.Parse(_qtpApplication.Version); if (qtpVersion.Equals(new Version(11, 0))) { // use the defined report path if provided if (!String.IsNullOrEmpty(testinf.ReportPath)) { runDesc.ReportLocation = Path.Combine(testinf.ReportPath, "Report"); } else { runDesc.ReportLocation = Path.Combine(testPath, "Report"); } if (Directory.Exists(runDesc.ReportLocation)) { int lastIndex = runDesc.ReportLocation.IndexOf("\\"); var location = runDesc.ReportLocation.Substring(0, lastIndex); var name = runDesc.ReportLocation.Substring(lastIndex + 1); runDesc.ReportLocation = Helper.GetNextResFolder(location, name); Console.WriteLine("Report location is:" + runDesc.ReportLocation); //Directory.Delete(runDesc.ReportLocation, true); Directory.CreateDirectory(runDesc.ReportLocation); } } // Check for required Addins LoadNeededAddins(testPath); // set Mc connection and other mobile info into rack if neccesary #region Mc connection and other mobile info // Mc Address, username and password if (!string.IsNullOrEmpty(_mcConnection.MobileHostAddress)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_HOST_ADDRESS, _mcConnection.MobileHostAddress); if (!string.IsNullOrEmpty(_mcConnection.MobileHostPort)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_HOST_PORT, _mcConnection.MobileHostPort); } } if (!string.IsNullOrEmpty(_mcConnection.MobileUserName)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_USER, _mcConnection.MobileUserName); } if (!string.IsNullOrEmpty(_mcConnection.MobileTenantId)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_TENANT, _mcConnection.MobileTenantId); } if (!string.IsNullOrEmpty(_mcConnection.MobilePassword)) { string encriptedMcPassword = WinUserNativeMethods.ProtectBSTRToBase64(_mcConnection.MobilePassword); if (encriptedMcPassword == null) { ConsoleWriter.WriteLine("ProtectBSTRToBase64 fail for mcPassword"); throw new Exception("ProtectBSTRToBase64 fail for mcPassword"); } _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PASSWORD, encriptedMcPassword); } // ssl and proxy info _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_USE_SSL, _mcConnection.MobileUseSSL); if (_mcConnection.MobileUseProxy == 1) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_USE_PROXY, _mcConnection.MobileUseProxy); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_ADDRESS, _mcConnection.MobileProxySetting_Address); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_PORT, _mcConnection.MobileProxySetting_Port); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_AUTHENTICATION, _mcConnection.MobileProxySetting_Authentication); _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_USERNAME, _mcConnection.MobileProxySetting_UserName); string encriptedMcProxyPassword = WinUserNativeMethods.ProtectBSTRToBase64(_mcConnection.MobileProxySetting_Password); if (encriptedMcProxyPassword == null) { ConsoleWriter.WriteLine("ProtectBSTRToBase64 fail for mc proxy Password"); throw new Exception("ProtectBSTRToBase64 fail for mc proxy Password"); } _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_PROXY_SETTING_PASSWORD, encriptedMcProxyPassword); } // Mc info (device, app, launch and terminate data) if (!string.IsNullOrEmpty(_mobileInfo)) { _qtpApplication.TDPierToTulip.SetTestOptionsVal(MOBILE_INFO, _mobileInfo); } #endregion if (!_qtpApplication.Launched) { if (_runCancelled()) { QTPTestCleanup(); KillQtp(); runDesc.TestState = TestState.Error; return(runDesc); } // Launch application after set Addins _qtpApplication.Launch(); _qtpApplication.Visible = false; } } } catch (Exception e) { errorReason = Resources.QtpNotLaunchedError; runDesc.TestState = TestState.Error; runDesc.ReportLocation = ""; runDesc.ErrorDesc = e.Message; return(runDesc); } if (_qtpApplication.Test != null && _qtpApplication.Test.Modified) { var message = Resources.QtpNotLaunchedError; errorReason = message; runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; return(runDesc); } _qtpApplication.UseLicenseOfType(_useUFTLicense ? tagUnifiedLicenseType.qtUnifiedFunctionalTesting : tagUnifiedLicenseType.qtNonUnified); if (!HandleInputParameters(testPath, ref errorReason, testinf.GetParameterDictionaryForQTP(), testinf.DataTablePath)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; return(runDesc); } GuiTestRunResult guiTestRunResult = ExecuteQTPRun(runDesc); runDesc.ReportLocation = guiTestRunResult.ReportPath; if (!guiTestRunResult.IsSuccess) { runDesc.TestState = TestState.Error; return(runDesc); } if (!HandleOutputArguments(ref errorReason)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; return(runDesc); } QTPTestCleanup(); return(runDesc); }
/// <summary> /// runs the given test /// </summary> /// <param name="testinf"></param> /// <param name="errorReason"></param> /// <param name="runCancelled">cancellation delegate, holds the function that checks cancellation</param> /// <returns></returns> public TestRunResults RunTest(TestInfo testinf, ref string errorReason, RunCancelledDelegate runCancelled) { TestRunResults runDesc = new TestRunResults(); ConsoleWriter.ActiveTestRun = runDesc; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Running: " + testinf.TestPath); runDesc.TestPath = testinf.TestPath; // check if the report path has been defined if (!string.IsNullOrWhiteSpace(testinf.ReportPath)) { runDesc.ReportLocation = testinf.ReportPath; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Report path is set explicitly: " + runDesc.ReportLocation); } else if (!String.IsNullOrEmpty(testinf.ReportBaseDirectory)) { if (!Helper.TrySetTestReportPath(runDesc, testinf, ref errorReason)) { return(runDesc); } ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Report path is generated under base directory: " + runDesc.ReportLocation); } else { // default report location is the next available folder under test path // for example, "path\to\tests\APITest\Report123", the name "Report123" will also be used as the report name string reportBasePath = testinf.TestPath; string testReportPath = Path.Combine(reportBasePath, "Report" + DateTime.Now.ToString("ddMMyyyyHHmmssfff")); int index = 0; while (index < int.MaxValue) { index++; string dir = Path.Combine(reportBasePath, "Report" + index.ToString()); if (!Directory.Exists(dir)) { testReportPath = dir; break; } } runDesc.ReportLocation = testReportPath; ConsoleWriter.WriteLine(DateTime.Now.ToString(Launcher.DateFormat) + " Report path is automatically generated: " + runDesc.ReportLocation); } runDesc.ErrorDesc = errorReason; runDesc.TestState = TestState.Unknown; if (!Helper.IsServiceTestInstalled()) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = string.Format(Resources.LauncherStNotInstalled, System.Environment.MachineName); ConsoleWriter.WriteErrLine(runDesc.ErrorDesc); Environment.ExitCode = (int)Launcher.ExitCodeEnum.Failed; return(runDesc); } _runCancelled = runCancelled; if (!_stCanRun) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = Resources.STExecuterNotFound; return(runDesc); } string fileName = Path.Combine(_stExecuterPath, STRunnerName); if (!File.Exists(fileName)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = Resources.STExecuterNotFound; ConsoleWriter.WriteErrLine(Resources.STExecuterNotFound); return(runDesc); } //write the input parameter xml file for the API test string paramFileName = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 10); string tempPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "TestParams"); Directory.CreateDirectory(tempPath); string paramsFilePath = Path.Combine(tempPath, "params" + paramFileName + ".xml"); string paramFileContent = testinf.GenerateAPITestXmlForTest(); string argumentString = ""; if (!string.IsNullOrWhiteSpace(paramFileContent)) { File.WriteAllText(paramsFilePath, paramFileContent); argumentString = String.Format("{0} \"{1}\" {2} \"{3}\" {4} \"{5}\"", STRunnerTestArg, testinf.TestPath, STRunnerReportArg, runDesc.ReportLocation, STRunnerInputParamsArg, paramsFilePath); } else { argumentString = String.Format("{0} \"{1}\" {2} \"{3}\"", STRunnerTestArg, testinf.TestPath, STRunnerReportArg, runDesc.ReportLocation); } Stopwatch s = Stopwatch.StartNew(); runDesc.TestState = TestState.Running; if (!ExecuteProcess(fileName, argumentString, ref errorReason)) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = errorReason; } else { // consider backward compatibility, here move the report folder one outside // that is, after test run, the report file might be at "path\to\tests\APITest1\Report123\Report\run_results.html" // here move the last directory "Report" one level outside, which is, "path\to\tests\APITest1\Report123\run_results.html" string apiTestReportPath = Path.Combine(runDesc.ReportLocation, "Report"); // apiTestReportPath: path\to\tests\APITest1\Report123\Report string targetReportDir = Path.GetDirectoryName(apiTestReportPath); // reportDir: path\to\tests\APITest1\Report123 string reportBaseDir = Path.GetDirectoryName(targetReportDir); // reportBaseDir: path\to\tests\APITest1 string tmpDir = Path.Combine(reportBaseDir, "tmp_" + DateTime.Now.ToString("ddMMyyyyHHmmssfff")); // tmpDir: path\to\tests\APITest1\tmp_ddMMyyyyHHmmssfff string tmpReportDir = Path.Combine(tmpDir, "Report"); // tmpReportDir: path\to\tests\APITest1\tmp_ddMMyyyyHHmmssfff\Report // since some files might not be closed yet, move the report folder might fail // so here will try a few times to move folder and let it as is (not moved) if still failed after several retry bool moveSuccess = false; string lastMoveError = string.Empty; int retry = 10; while (retry >= 0) { try { // steps: // 1. move directory "path\to\tests\APITest1\Report123" to "path\to\tests\APITest1\tmp_ddMMyyyyHHmmssfff" Directory.Move(targetReportDir, tmpDir); // 2. move directory "path\to\tests\APITest1\tmp_ddMMyyyyHHmmssfff\Report" to "path\to\tests\APITest1\Report123" Directory.Move(tmpReportDir, targetReportDir); // 3. delete empty directory "path\to\test1\tmp_ddMMyyyyHHmmssfff" Directory.Delete(tmpDir, true); // 4. update report location runDesc.ReportLocation = targetReportDir; moveSuccess = true; break; } catch (Exception ex) { lastMoveError = ex.Message; retry--; System.Threading.Thread.Sleep(500); } } if (!moveSuccess) { ConsoleWriter.WriteLine("Warning: Failed to change the report folder structure. " + lastMoveError); } if (!File.Exists(Path.Combine(runDesc.ReportLocation, "Results.xml")) && !File.Exists(Path.Combine(runDesc.ReportLocation, "run_results.html"))) { runDesc.TestState = TestState.Error; runDesc.ErrorDesc = "No Results.xml or run_results.html file found"; } } //File.Delete(paramsFilePath); runDesc.Runtime = s.Elapsed; return(runDesc); }