diff --git a/HpToolsLauncher/HpToolsLauncher.csproj b/HpToolsLauncher/HpToolsLauncher.csproj index 8114e537f..7a608b4df 100644 --- a/HpToolsLauncher/HpToolsLauncher.csproj +++ b/HpToolsLauncher/HpToolsLauncher.csproj @@ -89,6 +89,7 @@ + diff --git a/HpToolsLauncher/Launcher.cs b/HpToolsLauncher/Launcher.cs index 6836fbf7f..2bb9a2791 100644 --- a/HpToolsLauncher/Launcher.cs +++ b/HpToolsLauncher/Launcher.cs @@ -248,6 +248,36 @@ private IAssetRunner CreateRunner(bool isFirstRun, List reruntests = n { case TestStorageType.AlmLabManagement: + case TestStorageType.LoadRunner: + { + int timeout = 0; + if (_ciParams.ContainsKey("fsTimeout")) + { + int parsedTimeout; + if (int.TryParse(_ciParams["fsTimeout"], out parsedTimeout) && parsedTimeout != -1) + timeout = parsedTimeout; + } + + string resultsDirectory = _ciParams["fsReportPath"].ToString(); + if (!Directory.Exists(resultsDirectory)) + { + Console.WriteLine("The provided scenario folder path {0} does not exist.", resultsDirectory); + Environment.Exit((int)ExitCodeEnum.Failed); + } + string testPath = _ciParams["Test1"].ToString(); + if (!File.Exists(testPath)) + { + Console.WriteLine("The provided scenario folder path {0} does not exist.", testPath); + Environment.Exit((int)ExitCodeEnum.Failed); + } + + ServiceTestRunner svc = new ServiceTestRunner(); + bool result = svc.RunServiceTest(testPath, resultsDirectory, timeout); + + Environment.Exit(result ? (int)ExitCodeEnum.Passed : (int)ExitCodeEnum.Failed); + break; + } + case TestStorageType.Alm: { //check that all required parameters exist diff --git a/HpToolsLauncher/TestRunners/ServiceTestRunner.cs b/HpToolsLauncher/TestRunners/ServiceTestRunner.cs new file mode 100644 index 000000000..5443930f2 --- /dev/null +++ b/HpToolsLauncher/TestRunners/ServiceTestRunner.cs @@ -0,0 +1,211 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; + +namespace HpToolsLauncher.TestRunners +{ + public class ServiceTestRunner + { + // + public string binPath = Environment.ExpandEnvironmentVariables("%LR_PATH%bin"); + public string[] processesToKill = new string[] { "wlrun", "lrun_svc", "CmdServiceClient" }; + public int _timeout; + + public bool RunServiceTest(string testPath, string resultsDirectory, int timeout) + { + _timeout = timeout * 1000; + Cleanup(processesToKill); + LogMessage("Cleanup complete."); + + //Start lrun_svc.exe and CmdServiceClient.exe + StartLrunSvc(); + LogMessage("lrun_svc.exe is running"); + Process client = StartClient(); + LogMessage("CmdServiceClient.exe is running"); + + //Set the load test data to the given .lrs + string command = "setLoadTestData " + testPath; + Write(client, command); + LogMessage("Command given:",command); + + string result = Read(client); + LogMessage("Client response:", result); + if ((result.Contains("failed") || (result.Contains("empty")))) + { + Cleanup(processesToKill); + return false; + } + + + //Set the results folder directory + string command1 ="setResultsDirectory " + resultsDirectory; + Write(client, command1); + LogMessage("Command given:", command1); + + result = Read(client); + LogMessage("Client response:",result); + if ((result.Contains("failed") || (result.Contains("empty")))) + { + Cleanup(processesToKill); + return false; + } + + //Start the load test + Write(client,"startLoadTest"); + LogMessage("Command given: startLoadTest"); + + result = Read(client); + LogMessage("Client response:",result); + if (result.Contains("failed")) + { + Cleanup(processesToKill); + return false; + } + LogMessage("The test has started, waiting for the test to end."); + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + var startTime= DateTime.Now; + + //Get the result + result = ""; + while (!result.Contains("Ended")) //wait for the test to end + { + Write(client, "getServiceState"); //ready, collating, running, ended + result = Read(client); + if ((result.Contains("failed") || (result.Contains("empty")))) + { + LogMessage(result); + Cleanup(processesToKill); + return false; + } + Thread.Sleep(1); + } + + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", + ts.Hours, ts.Minutes, ts.Seconds, + ts.Milliseconds / 10); + LogMessage("Test completed in", elapsedTime); + Dispose(client); + Cleanup(processesToKill); + return true; + } + + #region Process utilities + public void StartLrunSvc() + { + LogMessage("Starting lrun_svc.exe..."); + var startInfo = new System.Diagnostics.ProcessStartInfo + { + WorkingDirectory = binPath, + FileName = "lrun_svc.exe", + }; + var proc = new Process + { + StartInfo = startInfo + }; + proc.Start(); + System.Threading.Thread.Sleep(5000); + } + + public Process StartClient() + { + var startInfo = new System.Diagnostics.ProcessStartInfo + { + FileName = binPath + @"\CmdServiceClient.exe", + RedirectStandardInput = true, + RedirectStandardOutput = true, + UseShellExecute = false + }; + + var proc = new Process + { + StartInfo = startInfo + }; + proc.Start(); + return proc; + } + + public void Cleanup(string[] processes) + { + foreach (string process in processes) + { + Process[] workers = Process.GetProcessesByName(process); + foreach (Process worker in workers) + { + try + { + worker.Kill(); + worker.WaitForExit(); + worker.Dispose(); + } + catch (UnauthorizedAccessException) + { + continue; + } + + } + } + + } + + public void LogMessage(string message) + { + Console.WriteLine("[{0}] {1}", DateTime.Now.ToString("h:mm:ss tt"), message); + } + + public void LogMessage(string message, string extraInfo) + { + Console.WriteLine("[{0}] {1} {2}", DateTime.Now.ToString("h:mm:ss tt"), message, extraInfo); + } + #endregion + + #region Client communication + public void Write(Process client, string command) + { + StreamWriter writer = client.StandardInput; + writer.WriteLine(command); + writer.Flush(); + } + public void Write(Process client, string command, int timeout) + { + StreamWriter writer = client.StandardInput; + writer.WriteLine(command); + //System.Threading.Thread.Sleep(timeout); + writer.Flush(); + } + public string ReadLine(Process client) + { + + StreamReader reader = client.StandardOutput; + string result = ""; + do + { + int output = reader.Read(); + result += (char)output; + } + while (reader.Peek() > -1); + reader.DiscardBufferedData(); + return result; + } + public void Dispose(Process client) + { + client.StandardInput.Close(); + client.StandardOutput.Close(); + client.Dispose(); + } + public string Read(Process client) + { + string result = ReadLine(client); + while (result.Length < 3) + { + result =ReadLine(client); + System.Threading.Thread.Sleep(5); + } + return result; + } + } + #endregion +} diff --git a/HpToolsLauncher/app.config b/HpToolsLauncher/app.config index 6e39bb5ce..c05a491e4 100644 --- a/HpToolsLauncher/app.config +++ b/HpToolsLauncher/app.config @@ -1,6 +1,6 @@ - + diff --git a/src/main/java/com/microfocus/application/automation/tools/model/RunFromServiceModel.java b/src/main/java/com/microfocus/application/automation/tools/model/RunFromServiceModel.java new file mode 100644 index 000000000..24b4dd627 --- /dev/null +++ b/src/main/java/com/microfocus/application/automation/tools/model/RunFromServiceModel.java @@ -0,0 +1,180 @@ +/* + * Certain versions of software and/or documents ("Material") accessible here may contain branding from + * Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, + * the Material is now offered by Micro Focus, a separately owned and operated company. 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 + * + * (c) Copyright 2012-2023 Micro Focus or one of its affiliates. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ___________________________________________________________________ + */ + +package com.microfocus.application.automation.tools.model; + +import com.microfocus.application.automation.tools.uft.utils.UftToolUtils; +import hudson.EnvVars; +import hudson.Extension; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Descriptor; +import hudson.model.Node; +import org.apache.commons.lang.StringUtils; +import org.kohsuke.stapler.DataBoundConstructor; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Properties; + +/** + * Holds the data for RunFromFile build type. + */ +public class RunFromServiceModel extends AbstractDescribableImpl { + + private String fsTests; + private String fsTimeout; + private String fsReportPath; + + /** + * Instantiates a new Run from file system model. + * + * @param fsTests the fs tests path + * @param fsTimeout the fs timeout in minutes for tests in seconds + * @param fsReportPath the fs report path + + */ + @DataBoundConstructor + public RunFromServiceModel(String fsTests, String fsTimeout, String fsReportPath) { + this.setFsTests(fsTests); + this.fsTimeout = fsTimeout; + this.fsReportPath = fsReportPath; + } + + + /** + * Sets fs tests. + * + * @param fsTests the fs tests + */ + public void setFsTests(String fsTests) { + this.fsTests = fsTests.trim(); + + if (!this.fsTests.contains("\n")) { + this.fsTests += "\n"; + } + } + + /** + * Sets fs timeout. + * + * @param fsTimeout the fs timeout + */ + public void setFsTimeout(String fsTimeout) { + this.fsTimeout = fsTimeout; + } + + /** + * Gets fs tests. + * + * @return the fs tests + */ + public String getFsTests() { + return fsTests; + } + + /** + * Gets fs timeout. + * + * @return the fs timeout + */ + public String getFsTimeout() { + return fsTimeout; + } + + /** + * Sets the report path for the given tests. + */ + public void setFsReportPath(String fsReportPath) { + this.fsReportPath = fsReportPath; + } + + /** + * Gets the test report path. + */ + public String getFsReportPath() { + return fsReportPath; + } + + /** + * Gets properties. + * + * @param envVars the env vars + * @return the properties + */ + @Nullable + public Properties getProperties(EnvVars envVars, Node currNode) { + return createProperties(envVars, currNode); + } + + private Properties createProperties(EnvVars envVars, Node currNode) { + Properties props = new Properties(); + + addTestsToProps(envVars, props); + + return props; + } + + + private void addTestsToProps(EnvVars envVars, Properties props) { + String fsTimeoutVal = StringUtils.isEmpty(fsTimeout) ? "-1" : envVars.expand(fsTimeout); + props.put("fsTimeout", fsTimeoutVal); + + if (StringUtils.isNotBlank(fsReportPath)) { + props.put("fsReportPath", fsReportPath); + } + if (!StringUtils.isEmpty(this.fsTests)) { + String expandedFsTests = envVars.expand(fsTests); + String[] testsArr; + if (UftToolUtils.isMtbxContent(expandedFsTests)) { + testsArr = new String[]{expandedFsTests}; + } else { + testsArr = expandedFsTests.replaceAll("\r", "").split("\n"); + } + + int i = 1; + + for (String test : testsArr) { + test = test.trim(); + props.put("Test" + i, test); + i++; + } + } else { + props.put("fsTests", ""); + } + } + + + @Extension + public static class DescriptorImpl extends Descriptor { + @Nonnull + @Override + public String getDisplayName() { + return "LR Service File System Model"; + } + } +} diff --git a/src/main/java/com/microfocus/application/automation/tools/run/RunFromService.java b/src/main/java/com/microfocus/application/automation/tools/run/RunFromService.java new file mode 100644 index 000000000..6d9e10a92 --- /dev/null +++ b/src/main/java/com/microfocus/application/automation/tools/run/RunFromService.java @@ -0,0 +1,490 @@ +/* + * Certain versions of software and/or documents ("Material") accessible here may contain branding from + * Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, + * the Material is now offered by Micro Focus, a separately owned and operated company. 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 + * + * (c) Copyright 2012-2023 Micro Focus or one of its affiliates. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ___________________________________________________________________ + */ + +package com.microfocus.application.automation.tools.run; + +import com.hp.octane.integrations.executor.TestsToRunConverter; +import com.microfocus.application.automation.tools.JenkinsUtils; +import com.microfocus.application.automation.tools.AlmToolsUtils; +import com.microfocus.application.automation.tools.EncryptionUtils; +import com.microfocus.application.automation.tools.Messages; +import com.microfocus.application.automation.tools.model.*; +import com.microfocus.application.automation.tools.uft.model.UftRunAsUser; +import com.microfocus.application.automation.tools.uft.utils.UftToolUtils; +import hudson.*; +import hudson.model.*; +import hudson.tasks.BuildStepDescriptor; +import hudson.tasks.Builder; +import hudson.util.FormValidation; +import hudson.util.IOUtils; +import hudson.util.VariableResolver; +import jenkins.model.Jenkins; +import jenkins.tasks.SimpleBuildStep; +import net.minidev.json.JSONObject; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.QueryParameter; + +import javax.annotation.Nonnull; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.URL; +import java.text.Format; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * Describes a regular jenkins build step from UFT or LR + */ +public class RunFromService extends Builder implements SimpleBuildStep { + + private static final String LRANALYSIS_LAUNCHER_EXE = "LRAnalysisLauncher.exe"; + + public static final String HP_TOOLS_LAUNCHER_EXE = "HpToolsLauncher.exe"; + public static final String HP_TOOLS_LAUNCHER_EXE_CFG = "HpToolsLauncher.exe.config"; + + private String ResultFilename = "ApiResults.xml"; + + private String ParamFileName = "ApiRun.txt"; + + private RunFromServiceModel runFromServiceModel; + + private Map resultFileNames; + + + // /** + // * Instantiates a new Run from file builder. + // * + // * @param fsTests the fs tests + // */ + // public RunFromService(String fsTests) { + // runFromServiceModel = new RunFromServiceModel(fsTests); + // } + + // /** + // * Instantiates a new Run from file builder. + // * + // * @param runFromServiceModel the run from file model + // */ + // public RunFromService(RunFromServiceModel runFromServiceModel) { + // this.runFromServiceModel = runFromServiceModel; + // } + + @DataBoundConstructor + public RunFromService(RunFromServiceModel runFromSm) { + runFromServiceModel = runFromSm; + } + + public String getFsTimeout() { + return runFromServiceModel.getFsTimeout(); + } + + /** + * Sets fs timeout. + * + * @param fsTimeout the fs timeout + */ + @DataBoundSetter + public void setFsTimeout(String fsTimeout) { + runFromServiceModel.setFsTimeout(fsTimeout); + } + + public String getFsTests() { + return runFromServiceModel.getFsTests(); + } + + public void setFsTests(String fsTests) { + runFromServiceModel.setFsTests(fsTests); + } + + /** + * Get the fs report path. + * + * @return the filesystem report path + */ + public String getFsReportPath() { + return runFromServiceModel.getFsReportPath(); + } + + /** + * Sets the report path + * + * @param fsReportPath the report path + */ + @DataBoundSetter + public void setFsReportPath(String fsReportPath) { + runFromServiceModel.setFsReportPath(fsReportPath); + } + + + public Map getResultFileNames() { + return resultFileNames; + } + + @DataBoundSetter + public void setResultFileNames(Map results) { + resultFileNames = results; + } + + @Override + public void perform(@Nonnull Run build, @Nonnull FilePath workspace, @Nonnull Launcher launcher, + @Nonnull TaskListener listener) + throws IOException { + PrintStream out = listener.getLogger(); + + UftOctaneUtils.setUFTRunnerTypeAsParameter(build, listener); + + EnvVars env = null; + try { + env = build.getEnvironment(listener); + } catch (IOException | InterruptedException e) { + listener.error("Failed loading build environment: " + e.getMessage()); + } + + Node currNode = JenkinsUtils.getCurrentNode(workspace); + if (currNode == null) { + listener.error("Failed to get current executor node."); + return; + } + + // in case of mbt, since mbt can support uft and codeless at the same time, run only if there are uft tests + ParametersAction parameterAction = build.getAction(ParametersAction.class); + ParameterValue octaneFrameworkParam = parameterAction != null ? parameterAction.getParameter("octaneTestRunnerFramework") : null; + if (octaneFrameworkParam != null && octaneFrameworkParam.getValue().equals("MBT")) { + String testsToRunConverted = env == null ? null : env.get(TestsToRunConverter.DEFAULT_TESTS_TO_RUN_CONVERTED_PARAMETER); + if (StringUtils.isEmpty(testsToRunConverted)) { + out.println(RunFromService.class.getSimpleName() + " : No UFT tests were found"); + return; + } + } + + // this is an unproper replacement to the build.getVariableResolver since workflow run won't support the + // getBuildEnvironment() as written here: + // https://github.com/jenkinsci/pipeline-plugin/blob/893e3484a25289c59567c6724f7ce19e3d23c6ee/DEVGUIDE + // .md#variable-substitutions + + JSONObject jobDetails; + // now merge them into one list + Properties mergedProperties = new Properties(); + + + if (env == null) { + listener.fatalError("Environment not set"); + throw new IOException("Env Null - something went wrong with fetching jenkins build environment"); + } + + if (build instanceof AbstractBuild) { + VariableResolver varResolver = ((AbstractBuild) build).getBuildVariableResolver(); + } + + mergedProperties.putAll(Objects.requireNonNull(runFromServiceModel).getProperties(env, currNode)); + + boolean isPrintTestParams = UftToolUtils.isPrintTestParams(build, listener); + mergedProperties.put("printTestParams", isPrintTestParams ? "1" : "0"); + + UftRunAsUser uftRunAsUser; + try { + uftRunAsUser = UftToolUtils.getRunAsUser(build, listener); + if (uftRunAsUser != null) { + mergedProperties.put("uftRunAsUserName", uftRunAsUser.getUsername()); + if (StringUtils.isNotBlank(uftRunAsUser.getEncodedPassword())) { + mergedProperties.put("uftRunAsUserEncodedPassword", uftRunAsUser.getEncodedPasswordAsEncrypted(currNode)); + } else if (uftRunAsUser.getPassword() != null) { + mergedProperties.put("uftRunAsUserPassword", uftRunAsUser.getPasswordAsEncrypted(currNode)); + } + } + } catch(IllegalArgumentException | EncryptionUtils.EncryptionException e) { + build.setResult(Result.FAILURE); + listener.fatalError(String.format("Build parameters check failed: %s.", e.getMessage())); + return; + } + int idx = 0; + for (Iterator iterator = env.keySet().iterator(); iterator.hasNext(); ) { + String key = iterator.next(); + idx++; + mergedProperties.put("JenkinsEnv" + idx, key + ";" + env.get(key)); + } + + Date now = new Date(); + Format formatter = new SimpleDateFormat("ddMMyyyyHHmmssSSS"); + String time = formatter.format(now); + + // get a unique filename for the params file + ParamFileName = "props" + time + ".txt"; + ResultFilename = String.format("Results%s_%d.xml", time, build.getNumber()); + + long threadId = Thread.currentThread().getId(); + if (resultFileNames == null) { + resultFileNames = new HashMap(); + } + resultFileNames.put(threadId, ResultFilename); + + mergedProperties.put("runType", AlmRunTypes.RunType.LoadRunner.toString()); + + mergedProperties.put("resultsFilename", ResultFilename); + + + // cleanup report folders before running the build + String selectedNode = env.get("NODE_NAME"); + if (selectedNode == null) {//if slave is given in the pipeline and not as part of build step + try { + selectedNode = launcher.getComputer().getName(); + } catch (Exception e) { + listener.error("Failed to get selected node for UFT execution : " + e.getMessage()); + } + } + + // clean cleanuptests' report folders + int index = 1; + while (mergedProperties.getProperty("CleanupTest" + index) != null) { + String testPath = mergedProperties.getProperty("CleanupTest" + index); + List cleanupTests = UftToolUtils.getBuildTests(selectedNode, testPath); + for (String test : cleanupTests) { + UftToolUtils.deleteReportFoldersFromNode(selectedNode, test, listener); + } + + index++; + } + + // clean actual tests' report folders + index = 1; + while (mergedProperties.getProperty("Test" + index) != null) { + String testPath = mergedProperties.getProperty(("Test" + index)); + List buildTests = UftToolUtils.getBuildTests(selectedNode, testPath); + for (String test : buildTests) { + UftToolUtils.deleteReportFoldersFromNode(selectedNode, test, listener); + } + index++; + } + + mergedProperties.setProperty("numOfTests", String.valueOf(index - 1)); + + // get properties serialized into a stream + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + mergedProperties.store(stream, ""); + } catch (IOException e) { + listener.error("Storing run variable failed: " + e); + build.setResult(Result.FAILURE); + } + + String propsSerialization = stream.toString(); + + FilePath CmdLineExe; + try (InputStream propsStream = IOUtils.toInputStream(propsSerialization)) { + // Get the URL to the Script used to run the test, which is bundled + // in the plugin + @SuppressWarnings("squid:S2259") + URL cmdExeUrl = Jenkins.get().pluginManager.uberClassLoader.getResource(HP_TOOLS_LAUNCHER_EXE); + if (cmdExeUrl == null) { + listener.fatalError(HP_TOOLS_LAUNCHER_EXE + " not found in resources"); + return; + } + + @SuppressWarnings("squid:S2259") + URL cmdExeCfgUrl = Jenkins.get().pluginManager.uberClassLoader.getResource(HP_TOOLS_LAUNCHER_EXE_CFG); + if (cmdExeCfgUrl == null) { + listener.fatalError(HP_TOOLS_LAUNCHER_EXE_CFG + " not found in resources"); + return; + } + + @SuppressWarnings("squid:S2259") + URL cmdExe2Url = Jenkins.get().pluginManager.uberClassLoader.getResource(LRANALYSIS_LAUNCHER_EXE); + if (cmdExe2Url == null) { + listener.fatalError(LRANALYSIS_LAUNCHER_EXE + "not found in resources"); + return; + } + + FilePath propsFileName = workspace.child(ParamFileName); + CmdLineExe = workspace.child(HP_TOOLS_LAUNCHER_EXE); + FilePath CmdLineExeCfg = workspace.child(HP_TOOLS_LAUNCHER_EXE_CFG); + FilePath CmdLineExe2 = workspace.child(LRANALYSIS_LAUNCHER_EXE); + + try { + // create a file for the properties file, and save the properties + propsFileName.copyFrom(propsStream); + // Copy the script to the project workspace + CmdLineExe.copyFrom(cmdExeUrl); + CmdLineExeCfg.copyFrom(cmdExeCfgUrl); + CmdLineExe2.copyFrom(cmdExe2Url); + } catch (IOException | InterruptedException e) { + build.setResult(Result.FAILURE); + listener.error("Copying executable files to executing node " + e); + } + } + + try { + // Run the HpToolsLauncher.exe + AlmToolsUtils.runOnBuildEnv(build, launcher, listener, CmdLineExe, ParamFileName, currNode); + // Has the report been successfully generated? + } catch (IOException ioe) { + Util.displayIOException(ioe, listener); + build.setResult(Result.FAILURE); + listener.error("Failed running HpToolsLauncher " + ioe.getMessage()); + } catch (InterruptedException e) { + build.setResult(Result.ABORTED); + listener.error("Failed running HpToolsLauncher - build aborted " + StringUtils.defaultString(e.getMessage())); + try { + AlmToolsUtils.runHpToolsAborterOnBuildEnv(build, launcher, listener, ParamFileName, workspace); + } catch (IOException e1) { + Util.displayIOException(e1, listener); + build.setResult(Result.FAILURE); + } catch (InterruptedException e1) { + listener.error("Failed running HpToolsAborter " + e1.getMessage()); + } + } + } + + + @Override + public DescriptorImpl getDescriptor() { + return (DescriptorImpl) super.getDescriptor(); + } + + /** + * Gets run from file model. + * + * @return the run from file model + */ + public RunFromServiceModel getrunFromServiceModel() { + return runFromServiceModel; + } + + /** + * Gets run results file name. + * + * @return the run results file name + */ + public String getRunResultsFileName() { + synchronized (this) { + long threadId = Thread.currentThread().getId(); + String fileName = resultFileNames.get(threadId); + return fileName; + } + } + + + /** + * The type Descriptor. + */ + @Symbol("runFromServiceBuilder") + @Extension + public static final class DescriptorImpl extends BuildStepDescriptor { + + /** + * Instantiates a new Descriptor. + */ + public DescriptorImpl() { + load(); + } + + @Override + public boolean isApplicable( + @SuppressWarnings("rawtypes") Class jobType) { + return true; + } + + + @Override + public String getDisplayName() { + return Messages.RunFromFileBuilderStepName(Messages.LrunSvc()); + } + + /** + * Do check fs tests form validation. + * + * @param value the value + * @return the form validation + */ + @SuppressWarnings("squid:S1172") + public FormValidation doCheckFsTests(@QueryParameter String value) { + //TODO + return FormValidation.ok(); + } + + /** + * Do check ignore error strings form validation. + * + * @param value the value + * @return the form validation + */ + @SuppressWarnings("squid:S1172") + public FormValidation doCheckIgnoreErrorStrings(@QueryParameter String value) { + + return FormValidation.ok(); + } + + /** + * Do check fs timeout form validation. + * + * @param value the value + * @return the form validation + */ + public FormValidation doCheckFsTimeout(@QueryParameter String value) { + if (StringUtils.isEmpty(value)) { + return FormValidation.ok(); + } + + String sanitizedValue = value.trim(); + if (sanitizedValue.length() > 0 && sanitizedValue.charAt(0) == '-') { + sanitizedValue = sanitizedValue.substring(1); + } + + if (!isParameterizedValue(sanitizedValue) && !StringUtils.isNumeric(sanitizedValue)) { + return FormValidation.error("Timeout must be a parameter or a number, e.g.: 23, $Timeout or " + + "${Timeout}."); + } + + return FormValidation.ok(); + } + + + /** + * Check if the value is parameterized. + * + * @param value the value + * @return boolean + */ + public boolean isParameterizedValue(String value) { + //Parameter (with or without brackets) + return value.matches("^\\$\\{[\\w-. ]*}$|^\\$[\\w-.]*$"); + } + + + public List getNodes() { + return UftToolUtils.getNodesList(); + } + + // public List getEncodings() { return RunFromServiceModel.encodings; } + } + +} \ No newline at end of file diff --git a/src/main/resources/com/microfocus/application/automation/tools/Messages.properties b/src/main/resources/com/microfocus/application/automation/tools/Messages.properties index 9d596f4d0..036d0d9b7 100644 --- a/src/main/resources/com/microfocus/application/automation/tools/Messages.properties +++ b/src/main/resources/com/microfocus/application/automation/tools/Messages.properties @@ -31,6 +31,7 @@ # CompanyName=OpenText +LrunSvc=Service RunFromAlmBuilderStepName=Execute {0} functional tests from {0} ALM SseBuilderStepName=Execute {0} tests using {0} ALM Lab Management AutEnvironmentBuilderStepName=Execute AUT Environment preparation using {0} ALM Lab Management diff --git a/src/main/resources/com/microfocus/application/automation/tools/run/RunFromService/config.jelly b/src/main/resources/com/microfocus/application/automation/tools/run/RunFromService/config.jelly new file mode 100644 index 000000000..04b878944 --- /dev/null +++ b/src/main/resources/com/microfocus/application/automation/tools/run/RunFromService/config.jelly @@ -0,0 +1,120 @@ + + + + +