util.ItUtils.java Source code

Java tutorial

Introduction

Here is the source code for util.ItUtils.java

Source

/*
 * SonarQube
 * Copyright (C) 2009-2017 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program 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 program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package util;

import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.BuildResult;
import com.sonar.orchestrator.build.SonarRunner;
import com.sonar.orchestrator.container.Server;
import com.sonar.orchestrator.locator.FileLocation;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.io.FileUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.sonar.wsclient.base.HttpException;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueClient;
import org.sonar.wsclient.issue.IssueQuery;
import org.sonarqube.ws.WsComponents.Component;
import org.sonarqube.ws.WsMeasures;
import org.sonarqube.ws.WsMeasures.Measure;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsClientFactories;
import org.sonarqube.ws.client.component.ShowWsRequest;
import org.sonarqube.ws.client.measure.ComponentWsRequest;
import org.sonarqube.ws.client.organization.OrganizationService;
import org.sonarqube.ws.client.organization.SearchWsRequest;
import org.sonarqube.ws.client.qualityprofile.RestoreWsRequest;
import org.sonarqube.ws.client.setting.ResetRequest;
import org.sonarqube.ws.client.setting.SetRequest;

import static com.google.common.base.Preconditions.checkState;
import static com.sonar.orchestrator.container.Server.ADMIN_LOGIN;
import static com.sonar.orchestrator.container.Server.ADMIN_PASSWORD;
import static java.lang.Double.parseDouble;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Locale.ENGLISH;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

public class ItUtils {
    public static final Splitter LINE_SPLITTER = Splitter.on(System.getProperty("line.separator"));

    private ItUtils() {
    }

    public static FileLocation xooPlugin() {
        return FileLocation.byWildcardMavenFilename(new File("../../plugins/sonar-xoo-plugin/target"),
                "sonar-xoo-plugin-*.jar");
    }

    public static List<Issue> getAllServerIssues(Orchestrator orchestrator) {
        IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
        return issueClient.find(IssueQuery.create()).list();
    }

    public static WsClient newAdminWsClient(Orchestrator orchestrator) {
        return newUserWsClient(orchestrator, ADMIN_LOGIN, ADMIN_PASSWORD);
    }

    public static WsClient newWsClient(Orchestrator orchestrator) {
        return newUserWsClient(orchestrator, null, null);
    }

    public static WsClient newUserWsClient(Orchestrator orchestrator, @Nullable String login,
            @Nullable String password) {
        Server server = orchestrator.getServer();
        return WsClientFactories.getDefault()
                .newClient(HttpConnector.newBuilder().url(server.getUrl()).credentials(login, password).build());
    }

    /**
     * Locate the directory of sample project
     *
     * @param relativePath path related to the directory it/it-projects, for example "qualitygate/xoo-sample"
     */
    public static File projectDir(String relativePath) {
        File dir = new File("../it-projects/" + relativePath);
        if (!dir.exists() || !dir.isDirectory()) {
            throw new IllegalStateException("Directory does not exist: " + dir.getAbsolutePath());
        }
        return dir;
    }

    /**
     * Locate the artifact of a fake plugin stored in it/it-plugins.
     *
     * @param dirName the directory of it/it-plugins, for example "sonar-fake-plugin".
     *                     It assumes that version is 1.0-SNAPSHOT
     */
    public static FileLocation pluginArtifact(String dirName) {
        return FileLocation.byWildcardMavenFilename(new File("../it-plugins/" + dirName + "/target"),
                dirName + "-*.jar");
    }

    /**
     * Locate the pom file of a sample project
     *
     * @param projectName project path related to the directory it/it-projects, for example "qualitygate/xoo-sample"
     */
    public static File projectPom(String projectName) {
        File pom = new File(projectDir(projectName), "pom.xml");
        if (!pom.exists() || !pom.isFile()) {
            throw new IllegalStateException("pom file does not exist: " + pom.getAbsolutePath());
        }
        return pom;
    }

    public static String sanitizeTimezones(String s) {
        return s.replaceAll("[\\+\\-]\\d\\d\\d\\d", "+0000");
    }

    public static JSONObject getJSONReport(BuildResult result) {
        Pattern pattern = Pattern.compile("Export issues to (.*?).json");
        Matcher m = pattern.matcher(result.getLogs());
        if (m.find()) {
            String s = m.group(1);
            File path = new File(s + ".json");
            assertThat(path).exists();
            try {
                return (JSONObject) JSONValue.parse(FileUtils.readFileToString(path));
            } catch (IOException e) {
                throw new RuntimeException("Unable to read JSON report", e);
            }
        }
        fail("Unable to locate json report");
        return null;
    }

    public static int countIssuesInJsonReport(BuildResult result, boolean onlyNews) {
        JSONObject obj = getJSONReport(result);
        JSONArray issues = (JSONArray) obj.get("issues");
        int count = 0;
        for (Object issue : issues) {
            JSONObject jsonIssue = (JSONObject) issue;
            if (!onlyNews || (Boolean) jsonIssue.get("isNew")) {
                count++;
            }
        }
        return count;
    }

    public static void assertIssuesInJsonReport(BuildResult result, int newIssues, int resolvedIssues,
            int existingIssues) {
        JSONObject obj = getJSONReport(result);
        JSONArray issues = (JSONArray) obj.get("issues");
        int countNew = 0;
        int countResolved = 0;
        int countExisting = 0;

        for (Object issue : issues) {
            JSONObject jsonIssue = (JSONObject) issue;

            if ((Boolean) jsonIssue.get("isNew")) {
                countNew++;
            } else if (jsonIssue.get("resolution") != null) {
                countResolved++;
            } else {
                countExisting++;
            }
        }
        assertThat(countNew).isEqualTo(newIssues);
        assertThat(countResolved).isEqualTo(resolvedIssues);
        assertThat(countExisting).isEqualTo(existingIssues);
    }

    public static SonarRunner runVerboseProjectAnalysis(Orchestrator orchestrator, String projectRelativePath,
            String... properties) {
        return runProjectAnalysis(orchestrator, projectRelativePath, true, properties);
    }

    public static SonarRunner runProjectAnalysis(Orchestrator orchestrator, String projectRelativePath,
            String... properties) {
        return runProjectAnalysis(orchestrator, projectRelativePath, false, properties);
    }

    private static SonarRunner runProjectAnalysis(Orchestrator orchestrator, String projectRelativePath,
            boolean enableDebugLogs, String... properties) {
        SonarRunner sonarRunner = SonarRunner.create(projectDir(projectRelativePath));
        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
        for (int i = 0; i < properties.length; i += 2) {
            builder.put(properties[i], properties[i + 1]);
        }
        SonarRunner scan = sonarRunner.setDebugLogs(enableDebugLogs).setProperties(builder.build());
        orchestrator.executeBuild(scan);
        return scan;
    }

    public static void setServerProperty(Orchestrator orchestrator, String key, @Nullable String value) {
        setServerProperty(orchestrator, null, key, value);
    }

    public static void setServerProperty(Orchestrator orchestrator, @Nullable String componentKey, String key,
            @Nullable String value) {
        if (value == null) {
            newAdminWsClient(orchestrator).settingsService()
                    .reset(ResetRequest.builder().setKeys(key).setComponent(componentKey).build());
        } else {
            newAdminWsClient(orchestrator).settingsService()
                    .set(SetRequest.builder().setKey(key).setValue(value).setComponent(componentKey).build());
        }
    }

    public static void setServerProperties(Orchestrator orchestrator, @Nullable String componentKey,
            String... properties) {
        for (int i = 0; i < properties.length; i += 2) {
            setServerProperty(orchestrator, componentKey, properties[i], properties[i + 1]);
        }
    }

    public static void resetSettings(Orchestrator orchestrator, @Nullable String componentKey, String... keys) {
        if (keys.length > 0) {
            newAdminWsClient(orchestrator).settingsService()
                    .reset(ResetRequest.builder().setKeys(keys).setComponent(componentKey).build());
        }
    }

    public static void resetEmailSettings(Orchestrator orchestrator) {
        resetSettings(orchestrator, null, "email.smtp_host.secured", "email.smtp_port.secured",
                "email.smtp_secure_connection.secured", "email.smtp_username.secured",
                "email.smtp_password.secured", "email.from", "email.prefix");
    }

    public static void resetPeriod(Orchestrator orchestrator) {
        resetSettings(orchestrator, null, "sonar.leak.period");
    }

    @CheckForNull
    public static Measure getMeasure(Orchestrator orchestrator, String componentKey, String metricKey) {
        return getMeasuresByMetricKey(orchestrator, componentKey, metricKey).get(metricKey);
    }

    @CheckForNull
    public static Double getMeasureAsDouble(Orchestrator orchestrator, String componentKey, String metricKey) {
        Measure measure = getMeasure(orchestrator, componentKey, metricKey);
        return (measure == null) ? null : Double.parseDouble(measure.getValue());
    }

    public static Map<String, Measure> getMeasuresByMetricKey(Orchestrator orchestrator, String componentKey,
            String... metricKeys) {
        return getStreamMeasures(orchestrator, componentKey, metricKeys).filter(Measure::hasValue)
                .collect(Collectors.toMap(Measure::getMetric, Function.identity()));
    }

    public static Map<String, Double> getMeasuresAsDoubleByMetricKey(Orchestrator orchestrator, String componentKey,
            String... metricKeys) {
        return getStreamMeasures(orchestrator, componentKey, metricKeys).filter(Measure::hasValue)
                .collect(Collectors.toMap(Measure::getMetric, measure -> parseDouble(measure.getValue())));
    }

    private static Stream<Measure> getStreamMeasures(Orchestrator orchestrator, String componentKey,
            String... metricKeys) {
        return newWsClient(orchestrator).measures()
                .component(new ComponentWsRequest().setComponentKey(componentKey).setMetricKeys(asList(metricKeys)))
                .getComponent().getMeasuresList().stream();
    }

    @CheckForNull
    public static Measure getMeasureWithVariation(Orchestrator orchestrator, String componentKey,
            String metricKey) {
        WsMeasures.ComponentWsResponse response = newWsClient(orchestrator).measures()
                .component(new ComponentWsRequest().setComponentKey(componentKey)
                        .setMetricKeys(singletonList(metricKey)).setAdditionalFields(singletonList("periods")));
        List<Measure> measures = response.getComponent().getMeasuresList();
        return measures.size() == 1 ? measures.get(0) : null;
    }

    @CheckForNull
    public static Map<String, Measure> getMeasuresWithVariationsByMetricKey(Orchestrator orchestrator,
            String componentKey, String... metricKeys) {
        return newWsClient(orchestrator).measures()
                .component(new ComponentWsRequest().setComponentKey(componentKey).setMetricKeys(asList(metricKeys))
                        .setAdditionalFields(singletonList("periods")))
                .getComponent().getMeasuresList().stream()
                .collect(Collectors.toMap(Measure::getMetric, Function.identity()));
    }

    /**
     * Return leak period value
     */
    @CheckForNull
    public static Double getLeakPeriodValue(Orchestrator orchestrator, String componentKey, String metricKey) {
        List<WsMeasures.PeriodValue> periodsValueList = getMeasureWithVariation(orchestrator, componentKey,
                metricKey).getPeriods().getPeriodsValueList();
        return periodsValueList.size() > 0 ? Double.parseDouble(periodsValueList.get(0).getValue()) : null;
    }

    @CheckForNull
    public static Component getComponent(Orchestrator orchestrator, String componentKey) {
        try {
            return newWsClient(orchestrator).components().show(new ShowWsRequest().setKey((componentKey)))
                    .getComponent();
        } catch (org.sonarqube.ws.client.HttpException e) {
            if (e.code() == 404) {
                return null;
            }
            throw new IllegalStateException(e);
        }
    }

    @CheckForNull
    public static ComponentNavigation getComponentNavigation(Orchestrator orchestrator, String componentKey) {
        // Waiting for SONAR-7745 to have version in api/components/show, we use internal api/navigation/component WS to get the component
        // version
        String content = newWsClient(orchestrator).wsConnector()
                .call(new GetRequest("api/navigation/component").setParam("componentKey", componentKey))
                .failIfNotSuccessful().content();
        return ComponentNavigation.parse(content);
    }

    public static void restoreProfile(Orchestrator orchestrator, URL resource) {
        restoreProfile(orchestrator, resource, null);
    }

    public static void restoreProfile(Orchestrator orchestrator, URL resource, String organization) {
        URI uri;
        try {
            uri = resource.toURI();
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException(
                    "Cannot find quality profile xml file '" + resource + "' in classpath");
        }
        newAdminWsClient(orchestrator).qualityProfiles().restoreProfile(
                RestoreWsRequest.builder().setBackup(new File(uri)).setOrganization(organization).build());
    }

    public static String newOrganizationKey() {
        return randomAlphabetic(32).toLowerCase(ENGLISH);
    }

    public static String newProjectKey() {
        return "key-" + randomAlphabetic(200);
    }

    public static void deleteOrganizationsIfExists(Orchestrator orchestrator, String... organizationKeys) {
        OrganizationService adminOrganizationService = newAdminWsClient(orchestrator).organizations();
        adminOrganizationService.search(SearchWsRequest.builder().setOrganizations(organizationKeys).build())
                .getOrganizationsList()
                .forEach(organization -> adminOrganizationService.delete(organization.getKey()));
    }

    public static class ComponentNavigation {
        private String version;
        private String snapshotDate;

        public String getVersion() {
            return version;
        }

        public Date getDate() {
            return toDatetime(snapshotDate);
        }

        public static ComponentNavigation parse(String json) {
            Gson gson = new Gson();
            return gson.fromJson(json, ComponentNavigation.class);
        }
    }

    /**
     * Concatenates a vararg to a String array.
     *
     * Useful when using {@link #runVerboseProjectAnalysis(Orchestrator, String, String...)}, eg.:
     * <pre>
     * ItUtils.runProjectAnalysis(orchestrator, "project_name",
     *    ItUtils.concat(properties, "sonar.scm.disabled", "false")
     *    );
     * </pre>
     */
    public static String[] concat(String[] properties, String... str) {
        if (properties == null || properties.length == 0) {
            return str;
        }
        return Stream.concat(Arrays.stream(properties), Arrays.stream(str)).toArray(String[]::new);
    }

    public static void verifyHttpException(Exception e, int expectedCode) {
        assertThat(e).isInstanceOf(HttpException.class);
        HttpException exception = (HttpException) e;
        assertThat(exception.status()).isEqualTo(expectedCode);
    }

    public static Date toDate(String sDate) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.parse(sDate);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static Date toDatetime(String sDate) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
            return sdf.parse(sDate);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static String formatDate(Date d) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(d);
    }

    public static String extractCeTaskId(BuildResult buildResult) {
        List<String> taskIds = extractCeTaskIds(buildResult);
        checkState(taskIds.size() == 1, "More than one task id retrieved from logs");
        return taskIds.iterator().next();
    }

    public static List<String> extractCeTaskIds(BuildResult buildResult) {
        String logs = buildResult.getLogs();
        return StreamSupport.stream(LINE_SPLITTER.split(logs).spliterator(), false)
                .filter(s -> s.contains("More about the report processing at"))
                .map(s -> s.substring(s.length() - 20, s.length())).collect(Collectors.toList());
    }

    public static Map<String, Object> jsonToMap(String json) {
        Gson gson = new Gson();
        Type type = new TypeToken<Map<String, Object>>() {
        }.getType();
        return gson.fromJson(json, type);
    }

    public static Response call(String url, String... headers) {
        Request.Builder requestBuilder = new Request.Builder().get().url(url);
        for (int i = 0; i < headers.length; i += 2) {
            String headerName = headers[i];
            String headerValue = headers[i + 1];
            if (headerValue != null) {
                requestBuilder.addHeader(headerName, headerValue);
            }
        }
        try {
            return new OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS)
                    .build().newCall(requestBuilder.build()).execute();
        } catch (IOException e) {
            throw Throwables.propagate(e);
        }
    }
}