com.hpe.application.automation.tools.run.RunLoadRunnerScript.java Source code

Java tutorial

Introduction

Here is the source code for com.hpe.application.automation.tools.run.RunLoadRunnerScript.java

Source

/*
 *  Copyright 2013 EntIT Software LLC
 *  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
 *
 * Copyright (c) 2018 Micro Focus Company, L.P.
 *
 * 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.hpe.application.automation.tools.run;

import com.hpe.application.automation.tools.results.lrscriptresultparser.LrScriptHtmlReportAction;
import com.hpe.application.automation.tools.results.lrscriptresultparser.LrScriptResultsSanitizer;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Builder;
import hudson.tasks.junit.JUnitResultArchiver;
import hudson.util.ArgumentListBuilder;
import jenkins.model.Jenkins;
import jenkins.tasks.SimpleBuildStep;
import jenkins.util.VirtualFile;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.input.BOMInputStream;
import org.kohsuke.stapler.DataBoundConstructor;

import javax.annotation.Nonnull;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;

/**
 * Created by kazaky on 14/03/2017.
 */

/**
 * This step enables to run LoadRunner scripts directly and collecting their results by converting them to JUnit
 */
public class RunLoadRunnerScript extends Builder implements SimpleBuildStep {
    public static final String LR_SCRIPT_HTML_REPORT_CSS = "PResults.css";
    private static final String LINUX_MDRV_PATH = "/bin/mdrv";
    private static final String WIN_MDRV_PATH = "\\bin\\mmdrv.exe";
    private static final String LR_SCRIPT_HTML_XSLT = "PDetails.xsl";
    private static final String LR_SCRIPT_HTML_CSS = "LR_SCRIPT_REPORT.css";
    private String scriptsPath;
    private Jenkins jenkinsInstance;
    private PrintStream logger;
    private EnvVars slaveEnvVars;

    @DataBoundConstructor
    public RunLoadRunnerScript(@Nonnull String scriptsPath) {
        if (scriptsPath.equals(DescriptorImpl.DEFAULT_SCRIPTS_PATH)) {
            this.scriptsPath = "";
        } else {
            this.scriptsPath = scriptsPath;
        }
    }

    /**
     * Returns {@link BuildStepMonitor#NONE} by default, as {@link Builder}s normally don't depend
     * on its previous result.
     */
    @Override
    public BuildStepMonitor getRequiredMonitorService() {
        return BuildStepMonitor.NONE;
    }

    public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace, @Nonnull Launcher launcher,
            @Nonnull TaskListener listener, @Nonnull EnvVars envVars) throws InterruptedException, IOException {
        this.slaveEnvVars = envVars;
        this.perform(build, workspace, launcher, listener);
    }

    @Override
    public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace, @Nonnull Launcher launcher,
            @Nonnull TaskListener listener) throws InterruptedException, IOException {
        try {
            jenkinsInstance = Jenkins.getInstance();
            if (jenkinsInstance == null) {
                listener.error("Failed loading Jenkins instance ");
                build.setResult(Result.FAILURE);
                return;
            }
            logger = listener.getLogger();
            ArgumentListBuilder args = new ArgumentListBuilder();
            String scriptName = FilenameUtils.getBaseName(this.scriptsPath);
            FilePath buildWorkDir = workspace.child(build.getId());
            buildWorkDir.mkdirs();
            buildWorkDir = buildWorkDir.absolutize();
            if (build instanceof AbstractBuild) {
                slaveEnvVars = build.getEnvironment(listener);
            }
            FilePath scriptPath = workspace.child(slaveEnvVars.expand(this.scriptsPath));
            FilePath scriptWorkDir = buildWorkDir.child(scriptName);
            scriptWorkDir.mkdirs();
            scriptWorkDir = scriptWorkDir.absolutize();

            if (runScriptMdrv(launcher, args, slaveEnvVars, scriptPath, scriptWorkDir)) {
                build.setResult(Result.FAILURE);
                return;
            }

            final VirtualFile root = build.getArtifactManager().root();

            File masterBuildWorkspace = new File(new File(root.toURI()), "LRReport");
            if (!masterBuildWorkspace.exists()) {
                if (!root.exists()) {
                    (new File(root.toURI())).mkdirs();
                }
                masterBuildWorkspace.mkdirs();
            }

            FilePath outputHTML = buildWorkDir.child(scriptName);
            outputHTML.mkdirs();
            outputHTML = outputHTML.child("result.html");
            FilePath xsltOnNode = copyXsltToNode(workspace);
            createHtmlReports(buildWorkDir, scriptName, outputHTML, xsltOnNode);
            LrScriptResultsParser lrScriptResultsParser = new LrScriptResultsParser(listener);
            lrScriptResultsParser.parseScriptResult(scriptName, buildWorkDir);
            copyScriptsResultToMaster(build, listener, buildWorkDir, new FilePath(masterBuildWorkspace));
            parseJunitResult(build, launcher, listener, buildWorkDir, scriptName);
            addLrScriptHtmlReportAcrion(build, scriptName);

            build.setResult(Result.SUCCESS);

        } catch (IllegalArgumentException e) {
            build.setResult(Result.FAILURE);
            logger.println(e);
        } catch (IOException | InterruptedException e) {
            listener.error("Failed loading build environment " + e);
            build.setResult(Result.FAILURE);
        } catch (XMLStreamException e) {
            listener.error(e.getMessage(), e);
            build.setResult(Result.FAILURE);
        }
    }

    private FilePath copyXsltToNode(@Nonnull FilePath workspace) throws IOException, InterruptedException {
        final URL xsltPath = jenkinsInstance.pluginManager.uberClassLoader.getResource(LR_SCRIPT_HTML_XSLT);
        logger.println("loading XSLT from " + xsltPath.getFile());
        FilePath xsltOnNode = workspace.child("resultsHtml.xslt");
        if (!xsltOnNode.exists()) {
            xsltOnNode.copyFrom(xsltPath);
        }
        return xsltOnNode;
    }

    private boolean runScriptMdrv(@Nonnull Launcher launcher, ArgumentListBuilder args, EnvVars env,
            FilePath scriptPath, FilePath scriptWorkDir) throws IOException, InterruptedException {
        FilePath mdrv;
        //base command line mmdrv.exe -usr "%1\%1.usr" -extra_ext NVReportExt -qt_result_dir
        // "c:\%1_results"
        //Do run the script on linux or windows?
        mdrv = getMDRVPath(launcher, env);
        args.add(mdrv);
        args.add("-usr");
        args.add(scriptPath);
        args.add("-extra_ext NVReportExt");
        args.add("-qt_result_dir");
        args.add(scriptWorkDir);

        int returnCode = launcher.launch().cmds(args).stdout(logger).pwd(scriptWorkDir).join();
        return returnCode != 0;
    }

    private static FilePath getMDRVPath(@Nonnull Launcher launcher, EnvVars env) {
        FilePath mdrv;
        if (launcher.isUnix()) {
            String lrPath = env.get("M_LROOT", "");
            if ("".equals(lrPath)) {
                throw new LrScriptParserException(
                        "Please make sure environment variables are set correctly on the running node - M_LROOT for "
                                + "linux");
            }
            lrPath += LINUX_MDRV_PATH;
            mdrv = new FilePath(launcher.getChannel(), lrPath);
        } else {
            String lrPath = env.get("LR_PATH", "");
            if ("".equals(lrPath)) {
                throw new LrScriptParserException("Please make sure environment variables are set correctly on the "
                        + "running node - LR_PATH for windows");
            }
            lrPath += WIN_MDRV_PATH;
            mdrv = new FilePath(launcher.getChannel(), lrPath);
        }
        return mdrv;
    }

    private void addLrScriptHtmlReportAcrion(@Nonnull Run<?, ?> build, String scriptName) {
        synchronized (build) {
            LrScriptHtmlReportAction action = build.getAction(LrScriptHtmlReportAction.class);
            if (action == null) {
                action = new LrScriptHtmlReportAction(build);
                action.mergeResult(build, scriptName);
                build.addAction(action);
            } else {
                action.mergeResult(build, scriptName);
            }
        }
    }

    private static void parseJunitResult(@Nonnull Run<?, ?> build, @Nonnull Launcher launcher,
            @Nonnull TaskListener listener, FilePath buildWorkDir, String scriptName)
            throws InterruptedException, IOException {
        JUnitResultArchiver jUnitResultArchiver = new JUnitResultArchiver("JunitResult.xml");
        jUnitResultArchiver.setKeepLongStdio(true);
        jUnitResultArchiver.setAllowEmptyResults(true);
        jUnitResultArchiver.perform(build, buildWorkDir.child(scriptName), launcher, listener);
    }

    private void createHtmlReports(FilePath buildWorkDir, String scriptName, FilePath outputHTML,
            FilePath xsltOnNode) throws IOException, InterruptedException, XMLStreamException {
        if (!buildWorkDir.exists()) {
            throw new IllegalArgumentException("Build worker doesn't exist");
        }
        if ("".equals(scriptName)) {
            throw new IllegalArgumentException("Script name is empty");
        }
        if (!xsltOnNode.exists()) {
            throw new IllegalArgumentException("LR Html report doesn't exist on the node");
        }
        try {
            TransformerFactory factory = TransformerFactory.newInstance();
            StreamSource xslStream = new StreamSource(xsltOnNode.read());
            Transformer transformer = factory.newTransformer(xslStream);

            CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
            decoder.onMalformedInput(CodingErrorAction.REPLACE).replacement();

            final InputStreamReader inputStreamReader = new InputStreamReader(
                    new BOMInputStream(buildWorkDir.child(scriptName).child("Results.xml").read()), decoder);

            StreamSource in = new StreamSource(new LrScriptResultsSanitizer(inputStreamReader));
            StreamResult out = new StreamResult(outputHTML.write());
            transformer.transform(in, out);
            final URL lrHtmlCSSPath = jenkinsInstance.pluginManager.uberClassLoader.getResource(LR_SCRIPT_HTML_CSS);
            if (lrHtmlCSSPath == null) {
                throw new LrScriptParserException(
                        "For some reason the jenkins instance is null - is it an improper set tests?");
            }

            FilePath lrScriptHtmlReportCss = buildWorkDir.child(scriptName).child(LR_SCRIPT_HTML_REPORT_CSS);
            lrScriptHtmlReportCss.copyFrom(lrHtmlCSSPath);

            logger.println("The generated HTML file is:" + outputHTML);
        } catch (TransformerConfigurationException e) {
            logger.println("TransformerConfigurationException");
            logger.println(e);
        } catch (TransformerException e) {
            logger.println("TransformerException");
            logger.println(e);
        } catch (LrScriptParserException e) {
            logger.println("General exception");
            logger.println(e);
        }
    }

    private static void copyScriptsResultToMaster(@Nonnull Run<?, ?> build, @Nonnull TaskListener listener,
            FilePath buildWorkDir, FilePath masterBuildWorkspace) throws IOException, InterruptedException {
        listener.getLogger().printf("Copying script results, from '%s' on node to '%s' on the master. %n",
                buildWorkDir.toURI(), build.getRootDir().toURI());

        buildWorkDir.copyRecursiveTo(masterBuildWorkspace);
    }

    public @Nonnull String getScriptsPath() {
        return scriptsPath == null ? DescriptorImpl.DEFAULT_SCRIPTS_PATH : this.scriptsPath;
    }

    @Extension
    public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
        public static final String DEFAULT_SCRIPTS_PATH = "";

        @Override
        public String getDisplayName() {
            return "Run LoadRunner script";
        }

        @Override
        public boolean isApplicable(@SuppressWarnings("rawtypes") Class<? extends AbstractProject> aClass) {
            return true;
        }

    }

    public static final class LrScriptParserException extends IllegalArgumentException {

        public LrScriptParserException(String s) {
            super(s);
        }

    }

}