123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- /*
- * 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 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);
- }
- }
- }
|