hudson.plugins.testlink.util.TestLinkHelper.java Source code

Java tutorial

Introduction

Here is the source code for hudson.plugins.testlink.util.TestLinkHelper.java

Source

/* 
 * The MIT License
 * 
 * Copyright (c) 2010 Bruno P. Kinoshita <http://www.kinoshita.eti.br>
 * 
 * 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 hudson.plugins.testlink.util;

import hudson.EnvVars;
import hudson.model.BuildListener;
import hudson.plugins.testlink.Report;
import hudson.plugins.testlink.TestLinkBuildAction;
import hudson.plugins.testlink.result.TestCaseWrapper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;

import br.eti.kinoshita.testlinkjavaapi.constants.ExecutionStatus;
import br.eti.kinoshita.testlinkjavaapi.model.Build;
import br.eti.kinoshita.testlinkjavaapi.model.CustomField;
import br.eti.kinoshita.testlinkjavaapi.model.TestCaseStep;
import br.eti.kinoshita.testlinkjavaapi.model.TestPlan;
import br.eti.kinoshita.testlinkjavaapi.model.TestProject;

/**
 * Helper methods for TestLink.
 * 
 * @author Bruno P. Kinoshita
 * @since 2.0
 */
public final class TestLinkHelper {

    // Environment Variables names.
    private static final String TESTLINK_TESTCASE_PREFIX = "TESTLINK_TESTCASE_";
    private static final String TESTLINK_TESTCASE_STEP_PREFIX = "TESTLINK_TESTCASE_STEP_";
    private static final String TESTLINK_TESTCASE_ID_ENVVAR = "TESTLINK_TESTCASE_ID";
    private static final String TESTLINK_TESTCASE_NAME_ENVVAR = "TESTLINK_TESTCASE_NAME";
    private static final String TESTLINK_TESTCASE_TESTSUITE_ID_ENVVAR = "TESTLINK_TESTCASE_TESTSUITEID";
    private static final String TESTLINK_TESTCASE_TESTPROJECT_ID = "TESTLINK_TESTCASE_TESTPROJECTID";
    private static final String TESTLINK_TESTCASE_AUTHOR_ENVVAR = "TESTLINK_TESTCASE_AUTHOR";
    private static final String TESTLINK_TESTCASE_SUMMARY_ENVVAR = "TESTLINK_TESTCASE_SUMMARY";
    private static final String TESTLINK_BUILD_NAME_ENVVAR = "TESTLINK_BUILD_NAME";
    private static final String TESTLINK_TESTPLAN_NAME_ENVVAR = "TESTLINK_TESTPLAN_NAME";
    private static final String TESTLINK_TESTPROJECT_NAME_ENVVAR = "TESTLINK_TESTPROJECT_NAME";

    // Used for HTTP basic auth
    private static final String BASIC_HTTP_PASSWORD = "basicPassword";

    /**
     * Default hidden constructor for a helper class.
     */
    private TestLinkHelper() {
        super();
    }

    /**
     * Retrieves the text for an execution status wrapped in html tags that add 
     * color to the text. Green for sucess, yellow for blocked, gray for not ran 
     * and red for failed. If the plug-in supports the locale the text will be 
     * translated automatically.
     * 
     * @param executionStatus the execution status.
     * @return the text wrapped in html tags that add color to the text.
     */
    public static String getExecutionStatusTextColored(ExecutionStatus executionStatus) {
        String executionStatusTextColored = "Undefined";
        if (executionStatus == ExecutionStatus.FAILED) {
            executionStatusTextColored = "<span style='color: red'>Failed</span>";
        }
        if (executionStatus == ExecutionStatus.PASSED) {
            executionStatusTextColored = "<span style='color: green'>Passed</span>";
        }
        if (executionStatus == ExecutionStatus.BLOCKED) {
            executionStatusTextColored = "<span style='color: yellow'>Blocked</span>";
        }
        if (executionStatus == ExecutionStatus.NOT_RUN) {
            executionStatusTextColored = "<span style='color: gray'>Not Run</span>";
        }
        return executionStatusTextColored;
    }

    /**
     * <p>Defines TestLink Java API Properties. Following is the list of available 
     * properties.</p>
     * 
     * <ul>
     *     <li>xmlrpc.basicEncoding</li>
      *     <li>xmlrpc.basicPassword</li>
      *     <li>xmlrpc.basicUsername</li>
      *     <li>xmlrpc.connectionTimeout</li>
      *     <li>xmlrpc.contentLengthOptional</li>
      *     <li>xmlrpc.enabledForExceptions</li>
      *     <li>xmlrpc.encoding</li>
      *     <li>xmlrpc.gzipCompression</li>
      *     <li>xmlrpc.gzipRequesting</li>
      *     <li>xmlrpc.replyTimeout</li>
      *     <li>xmlrpc.userAgent</li>
     * </ul>
     * 
     * @param testLinkJavaAPIProperties
     * @param listener Jenkins Build listener
     */
    public static void setTestLinkJavaAPIProperties(String testLinkJavaAPIProperties, BuildListener listener) {
        if (StringUtils.isNotBlank(testLinkJavaAPIProperties)) {
            final StringTokenizer tokenizer = new StringTokenizer(testLinkJavaAPIProperties, ",");

            if (tokenizer.countTokens() > 0) {
                while (tokenizer.hasMoreTokens()) {
                    String systemProperty = tokenizer.nextToken();
                    maybeAddSystemProperty(systemProperty, listener);
                }
            }
        }
    }

    /**
     * Maybe adds a system property if it is in format <key>=<value>.
     * 
     * @param systemProperty System property entry in format <key>=<value>.
     * @param listener Jenkins Build listener
     */
    public static void maybeAddSystemProperty(String systemProperty, BuildListener listener) {
        final StringTokenizer tokenizer = new StringTokenizer(systemProperty, "=:");
        if (tokenizer.countTokens() == 2) {
            final String key = tokenizer.nextToken();
            final String value = tokenizer.nextToken();

            if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
                if (key.contains(BASIC_HTTP_PASSWORD)) {
                    listener.getLogger().println(Messages.TestLinkBuilder_SettingSystemProperty(key, "********"));
                } else {
                    listener.getLogger().println(Messages.TestLinkBuilder_SettingSystemProperty(key, value));
                }
                try {
                    System.setProperty(key, value);
                } catch (SecurityException se) {
                    se.printStackTrace(listener.getLogger());
                }

            }
        }
    }

    /**
     * Creates a Map (name, value) of environment variables for a TestLink Test Case.
     * 
     * @param testCase TestLink test Case.
     * @param testProject TestLink Test Project.
     * @param testPlan TestLink Test Plan.
     * @param build TestLink Build.
     * @return Map (name, value) of environment variables.
     */
    public static Map<String, String> createTestLinkEnvironmentVariables(TestCaseWrapper testCase,
            TestProject testProject, TestPlan testPlan, Build build) {
        Map<String, String> testLinkEnvVar = new HashMap<String, String>();

        testLinkEnvVar.put(TESTLINK_TESTCASE_ID_ENVVAR, "" + testCase.getId());
        testLinkEnvVar.put(TESTLINK_TESTCASE_NAME_ENVVAR, StringUtils.defaultIfEmpty(testCase.getName(), ""));
        testLinkEnvVar.put(TESTLINK_TESTCASE_TESTSUITE_ID_ENVVAR, "" + testCase.getTestSuiteId());
        testLinkEnvVar.put(TESTLINK_TESTCASE_TESTPROJECT_ID, "" + testCase.getTestProjectId());
        testLinkEnvVar.put(TESTLINK_TESTCASE_AUTHOR_ENVVAR, "" + testCase.getAuthorLogin());
        testLinkEnvVar.put(TESTLINK_TESTCASE_SUMMARY_ENVVAR, StringUtils.defaultIfEmpty(testCase.getSummary(), ""));
        testLinkEnvVar.put(TESTLINK_BUILD_NAME_ENVVAR, StringUtils.defaultIfEmpty(build.getName(), ""));
        testLinkEnvVar.put(TESTLINK_TESTPLAN_NAME_ENVVAR, StringUtils.defaultIfEmpty(testPlan.getName(), ""));
        testLinkEnvVar.put(TESTLINK_TESTPROJECT_NAME_ENVVAR, StringUtils.defaultIfEmpty(testProject.getName(), ""));

        List<CustomField> customFields = testCase.getCustomFields();
        for (CustomField customField : customFields) {
            addCustomFieldEnvironmentVariableName(customField, testLinkEnvVar);
        }

        List<TestCaseStep> steps = testCase.getSteps();
        testLinkEnvVar.put(TESTLINK_TESTCASE_STEP_PREFIX + "TOTAL", Integer.toString(steps.size()));
        for (TestCaseStep step : steps) {
            String name = TESTLINK_TESTCASE_STEP_PREFIX + step.getNumber() + "_ACTION";
            String action = step.getActions();
            testLinkEnvVar.put(name, action);

            name = TESTLINK_TESTCASE_STEP_PREFIX + step.getNumber() + "_EXPECTED";
            String expected = step.getExpectedResults();
            testLinkEnvVar.put(name, expected);
        }
        return testLinkEnvVar;
    }

    /**
      * Creates a Map (name, value) of environment variables for a TestLink Test Case.
      * 
      * @param testProject TestLink Test Project.
      * @param testPlan TestLink Test Plan.
      * @param build TestLink Build.
      * @return Map (name, value) of environment variables.
      */
    public static Map<String, String> createTestLinkEnvironmentVariables(int numberOfTests, TestProject testProject,
            TestPlan testPlan, Build build) {
        Map<String, String> testLinkEnvVar = new HashMap<String, String>();

        testLinkEnvVar.put(TESTLINK_BUILD_NAME_ENVVAR, StringUtils.defaultIfEmpty(build.getName(), ""));
        testLinkEnvVar.put(TESTLINK_TESTPLAN_NAME_ENVVAR, StringUtils.defaultIfEmpty(testPlan.getName(), ""));
        testLinkEnvVar.put(TESTLINK_TESTPROJECT_NAME_ENVVAR, StringUtils.defaultIfEmpty(testProject.getName(), ""));

        testLinkEnvVar.put(TESTLINK_TESTCASE_PREFIX + "TOTAL", Integer.toString(numberOfTests));
        return testLinkEnvVar;
    }

    /**
     * <p>Formats a custom field into an environment variable. It appends 
     * TESTLINK_TESTCASE in front of the environment variable name.</p>
     * 
     * <p>So, for example, the custom field which name is Sample  Custom Field and 
     * value is <b>Sample Value</b>, will be added into the environment variables 
     * as TESTLINK_TESTCASE_SAMPLE__CUSTOM_FIELD="Sample Value" (note for the double spaces).</p>
     * 
     * <p>If the custom's value contains commas (,), then this method splits the 
     * value and, for each token found, it creates a new environment variable 
     * appending a numeric index after its name</p>
     * 
     * <p>So, for example, the custom field which name is Sample Custom Field and 
     * value is <b>Sample Value 1, Sample Value 2</b>, will generate three 
     * environment variables: TESTLINK_TESTCASE_SAMPLE_CUSTOM_FIELD="Sample Value 1, Sample Value 2", 
     * TESTLINK_TESTCASE_SAMPLE_CUSTOM_FIELD_0="Sample Value 1" and 
     * TESTLINK_TESTCASE_SAMPLE_CUSTOM_FIELD_1="Sample Value 2".</p> 
     * 
     * @param customField The custom field
     * @param testLinkEnvVar TestLink envVars
     */
    public static void addCustomFieldEnvironmentVariableName(CustomField customField,
            Map<String, String> testLinkEnvVar) {
        String customFieldName = customField.getName();
        String customFieldValue = customField.getValue();

        customFieldName = customFieldName.toUpperCase(); // uppercase
        customFieldName = customFieldName.trim(); // trim
        customFieldName = TESTLINK_TESTCASE_PREFIX + customFieldName; // add prefix
        customFieldName = customFieldName.replaceAll("\\s+", "_"); // replace white spaces

        testLinkEnvVar.put(customFieldName, customFieldValue);

        if (StringUtils.isNotBlank(customFieldValue)) {
            StringTokenizer tokenizer = new StringTokenizer(customFieldValue, ",");
            if (tokenizer.countTokens() > 1) {
                int index = 0;
                while (tokenizer.hasMoreTokens()) {
                    String token = tokenizer.nextToken();
                    token = token.trim();

                    customFieldName = customField.getName();
                    customFieldName = customFieldName.toUpperCase(); // uppercase
                    customFieldName = customFieldName.trim(); // trim

                    String tokenName = TESTLINK_TESTCASE_PREFIX + customFieldName + "_" + index; // add prefix
                    tokenName = tokenName.replaceAll("\\s+", "_"); // replace white spaces

                    testLinkEnvVar.put(tokenName, token);
                    ++index;
                }
            }
        }
    }

    /**
     * Creates EnvVars for a TestLink Test Case.
     * 
     * @param testCase TestLink test Case
     * @param testProject TestLink Test Project
     * @param testPlan TestLink Test Plan
     * @param build TestLink Build
     * @param listener Hudson Build Listener
     * @return EnvVars (environment variables)
     */
    public static EnvVars buildTestCaseEnvVars(TestCaseWrapper testCase, TestProject testProject, TestPlan testPlan,
            Build build, BuildListener listener) {
        // Build environment variables list
        Map<String, String> testLinkEnvironmentVariables = TestLinkHelper
                .createTestLinkEnvironmentVariables(testCase, testProject, testPlan, build);
        // Merge with build environment variables list
        listener.getLogger().println(Messages.TestLinkBuilder_MergingEnvVars());
        final EnvVars buildEnvironment = new EnvVars(testLinkEnvironmentVariables);
        return buildEnvironment;
    }

    /**
      * Creates EnvVars for TestLink entities.
      * 
      * @param numberOfTests number of tests
      * @param testProject TestLink Test Project
      * @param testPlan TestLink Test Plan
      * @param build TestLink Build
      * @param listener Hudson Build Listener
      * @return EnvVars (environment variables)
      */
    public static EnvVars buildTestCaseEnvVars(int numberOfTests, TestProject testProject, TestPlan testPlan,
            Build build, BuildListener listener) {
        // Build environment variables list
        Map<String, String> testLinkEnvironmentVariables = TestLinkHelper
                .createTestLinkEnvironmentVariables(numberOfTests, testProject, testPlan, build);
        // Merge with build environment variables list
        listener.getLogger().println(Messages.TestLinkBuilder_MergingEnvVars());
        final EnvVars buildEnvironment = new EnvVars(testLinkEnvironmentVariables);
        return buildEnvironment;
    }

    /**
     * Creates Report Summary.
     * 
     * @param testLinkReport TestLink Report
     * @param previous Previous TestLink Report
     * @return Report Summary
     */
    public static String createReportSummary(Report testLinkReport, Report previous) {
        StringBuilder builder = new StringBuilder();
        builder.append("<p><b>" + Messages.ReportSummary_Summary_BuildID(testLinkReport.getBuildId()) + "</b></p>");
        builder.append(
                "<p><b>" + Messages.ReportSummary_Summary_BuildName(testLinkReport.getBuildName()) + "</b></p>");
        builder.append("<p><a href=\"" + TestLinkBuildAction.URL_NAME + "\">");

        Integer total = testLinkReport.getTestsTotal();
        Integer previousTotal = previous != null ? previous.getTestsTotal() : total;
        Integer passed = testLinkReport.getPassed();
        Integer previousPassed = previous != null ? previous.getPassed() : passed;
        Integer failed = testLinkReport.getFailed();
        Integer previousFailed = previous != null ? previous.getFailed() : failed;
        Integer blocked = testLinkReport.getBlocked();
        Integer previousBlocked = previous != null ? previous.getBlocked() : blocked;
        Integer notRun = testLinkReport.getNotRun();
        Integer previousNotRun = previous != null ? previous.getNotRun() : notRun;

        builder.append(Messages.ReportSummary_Summary_Text(total + getPlusSignal(total, previousTotal),
                passed + getPlusSignal(passed, previousPassed), failed + getPlusSignal(failed, previousFailed),
                blocked + getPlusSignal(blocked, previousBlocked), notRun + getPlusSignal(notRun, previousNotRun)));

        builder.append("</p>");

        return builder.toString();
    }

    /**
     * Creates detailed Report Summary.
     * 
     * @param report TestLink report
     * @param previous Previous TestLink report
     * @return Detailed Report Summary
     */
    public static String createReportSummaryDetails(Report report, Report previous) {
        final StringBuilder builder = new StringBuilder();

        builder.append("<p>" + Messages.ReportSummary_Details_Header() + "</p>");
        builder.append("<table border=\"1\">\n");
        builder.append("<tr><th>");
        builder.append(Messages.ReportSummary_Details_TestCaseId());
        builder.append("</th><th>");
        builder.append(Messages.ReportSummary_Details_TestCaseExternalId());
        builder.append("</th><th>");
        builder.append(Messages.ReportSummary_Details_Version());
        builder.append("</th><th>");
        builder.append(Messages.ReportSummary_Details_Name());
        builder.append("</th><th>");
        builder.append(Messages.ReportSummary_Details_TestProjectId());
        builder.append("</th><th>");
        builder.append(Messages.ReportSummary_Details_ExecutionStatus());
        builder.append("</th></tr>\n");

        for (TestCaseWrapper tc : report.getTestCases()) {
            builder.append("<tr>\n");

            builder.append("<td>" + tc.getId() + "</td>");
            builder.append("<td>" + tc.getFullExternalId() + "</td>");
            builder.append("<td>" + tc.getVersion() + "</td>");
            builder.append("<td>" + tc.getName() + "</td>");
            builder.append("<td>" + tc.getTestProjectId() + "</td>");
            builder.append(
                    "<td>" + TestLinkHelper.getExecutionStatusTextColored(tc.getExecutionStatus()) + "</td>\n");

            builder.append("</tr>\n");
        }

        builder.append("</table>");
        return builder.toString();
    }

    /**
     * Prints the difference between two int values, showing a plus sign if the 
     * current number is greater than the previous. 
     * 
     * @param current Current value
     * @param previous Previous value
     */
    public static String getPlusSignal(int current, int previous) {
        int difference = current - previous;
        return difference > 0 ? " (+" + difference + ")" : "";
    }

}