org.squashtest.tm.plugin.testautomation.jenkins.TestAutomationJenkinsConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.squashtest.tm.plugin.testautomation.jenkins.TestAutomationJenkinsConnector.java

Source

/**
 *     This file is part of the Squashtest platform.
 *     Copyright (C) 2010 - 2016 Henix, henix.fr
 *
 *     See the NOTICE file distributed with this work for additional
 *     information regarding copyright ownership.
 *
 *     This is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     this software is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with this software.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.squashtest.tm.plugin.testautomation.jenkins;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.squashtest.tm.core.foundation.lang.Couple;
import org.squashtest.tm.domain.testautomation.AutomatedExecutionExtender;
import org.squashtest.tm.domain.testautomation.AutomatedTest;
import org.squashtest.tm.domain.testautomation.TestAutomationProject;
import org.squashtest.tm.domain.testautomation.TestAutomationServer;
import org.squashtest.tm.plugin.testautomation.jenkins.internal.*;
import org.squashtest.tm.plugin.testautomation.jenkins.internal.net.HttpClientProvider;
import org.squashtest.tm.plugin.testautomation.jenkins.internal.net.HttpRequestFactory;
import org.squashtest.tm.plugin.testautomation.jenkins.internal.net.RequestExecutor;
import org.squashtest.tm.plugin.testautomation.jenkins.internal.tasksteps.BuildAbsoluteId;
import org.squashtest.tm.service.testautomation.TestAutomationCallbackService;
import org.squashtest.tm.service.testautomation.spi.TestAutomationConnector;
import org.squashtest.tm.service.testautomation.spi.TestAutomationException;
import org.squashtest.tm.service.testautomation.spi.UnreadableResponseException;

import javax.inject.Inject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;

@Service("plugin.testautomation.jenkins.connector")
public class TestAutomationJenkinsConnector implements TestAutomationConnector {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestAutomationConnector.class);

    private static final String CONNECTOR_KIND = "jenkins";
    private static final int DEFAULT_SPAM_INTERVAL_MILLIS = 5000;

    @Inject
    private TaskScheduler taskScheduler;
    @Inject
    private HttpClientProvider clientProvider;

    private JsonParser jsonParser = new JsonParser();
    private HttpRequestFactory requestFactory = new HttpRequestFactory();

    @Value("${tm.test.automation.pollinterval.millis}")
    private int spamInterval = DEFAULT_SPAM_INTERVAL_MILLIS;

    private RequestExecutor requestExecutor = RequestExecutor.getInstance();

    // ****************************** let's roll ****************************************

    @Override
    public String getConnectorKind() {
        return CONNECTOR_KIND;
    }

    @Override
    public boolean checkCredentials(TestAutomationServer server) {

        CloseableHttpClient client = clientProvider.getClientFor(server);

        HttpGet credCheck = requestFactory.newCheckCredentialsMethod(server);

        requestExecutor.execute(client, credCheck);

        // if everything went fine, we may return true. Or else let the exception go.
        return true;

    }

    @Override
    public Collection<TestAutomationProject> listProjectsOnServer(TestAutomationServer server)
            throws TestAutomationException {

        CloseableHttpClient client = clientProvider.getClientFor(server);

        HttpGet getJobsMethod = requestFactory.newGetJobsMethod(server);

        String response = requestExecutor.execute(client, getJobsMethod);

        try {
            return jsonParser.readJobListFromJson(response);
        } catch (UnreadableResponseException ex) {
            throw new UnreadableResponseException(
                    "Test automation - jenkins : server '" + server + "' returned malformed response : ",
                    ex.getCause()); // NOSONAR (GRF) call stack broken on purpose, i guess
        }

    }

    @Override
    public Collection<AutomatedTest> listTestsInProject(TestAutomationProject project)
            throws TestAutomationException {

        // first we try an optimistic approach
        try {
            OptimisticTestList otl = new OptimisticTestList(clientProvider, project);
            return otl.run();
        }

        // if the file isn't available we regenerate the file
        catch (Exception ex) {

            CloseableHttpClient client = clientProvider.getClientFor(project.getServer());

            FetchTestListBuildProcessor processor = new FetchTestListBuildProcessor();

            processor.setClient(client);
            processor.setProject(project);
            processor.setBuildAbsoluteId(new BuildAbsoluteId(project.getJobName(), generateNewId()));
            processor.setDefaultReschedulingDelay(spamInterval);

            processor.run();

            return processor.getResult();

        }

    }

    /**
     * @see org.squashtest.tm.service.testautomation.spi.TestAutomationConnector#executeParameterizedTests(java.util.Collection,
     * java.lang.String, org.squashtest.tm.service.testautomation.TestAutomationCallbackService)
     */
    @Override
    public void executeParameterizedTests(
            Collection<Couple<AutomatedExecutionExtender, Map<String, Object>>> parameterizedExecutions,
            String externalId, TestAutomationCallbackService callbackService) {

        MultiValueMap<TestAutomationProject, Couple<AutomatedExecutionExtender, Map<String, Object>>> execsByProject = reduceToParamdExecsByProject(
                parameterizedExecutions);

        List<BuildDef> buildDefs = mapToJobDefs(execsByProject);

        for (BuildDef buildDef : buildDefs) {

            new StartTestExecution(buildDef, clientProvider, externalId).run();

        }

    }

    // ************************************ other private stuffs **************************

    private String generateNewId() {
        return Long.toString(System.currentTimeMillis());
    }

    private List<BuildDef> mapToJobDefs(
            MultiValueMap<TestAutomationProject, Couple<AutomatedExecutionExtender, Map<String, Object>>> execsByProject) {
        ArrayList<BuildDef> jobDefs = new ArrayList<>(execsByProject.size());

        for (Entry<TestAutomationProject, List<Couple<AutomatedExecutionExtender, Map<String, Object>>>> entry : execsByProject
                .entrySet()) {
            if (!entry.getValue().isEmpty()) {
                // fetch the name of the slave node if any
                Couple<AutomatedExecutionExtender, Map<String, Object>> firstEntry = entry.getValue().get(0);

                jobDefs.add(new BuildDef(entry.getKey(), entry.getValue(), firstEntry.getA1().getNodeName()));
            }
        }
        return jobDefs;
    }

    private MultiValueMap<TestAutomationProject, Couple<AutomatedExecutionExtender, Map<String, Object>>> reduceToParamdExecsByProject(
            Collection<Couple<AutomatedExecutionExtender, Map<String, Object>>> parameterizedExecutions) {
        MultiValueMap<TestAutomationProject, Couple<AutomatedExecutionExtender, Map<String, Object>>> execsByProject = new LinkedMultiValueMap<>();

        for (Couple<AutomatedExecutionExtender, Map<String, Object>> paramdExec : parameterizedExecutions) {
            execsByProject.add(paramdExec.getA1().getAutomatedProject(), paramdExec);
        }

        return execsByProject;
    }

    /**
     * @see TestAutomationJenkinsConnector#findTestAutomationProjectURL(TestAutomationProject)
     */
    @Override
    public URL findTestAutomationProjectURL(TestAutomationProject testAutomationProject) {
        TestAutomationServer server = testAutomationProject.getServer();
        String projectUrl = server.getBaseURL().toString() + "/job/" + testAutomationProject.getJobName();
        try {
            return new URL(projectUrl);
        } catch (MalformedURLException e) {
            throw new TestAutomationProjectMalformedURLException(projectUrl, e);
        }
    }

    /**
     * @see TestAutomationJenkinsConnector#testListIsOrderGuaranteed(Collection)
     */
    @Override
    public boolean testListIsOrderGuaranteed(Collection<AutomatedTest> tests) {
        if (tests.isEmpty()) {
            return true;
        }
        Iterator<AutomatedTest> iterator = tests.iterator();
        String firstPath = iterator.next().getPath();
        for (AutomatedTest test : tests) {
            String path = test.getPath();
            if (!firstPath.equals(path)) {
                return false;
            }
        }
        return true;
    }

    public class TestAutomationProjectMalformedURLException extends RuntimeException {

        /**
         *
         */
        private static final long serialVersionUID = -4904491027261699261L;

        public TestAutomationProjectMalformedURLException(String projectUrl, Exception e) {
            super("The test automation project url : " + projectUrl + ", is malformed", e);
        }

    }

}