Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

ItUtils.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2017 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package util;
  21. import com.google.common.base.Splitter;
  22. import com.google.common.base.Throwables;
  23. import com.google.common.collect.ImmutableMap;
  24. import com.google.gson.Gson;
  25. import com.google.gson.reflect.TypeToken;
  26. import com.sonar.orchestrator.Orchestrator;
  27. import com.sonar.orchestrator.build.BuildResult;
  28. import com.sonar.orchestrator.build.SonarRunner;
  29. import com.sonar.orchestrator.container.Server;
  30. import com.sonar.orchestrator.locator.FileLocation;
  31. import java.io.File;
  32. import java.io.IOException;
  33. import java.lang.reflect.Type;
  34. import java.net.URI;
  35. import java.net.URISyntaxException;
  36. import java.net.URL;
  37. import java.text.ParseException;
  38. import java.text.SimpleDateFormat;
  39. import java.util.Arrays;
  40. import java.util.Date;
  41. import java.util.List;
  42. import java.util.Map;
  43. import java.util.concurrent.TimeUnit;
  44. import java.util.function.Function;
  45. import java.util.regex.Matcher;
  46. import java.util.regex.Pattern;
  47. import java.util.stream.Collectors;
  48. import java.util.stream.Stream;
  49. import java.util.stream.StreamSupport;
  50. import javax.annotation.CheckForNull;
  51. import javax.annotation.Nullable;
  52. import okhttp3.OkHttpClient;
  53. import okhttp3.Request;
  54. import okhttp3.Response;
  55. import org.apache.commons.io.FileUtils;
  56. import org.json.simple.JSONArray;
  57. import org.json.simple.JSONObject;
  58. import org.json.simple.JSONValue;
  59. import org.sonar.wsclient.base.HttpException;
  60. import org.sonar.wsclient.issue.Issue;
  61. import org.sonar.wsclient.issue.IssueClient;
  62. import org.sonar.wsclient.issue.IssueQuery;
  63. import org.sonarqube.ws.WsComponents.Component;
  64. import org.sonarqube.ws.WsMeasures;
  65. import org.sonarqube.ws.WsMeasures.Measure;
  66. import org.sonarqube.ws.client.GetRequest;
  67. import org.sonarqube.ws.client.HttpConnector;
  68. import org.sonarqube.ws.client.WsClient;
  69. import org.sonarqube.ws.client.WsClientFactories;
  70. import org.sonarqube.ws.client.component.ShowWsRequest;
  71. import org.sonarqube.ws.client.measure.ComponentWsRequest;
  72. import org.sonarqube.ws.client.organization.OrganizationService;
  73. import org.sonarqube.ws.client.organization.SearchWsRequest;
  74. import org.sonarqube.ws.client.qualityprofile.RestoreWsRequest;
  75. import org.sonarqube.ws.client.setting.ResetRequest;
  76. import org.sonarqube.ws.client.setting.SetRequest;
  77. import static com.google.common.base.Preconditions.checkState;
  78. import static com.sonar.orchestrator.container.Server.ADMIN_LOGIN;
  79. import static com.sonar.orchestrator.container.Server.ADMIN_PASSWORD;
  80. import static java.lang.Double.parseDouble;
  81. import static java.util.Arrays.asList;
  82. import static java.util.Collections.singletonList;
  83. import static java.util.Locale.ENGLISH;
  84. import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
  85. import static org.assertj.core.api.Assertions.assertThat;
  86. import static org.assertj.core.api.Assertions.fail;
  87. public class ItUtils {
  88. public static final Splitter LINE_SPLITTER = Splitter.on(System.getProperty("line.separator"));
  89. private ItUtils() {
  90. }
  91. public static FileLocation xooPlugin() {
  92. return FileLocation.byWildcardMavenFilename(new File("../../plugins/sonar-xoo-plugin/target"), "sonar-xoo-plugin-*.jar");
  93. }
  94. public static List<Issue> getAllServerIssues(Orchestrator orchestrator) {
  95. IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
  96. return issueClient.find(IssueQuery.create()).list();
  97. }
  98. public static WsClient newAdminWsClient(Orchestrator orchestrator) {
  99. return newUserWsClient(orchestrator, ADMIN_LOGIN, ADMIN_PASSWORD);
  100. }
  101. public static WsClient newWsClient(Orchestrator orchestrator) {
  102. return newUserWsClient(orchestrator, null, null);
  103. }
  104. public static WsClient newUserWsClient(Orchestrator orchestrator, @Nullable String login, @Nullable String password) {
  105. Server server = orchestrator.getServer();
  106. return WsClientFactories.getDefault().newClient(HttpConnector.newBuilder()
  107. .url(server.getUrl())
  108. .credentials(login, password)
  109. .build());
  110. }
  111. /**
  112. * Locate the directory of sample project
  113. *
  114. * @param relativePath path related to the directory it/it-projects, for example "qualitygate/xoo-sample"
  115. */
  116. public static File projectDir(String relativePath) {
  117. File dir = new File("../it-projects/" + relativePath);
  118. if (!dir.exists() || !dir.isDirectory()) {
  119. throw new IllegalStateException("Directory does not exist: " + dir.getAbsolutePath());
  120. }
  121. return dir;
  122. }
  123. /**
  124. * Locate the artifact of a fake plugin stored in it/it-plugins.
  125. *
  126. * @param dirName the directory of it/it-plugins, for example "sonar-fake-plugin".
  127. * It assumes that version is 1.0-SNAPSHOT
  128. */
  129. public static FileLocation pluginArtifact(String dirName) {
  130. return FileLocation.byWildcardMavenFilename(new File("../it-plugins/" + dirName + "/target"), dirName + "-*.jar");
  131. }
  132. /**
  133. * Locate the pom file of a sample project
  134. *
  135. * @param projectName project path related to the directory it/it-projects, for example "qualitygate/xoo-sample"
  136. */
  137. public static File projectPom(String projectName) {
  138. File pom = new File(projectDir(projectName), "pom.xml");
  139. if (!pom.exists() || !pom.isFile()) {
  140. throw new IllegalStateException("pom file does not exist: " + pom.getAbsolutePath());
  141. }
  142. return pom;
  143. }
  144. public static String sanitizeTimezones(String s) {
  145. return s.replaceAll("[\\+\\-]\\d\\d\\d\\d", "+0000");
  146. }
  147. public static JSONObject getJSONReport(BuildResult result) {
  148. Pattern pattern = Pattern.compile("Export issues to (.*?).json");
  149. Matcher m = pattern.matcher(result.getLogs());
  150. if (m.find()) {
  151. String s = m.group(1);
  152. File path = new File(s + ".json");
  153. assertThat(path).exists();
  154. try {
  155. return (JSONObject) JSONValue.parse(FileUtils.readFileToString(path));
  156. } catch (IOException e) {
  157. throw new RuntimeException("Unable to read JSON report", e);
  158. }
  159. }
  160. fail("Unable to locate json report");
  161. return null;
  162. }
  163. public static int countIssuesInJsonReport(BuildResult result, boolean onlyNews) {
  164. JSONObject obj = getJSONReport(result);
  165. JSONArray issues = (JSONArray) obj.get("issues");
  166. int count = 0;
  167. for (Object issue : issues) {
  168. JSONObject jsonIssue = (JSONObject) issue;
  169. if (!onlyNews || (Boolean) jsonIssue.get("isNew")) {
  170. count++;
  171. }
  172. }
  173. return count;
  174. }
  175. public static void assertIssuesInJsonReport(BuildResult result, int newIssues, int resolvedIssues, int existingIssues) {
  176. JSONObject obj = getJSONReport(result);
  177. JSONArray issues = (JSONArray) obj.get("issues");
  178. int countNew = 0;
  179. int countResolved = 0;
  180. int countExisting = 0;
  181. for (Object issue : issues) {
  182. JSONObject jsonIssue = (JSONObject) issue;
  183. if ((Boolean) jsonIssue.get("isNew")) {
  184. countNew++;
  185. } else if (jsonIssue.get("resolution") != null) {
  186. countResolved++;
  187. } else {
  188. countExisting++;
  189. }
  190. }
  191. assertThat(countNew).isEqualTo(newIssues);
  192. assertThat(countResolved).isEqualTo(resolvedIssues);
  193. assertThat(countExisting).isEqualTo(existingIssues);
  194. }
  195. public static SonarRunner runVerboseProjectAnalysis(Orchestrator orchestrator, String projectRelativePath, String... properties) {
  196. return runProjectAnalysis(orchestrator, projectRelativePath, true, properties);
  197. }
  198. public static SonarRunner runProjectAnalysis(Orchestrator orchestrator, String projectRelativePath, String... properties) {
  199. return runProjectAnalysis(orchestrator, projectRelativePath, false, properties);
  200. }
  201. private static SonarRunner runProjectAnalysis(Orchestrator orchestrator, String projectRelativePath, boolean enableDebugLogs, String... properties) {
  202. SonarRunner sonarRunner = SonarRunner.create(projectDir(projectRelativePath));
  203. ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
  204. for (int i = 0; i < properties.length; i += 2) {
  205. builder.put(properties[i], properties[i + 1]);
  206. }
  207. SonarRunner scan = sonarRunner.setDebugLogs(enableDebugLogs).setProperties(builder.build());
  208. orchestrator.executeBuild(scan);
  209. return scan;
  210. }
  211. public static void setServerProperty(Orchestrator orchestrator, String key, @Nullable String value) {
  212. setServerProperty(orchestrator, null, key, value);
  213. }
  214. public static void setServerProperty(Orchestrator orchestrator, @Nullable String componentKey, String key, @Nullable String value) {
  215. if (value == null) {
  216. newAdminWsClient(orchestrator).settingsService().reset(ResetRequest.builder().setKeys(key).setComponent(componentKey).build());
  217. } else {
  218. newAdminWsClient(orchestrator).settingsService().set(SetRequest.builder().setKey(key).setValue(value).setComponent(componentKey).build());
  219. }
  220. }
  221. public static void setServerProperties(Orchestrator orchestrator, @Nullable String componentKey, String... properties) {
  222. for (int i = 0; i < properties.length; i += 2) {
  223. setServerProperty(orchestrator, componentKey, properties[i], properties[i + 1]);
  224. }
  225. }
  226. public static void resetSettings(Orchestrator orchestrator, @Nullable String componentKey, String... keys) {
  227. if (keys.length > 0) {
  228. newAdminWsClient(orchestrator).settingsService().reset(ResetRequest.builder().setKeys(keys).setComponent(componentKey).build());
  229. }
  230. }
  231. public static void resetEmailSettings(Orchestrator orchestrator) {
  232. resetSettings(orchestrator, null, "email.smtp_host.secured", "email.smtp_port.secured", "email.smtp_secure_connection.secured", "email.smtp_username.secured",
  233. "email.smtp_password.secured", "email.from", "email.prefix");
  234. }
  235. public static void resetPeriod(Orchestrator orchestrator) {
  236. resetSettings(orchestrator, null, "sonar.leak.period");
  237. }
  238. @CheckForNull
  239. public static Measure getMeasure(Orchestrator orchestrator, String componentKey, String metricKey) {
  240. return getMeasuresByMetricKey(orchestrator, componentKey, metricKey).get(metricKey);
  241. }
  242. @CheckForNull
  243. public static Double getMeasureAsDouble(Orchestrator orchestrator, String componentKey, String metricKey) {
  244. Measure measure = getMeasure(orchestrator, componentKey, metricKey);
  245. return (measure == null) ? null : Double.parseDouble(measure.getValue());
  246. }
  247. public static Map<String, Measure> getMeasuresByMetricKey(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  248. return getStreamMeasures(orchestrator, componentKey, metricKeys)
  249. .filter(Measure::hasValue)
  250. .collect(Collectors.toMap(Measure::getMetric, Function.identity()));
  251. }
  252. public static Map<String, Double> getMeasuresAsDoubleByMetricKey(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  253. return getStreamMeasures(orchestrator, componentKey, metricKeys)
  254. .filter(Measure::hasValue)
  255. .collect(Collectors.toMap(Measure::getMetric, measure -> parseDouble(measure.getValue())));
  256. }
  257. private static Stream<Measure> getStreamMeasures(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  258. return newWsClient(orchestrator).measures().component(new ComponentWsRequest()
  259. .setComponentKey(componentKey)
  260. .setMetricKeys(asList(metricKeys)))
  261. .getComponent().getMeasuresList()
  262. .stream();
  263. }
  264. @CheckForNull
  265. public static Measure getMeasureWithVariation(Orchestrator orchestrator, String componentKey, String metricKey) {
  266. WsMeasures.ComponentWsResponse response = newWsClient(orchestrator).measures().component(new ComponentWsRequest()
  267. .setComponentKey(componentKey)
  268. .setMetricKeys(singletonList(metricKey))
  269. .setAdditionalFields(singletonList("periods")));
  270. List<Measure> measures = response.getComponent().getMeasuresList();
  271. return measures.size() == 1 ? measures.get(0) : null;
  272. }
  273. @CheckForNull
  274. public static Map<String, Measure> getMeasuresWithVariationsByMetricKey(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  275. return newWsClient(orchestrator).measures().component(new ComponentWsRequest()
  276. .setComponentKey(componentKey)
  277. .setMetricKeys(asList(metricKeys))
  278. .setAdditionalFields(singletonList("periods"))).getComponent().getMeasuresList()
  279. .stream()
  280. .collect(Collectors.toMap(Measure::getMetric, Function.identity()));
  281. }
  282. /**
  283. * Return leak period value
  284. */
  285. @CheckForNull
  286. public static Double getLeakPeriodValue(Orchestrator orchestrator, String componentKey, String metricKey) {
  287. List<WsMeasures.PeriodValue> periodsValueList = getMeasureWithVariation(orchestrator, componentKey, metricKey).getPeriods().getPeriodsValueList();
  288. return periodsValueList.size() > 0 ? Double.parseDouble(periodsValueList.get(0).getValue()) : null;
  289. }
  290. @CheckForNull
  291. public static Component getComponent(Orchestrator orchestrator, String componentKey) {
  292. try {
  293. return newWsClient(orchestrator).components().show(new ShowWsRequest().setKey((componentKey))).getComponent();
  294. } catch (org.sonarqube.ws.client.HttpException e) {
  295. if (e.code() == 404) {
  296. return null;
  297. }
  298. throw new IllegalStateException(e);
  299. }
  300. }
  301. @CheckForNull
  302. public static ComponentNavigation getComponentNavigation(Orchestrator orchestrator, String componentKey) {
  303. // Waiting for SONAR-7745 to have version in api/components/show, we use internal api/navigation/component WS to get the component
  304. // version
  305. String content = newWsClient(orchestrator).wsConnector().call(new GetRequest("api/navigation/component").setParam("componentKey", componentKey)).failIfNotSuccessful()
  306. .content();
  307. return ComponentNavigation.parse(content);
  308. }
  309. public static void restoreProfile(Orchestrator orchestrator, URL resource) {
  310. restoreProfile(orchestrator, resource, null);
  311. }
  312. public static void restoreProfile(Orchestrator orchestrator, URL resource, String organization) {
  313. URI uri;
  314. try {
  315. uri = resource.toURI();
  316. } catch (URISyntaxException e) {
  317. throw new IllegalArgumentException("Cannot find quality profile xml file '" + resource + "' in classpath");
  318. }
  319. newAdminWsClient(orchestrator)
  320. .qualityProfiles()
  321. .restoreProfile(
  322. RestoreWsRequest.builder()
  323. .setBackup(new File(uri))
  324. .setOrganization(organization)
  325. .build());
  326. }
  327. public static String newOrganizationKey() {
  328. return randomAlphabetic(32).toLowerCase(ENGLISH);
  329. }
  330. public static void deleteOrganizationsIfExists(Orchestrator orchestrator, String... organizationKeys) {
  331. OrganizationService adminOrganizationService = newAdminWsClient(orchestrator).organizations();
  332. adminOrganizationService.search(SearchWsRequest.builder().setOrganizations(organizationKeys).build()).getOrganizationsList()
  333. .forEach(organization -> adminOrganizationService.delete(organization.getKey()));
  334. }
  335. public static class ComponentNavigation {
  336. private String version;
  337. private String snapshotDate;
  338. public String getVersion() {
  339. return version;
  340. }
  341. public Date getDate() {
  342. return toDatetime(snapshotDate);
  343. }
  344. public static ComponentNavigation parse(String json) {
  345. Gson gson = new Gson();
  346. return gson.fromJson(json, ComponentNavigation.class);
  347. }
  348. }
  349. /**
  350. * Concatenates a vararg to a String array.
  351. *
  352. * Useful when using {@link #runVerboseProjectAnalysis(Orchestrator, String, String...)}, eg.:
  353. * <pre>
  354. * ItUtils.runProjectAnalysis(orchestrator, "project_name",
  355. * ItUtils.concat(properties, "sonar.scm.disabled", "false")
  356. * );
  357. * </pre>
  358. */
  359. public static String[] concat(String[] properties, String... str) {
  360. if (properties == null || properties.length == 0) {
  361. return str;
  362. }
  363. return Stream.concat(Arrays.stream(properties), Arrays.stream(str))
  364. .toArray(String[]::new);
  365. }
  366. public static void verifyHttpException(Exception e, int expectedCode) {
  367. assertThat(e).isInstanceOf(HttpException.class);
  368. HttpException exception = (HttpException) e;
  369. assertThat(exception.status()).isEqualTo(expectedCode);
  370. }
  371. public static Date toDate(String sDate) {
  372. try {
  373. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  374. return sdf.parse(sDate);
  375. } catch (ParseException e) {
  376. throw new RuntimeException(e);
  377. }
  378. }
  379. public static Date toDatetime(String sDate) {
  380. try {
  381. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
  382. return sdf.parse(sDate);
  383. } catch (ParseException e) {
  384. throw new RuntimeException(e);
  385. }
  386. }
  387. public static String formatDate(Date d) {
  388. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  389. return sdf.format(d);
  390. }
  391. public static String extractCeTaskId(BuildResult buildResult) {
  392. List<String> taskIds = extractCeTaskIds(buildResult);
  393. checkState(taskIds.size() == 1, "More than one task id retrieved from logs");
  394. return taskIds.iterator().next();
  395. }
  396. public static List<String> extractCeTaskIds(BuildResult buildResult) {
  397. String logs = buildResult.getLogs();
  398. return StreamSupport.stream(LINE_SPLITTER.split(logs).spliterator(), false)
  399. .filter(s -> s.contains("More about the report processing at"))
  400. .map(s -> s.substring(s.length() - 20, s.length()))
  401. .collect(Collectors.toList());
  402. }
  403. public static Map<String, Object> jsonToMap(String json) {
  404. Gson gson = new Gson();
  405. Type type = new TypeToken<Map<String, Object>>() {
  406. }.getType();
  407. return gson.fromJson(json, type);
  408. }
  409. public static Response call(String url, String... headers) {
  410. Request.Builder requestBuilder = new Request.Builder().get().url(url);
  411. for (int i = 0; i < headers.length; i += 2) {
  412. String headerName = headers[i];
  413. String headerValue = headers[i + 1];
  414. if (headerValue != null) {
  415. requestBuilder.addHeader(headerName, headerValue);
  416. }
  417. }
  418. try {
  419. return new OkHttpClient.Builder()
  420. .connectTimeout(30, TimeUnit.SECONDS)
  421. .readTimeout(30, TimeUnit.SECONDS)
  422. .build()
  423. .newCall(requestBuilder.build())
  424. .execute();
  425. } catch (IOException e) {
  426. throw Throwables.propagate(e);
  427. }
  428. }
  429. }