You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ItUtils.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2018 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.OrchestratorBuilder;
  28. import com.sonar.orchestrator.build.BuildResult;
  29. import com.sonar.orchestrator.build.SonarScanner;
  30. import com.sonar.orchestrator.container.Server;
  31. import com.sonar.orchestrator.locator.FileLocation;
  32. import java.io.File;
  33. import java.io.IOException;
  34. import java.lang.reflect.Type;
  35. import java.net.URI;
  36. import java.net.URISyntaxException;
  37. import java.net.URL;
  38. import java.text.ParseException;
  39. import java.text.SimpleDateFormat;
  40. import java.util.Arrays;
  41. import java.util.Date;
  42. import java.util.List;
  43. import java.util.Map;
  44. import java.util.concurrent.TimeUnit;
  45. import java.util.function.Function;
  46. import java.util.regex.Matcher;
  47. import java.util.regex.Pattern;
  48. import java.util.stream.Collectors;
  49. import java.util.stream.Stream;
  50. import java.util.stream.StreamSupport;
  51. import javax.annotation.CheckForNull;
  52. import javax.annotation.Nullable;
  53. import okhttp3.OkHttpClient;
  54. import okhttp3.Request;
  55. import okhttp3.Response;
  56. import org.apache.commons.io.FileUtils;
  57. import org.apache.commons.lang.StringUtils;
  58. import org.json.simple.JSONArray;
  59. import org.json.simple.JSONObject;
  60. import org.json.simple.JSONValue;
  61. import org.junit.Assert;
  62. import org.sonar.wsclient.issue.Issue;
  63. import org.sonar.wsclient.issue.IssueClient;
  64. import org.sonar.wsclient.issue.IssueQuery;
  65. import org.sonarqube.qa.util.SettingTester;
  66. import org.sonarqube.qa.util.Tester;
  67. import org.sonarqube.ws.Components.Component;
  68. import org.sonarqube.ws.Measures;
  69. import org.sonarqube.ws.Measures.Measure;
  70. import org.sonarqube.ws.MediaTypes;
  71. import org.sonarqube.ws.client.GetRequest;
  72. import org.sonarqube.ws.client.HttpConnector;
  73. import org.sonarqube.ws.client.PostRequest;
  74. import org.sonarqube.ws.client.WsClient;
  75. import org.sonarqube.ws.client.WsClientFactories;
  76. import org.sonarqube.ws.client.components.ShowRequest;
  77. import org.sonarqube.ws.client.measures.ComponentRequest;
  78. import org.sonarqube.ws.client.settings.ResetRequest;
  79. import org.sonarqube.ws.client.settings.SetRequest;
  80. import static com.google.common.base.Preconditions.checkState;
  81. import static com.sonar.orchestrator.container.Edition.COMMUNITY;
  82. import static com.sonar.orchestrator.container.Server.ADMIN_LOGIN;
  83. import static com.sonar.orchestrator.container.Server.ADMIN_PASSWORD;
  84. import static java.lang.Double.parseDouble;
  85. import static java.util.Arrays.asList;
  86. import static java.util.Collections.singletonList;
  87. import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
  88. import static org.assertj.core.api.Assertions.assertThat;
  89. import static org.assertj.core.api.Assertions.fail;
  90. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION;
  91. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.RestoreActionParameters.PARAM_BACKUP;
  92. public class ItUtils {
  93. public static final Splitter LINE_SPLITTER = Splitter.on(System.getProperty("line.separator"));
  94. private ItUtils() {
  95. }
  96. public static OrchestratorBuilder newOrchestratorBuilder() {
  97. OrchestratorBuilder builder = Orchestrator.builderEnv();
  98. builder.setEdition(COMMUNITY);
  99. String version = System.getProperty("sonar.runtimeVersion");
  100. if (StringUtils.isEmpty(version)) {
  101. File zip = FileLocation.byWildcardMavenFilename(new File("../sonar-application/build/distributions"), "sonar-application-*.zip").getFile();
  102. builder.setZipFile(zip);
  103. } else {
  104. builder.setSonarVersion(version);
  105. }
  106. return builder
  107. // reduce memory for Elasticsearch
  108. .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m")
  109. .setOrchestratorProperty("orchestrator.workspaceDir", "build/it");
  110. }
  111. public static FileLocation xooPlugin() {
  112. return FileLocation.byWildcardMavenFilename(new File("../plugins/sonar-xoo-plugin/build/libs"), "sonar-xoo-plugin-*.jar");
  113. }
  114. public static List<Issue> getAllServerIssues(Orchestrator orchestrator) {
  115. IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
  116. return issueClient.find(IssueQuery.create()).list();
  117. }
  118. /**
  119. * @deprecated replaced by {@link Tester#wsClient()}
  120. */
  121. @Deprecated
  122. public static WsClient newAdminWsClient(Orchestrator orchestrator) {
  123. return newUserWsClient(orchestrator, ADMIN_LOGIN, ADMIN_PASSWORD);
  124. }
  125. /**
  126. * @deprecated replaced by {@link Tester#wsClient()}
  127. */
  128. @Deprecated
  129. public static WsClient newWsClient(Orchestrator orchestrator) {
  130. return newUserWsClient(orchestrator, null, null);
  131. }
  132. /**
  133. * @deprecated replaced by {@link Tester#wsClient()}
  134. */
  135. @Deprecated
  136. public static WsClient newUserWsClient(Orchestrator orchestrator, @Nullable String login, @Nullable String password) {
  137. Server server = orchestrator.getServer();
  138. return WsClientFactories.getDefault().newClient(HttpConnector.newBuilder()
  139. .url(server.getUrl())
  140. .credentials(login, password)
  141. .build());
  142. }
  143. /**
  144. * @deprecated replaced by {@link Tester#wsClient()}
  145. */
  146. @Deprecated
  147. public static WsClient newSystemUserWsClient(Orchestrator orchestrator, @Nullable String systemPassCode) {
  148. Server server = orchestrator.getServer();
  149. return WsClientFactories.getDefault().newClient(HttpConnector.newBuilder()
  150. .url(server.getUrl())
  151. .systemPassCode(systemPassCode)
  152. .build());
  153. }
  154. /**
  155. * Locate the directory of sample project
  156. *
  157. * @param relativePath path related to the directory it/projects, for example "qualitygate/xoo-sample"
  158. */
  159. public static File projectDir(String relativePath) {
  160. File dir = new File("projects/" + relativePath);
  161. if (!dir.exists() || !dir.isDirectory()) {
  162. throw new IllegalStateException("Directory does not exist: " + dir.getAbsolutePath());
  163. }
  164. return dir;
  165. }
  166. /**
  167. * Locate the artifact of a fake plugin stored in it/plugins.
  168. *
  169. * @param dirName the directory of it/plugins, for example "sonar-fake-plugin".
  170. */
  171. public static FileLocation pluginArtifact(String dirName) {
  172. return FileLocation.byWildcardMavenFilename(new File("plugins/" + dirName + "/build/libs"), dirName + "-*.jar");
  173. }
  174. /**
  175. * Locate the pom file of a sample project
  176. *
  177. * @param projectName project path related to the directory it/projects, for example "qualitygate/xoo-sample"
  178. */
  179. public static File projectPom(String projectName) {
  180. File pom = new File(projectDir(projectName), "pom.xml");
  181. if (!pom.exists() || !pom.isFile()) {
  182. throw new IllegalStateException("pom file does not exist: " + pom.getAbsolutePath());
  183. }
  184. return pom;
  185. }
  186. public static String sanitizeTimezones(String s) {
  187. return s.replaceAll("[\\+\\-]\\d\\d\\d\\d", "+0000");
  188. }
  189. public static JSONObject getJSONReport(BuildResult result) {
  190. Pattern pattern = Pattern.compile("Export issues to (.*?).json");
  191. Matcher m = pattern.matcher(result.getLogs());
  192. if (m.find()) {
  193. String s = m.group(1);
  194. File path = new File(s + ".json");
  195. assertThat(path).exists();
  196. try {
  197. return (JSONObject) JSONValue.parse(FileUtils.readFileToString(path));
  198. } catch (IOException e) {
  199. throw new RuntimeException("Unable to read JSON report", e);
  200. }
  201. }
  202. fail("Unable to locate json report");
  203. return null;
  204. }
  205. public static int countIssuesInJsonReport(BuildResult result, boolean onlyNews) {
  206. JSONObject obj = getJSONReport(result);
  207. JSONArray issues = (JSONArray) obj.get("issues");
  208. int count = 0;
  209. for (Object issue : issues) {
  210. JSONObject jsonIssue = (JSONObject) issue;
  211. if (!onlyNews || (Boolean) jsonIssue.get("isNew")) {
  212. count++;
  213. }
  214. }
  215. return count;
  216. }
  217. public static void assertIssuesInJsonReport(BuildResult result, int newIssues, int resolvedIssues, int existingIssues) {
  218. JSONObject obj = getJSONReport(result);
  219. JSONArray issues = (JSONArray) obj.get("issues");
  220. int countNew = 0;
  221. int countResolved = 0;
  222. int countExisting = 0;
  223. for (Object issue : issues) {
  224. JSONObject jsonIssue = (JSONObject) issue;
  225. if ((Boolean) jsonIssue.get("isNew")) {
  226. countNew++;
  227. } else if (jsonIssue.get("resolution") != null) {
  228. countResolved++;
  229. } else {
  230. countExisting++;
  231. }
  232. }
  233. assertThat(countNew).isEqualTo(newIssues);
  234. assertThat(countResolved).isEqualTo(resolvedIssues);
  235. assertThat(countExisting).isEqualTo(existingIssues);
  236. }
  237. public static SonarScanner runVerboseProjectAnalysis(Orchestrator orchestrator, String projectRelativePath, String... properties) {
  238. return runProjectAnalysis(orchestrator, projectRelativePath, true, properties);
  239. }
  240. public static SonarScanner runProjectAnalysis(Orchestrator orchestrator, String projectRelativePath, String... properties) {
  241. return runProjectAnalysis(orchestrator, projectRelativePath, false, properties);
  242. }
  243. private static SonarScanner runProjectAnalysis(Orchestrator orchestrator, String projectRelativePath, boolean enableDebugLogs, String... properties) {
  244. SonarScanner sonarScanner = SonarScanner.create(projectDir(projectRelativePath));
  245. ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
  246. for (int i = 0; i < properties.length; i += 2) {
  247. builder.put(properties[i], properties[i + 1]);
  248. }
  249. SonarScanner scan = sonarScanner.setDebugLogs(enableDebugLogs).setProperties(builder.build());
  250. orchestrator.executeBuild(scan);
  251. return scan;
  252. }
  253. /**
  254. * @deprecated replaced by {@link SettingTester#setGlobalSetting(String, String)}
  255. */
  256. @Deprecated
  257. public static void setServerProperty(Orchestrator orchestrator, String key, @Nullable String value) {
  258. setServerProperty(orchestrator, null, key, value);
  259. }
  260. /**
  261. * @deprecated replaced by {@link SettingTester#setProjectSetting(String, String, String)}
  262. */
  263. @Deprecated
  264. public static void setServerProperty(Orchestrator orchestrator, @Nullable String componentKey, String key, @Nullable String value) {
  265. if (value == null) {
  266. newAdminWsClient(orchestrator).settings().reset(new ResetRequest().setKeys(asList(key)).setComponent(componentKey));
  267. } else {
  268. newAdminWsClient(orchestrator).settings().set(new SetRequest().setKey(key).setValue(value).setComponent(componentKey));
  269. }
  270. }
  271. /**
  272. * @deprecated replaced by {@link SettingTester#setGlobalSetting(String, String)} or {@link SettingTester#setProjectSettings(String, String...)}
  273. */
  274. @Deprecated
  275. public static void setServerProperties(Orchestrator orchestrator, @Nullable String componentKey, String... properties) {
  276. for (int i = 0; i < properties.length; i += 2) {
  277. setServerProperty(orchestrator, componentKey, properties[i], properties[i + 1]);
  278. }
  279. }
  280. /**
  281. * @deprecated replaced by {@link SettingTester#resetSettings(String...)}
  282. */
  283. @Deprecated
  284. public static void resetSettings(Orchestrator orchestrator, @Nullable String componentKey, String... keys) {
  285. if (keys.length > 0) {
  286. newAdminWsClient(orchestrator).settings().reset(new ResetRequest().setKeys(Arrays.asList(keys)).setComponent(componentKey));
  287. }
  288. }
  289. /**
  290. * @deprecated no more needed as already done by {@link Tester#after()}
  291. */
  292. @Deprecated
  293. public static void resetEmailSettings(Orchestrator orchestrator) {
  294. resetSettings(orchestrator, null, "email.smtp_host.secured", "email.smtp_port.secured", "email.smtp_secure_connection.secured", "email.smtp_username.secured",
  295. "email.smtp_password.secured", "email.from", "email.prefix");
  296. }
  297. /**
  298. * @deprecated no more needed as already done by {@link Tester#after()}
  299. */
  300. @Deprecated
  301. public static void resetPeriod(Orchestrator orchestrator) {
  302. resetSettings(orchestrator, null, "sonar.leak.period");
  303. }
  304. @CheckForNull
  305. public static Measure getMeasure(Orchestrator orchestrator, String componentKey, String metricKey) {
  306. return getMeasuresByMetricKey(orchestrator, componentKey, metricKey).get(metricKey);
  307. }
  308. @CheckForNull
  309. public static Double getMeasureAsDouble(Orchestrator orchestrator, String componentKey, String metricKey) {
  310. Measure measure = getMeasure(orchestrator, componentKey, metricKey);
  311. return (measure == null) ? null : Double.parseDouble(measure.getValue());
  312. }
  313. public static Map<String, Measure> getMeasuresByMetricKey(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  314. return getStreamMeasures(orchestrator, componentKey, metricKeys)
  315. .filter(Measure::hasValue)
  316. .collect(Collectors.toMap(Measure::getMetric, Function.identity()));
  317. }
  318. public static Map<String, Double> getMeasuresAsDoubleByMetricKey(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  319. return getStreamMeasures(orchestrator, componentKey, metricKeys)
  320. .filter(Measure::hasValue)
  321. .collect(Collectors.toMap(Measure::getMetric, measure -> parseDouble(measure.getValue())));
  322. }
  323. private static Stream<Measure> getStreamMeasures(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  324. return newWsClient(orchestrator).measures().component(new ComponentRequest()
  325. .setComponent(componentKey)
  326. .setMetricKeys(asList(metricKeys)))
  327. .getComponent().getMeasuresList()
  328. .stream();
  329. }
  330. @CheckForNull
  331. public static Measure getMeasureWithVariation(Orchestrator orchestrator, String componentKey, String metricKey) {
  332. Measures.ComponentWsResponse response = newWsClient(orchestrator).measures().component(new ComponentRequest()
  333. .setComponent(componentKey)
  334. .setMetricKeys(singletonList(metricKey))
  335. .setAdditionalFields(singletonList("periods")));
  336. List<Measure> measures = response.getComponent().getMeasuresList();
  337. return measures.size() == 1 ? measures.get(0) : null;
  338. }
  339. @CheckForNull
  340. public static Map<String, Measure> getMeasuresWithVariationsByMetricKey(Orchestrator orchestrator, String componentKey, String... metricKeys) {
  341. return newWsClient(orchestrator).measures().component(new ComponentRequest()
  342. .setComponent(componentKey)
  343. .setMetricKeys(asList(metricKeys))
  344. .setAdditionalFields(singletonList("periods"))).getComponent().getMeasuresList()
  345. .stream()
  346. .collect(Collectors.toMap(Measure::getMetric, Function.identity()));
  347. }
  348. /**
  349. * Return leak period value
  350. */
  351. @CheckForNull
  352. public static Double getLeakPeriodValue(Orchestrator orchestrator, String componentKey, String metricKey) {
  353. List<Measures.PeriodValue> periodsValueList = getMeasureWithVariation(orchestrator, componentKey, metricKey).getPeriods().getPeriodsValueList();
  354. return periodsValueList.size() > 0 ? Double.parseDouble(periodsValueList.get(0).getValue()) : null;
  355. }
  356. @CheckForNull
  357. public static Component getComponent(Orchestrator orchestrator, String componentKey) {
  358. try {
  359. return newWsClient(orchestrator).components().show(new ShowRequest().setComponent((componentKey))).getComponent();
  360. } catch (org.sonarqube.ws.client.HttpException e) {
  361. if (e.code() == 404) {
  362. return null;
  363. }
  364. throw new IllegalStateException(e);
  365. }
  366. }
  367. @CheckForNull
  368. public static ComponentNavigation getComponentNavigation(Orchestrator orchestrator, String componentKey) {
  369. // Waiting for SONAR-7745 to have version in api/components/show, we use internal api/navigation/component WS to get the component
  370. // version
  371. String content = newWsClient(orchestrator).wsConnector().call(new GetRequest("api/navigation/component").setParam("componentKey", componentKey)).failIfNotSuccessful()
  372. .content();
  373. return ComponentNavigation.parse(content);
  374. }
  375. public static void restoreProfile(Orchestrator orchestrator, URL resource) {
  376. restoreProfile(orchestrator, resource, null);
  377. }
  378. public static void restoreProfile(Orchestrator orchestrator, URL resource, String organization) {
  379. URI uri;
  380. try {
  381. uri = resource.toURI();
  382. } catch (URISyntaxException e) {
  383. throw new IllegalArgumentException("Cannot find quality profile xml file '" + resource + "' in classpath");
  384. }
  385. PostRequest httpRequest = new PostRequest("api/qualityprofiles/restore")
  386. .setParam(PARAM_ORGANIZATION, organization)
  387. .setPart(PARAM_BACKUP, new PostRequest.Part(MediaTypes.XML, new File(uri)));
  388. HttpConnector.newBuilder()
  389. .url(orchestrator.getServer().getUrl())
  390. .credentials(ADMIN_LOGIN, ADMIN_PASSWORD)
  391. .build().call(httpRequest);
  392. }
  393. public static String newProjectKey() {
  394. return "key-" + randomAlphabetic(100);
  395. }
  396. public static class ComponentNavigation {
  397. private String version;
  398. private String analysisDate;
  399. public String getVersion() {
  400. return version;
  401. }
  402. public Date getDate() {
  403. return toDatetime(analysisDate);
  404. }
  405. public static ComponentNavigation parse(String json) {
  406. Gson gson = new Gson();
  407. return gson.fromJson(json, ComponentNavigation.class);
  408. }
  409. }
  410. /**
  411. * Concatenates a vararg to a String array.
  412. *
  413. * Useful when using {@link #runVerboseProjectAnalysis(Orchestrator, String, String...)}, eg.:
  414. * <pre>
  415. * ItUtils.runProjectAnalysis(orchestrator, "project_name",
  416. * ItUtils.concat(properties, "sonar.scm.disabled", "false")
  417. * );
  418. * </pre>
  419. */
  420. public static String[] concat(String[] properties, String... str) {
  421. if (properties == null || properties.length == 0) {
  422. return str;
  423. }
  424. return Stream.concat(Arrays.stream(properties), Arrays.stream(str))
  425. .toArray(String[]::new);
  426. }
  427. public static Date toDate(String sDate) {
  428. try {
  429. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  430. return sdf.parse(sDate);
  431. } catch (ParseException e) {
  432. throw new RuntimeException(e);
  433. }
  434. }
  435. public static Date toDatetime(String sDate) {
  436. try {
  437. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
  438. return sdf.parse(sDate);
  439. } catch (ParseException e) {
  440. throw new RuntimeException(e);
  441. }
  442. }
  443. public static String formatDate(Date d) {
  444. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  445. return sdf.format(d);
  446. }
  447. public static String extractCeTaskId(BuildResult buildResult) {
  448. List<String> taskIds = extractCeTaskIds(buildResult);
  449. checkState(taskIds.size() == 1, "More than one task id retrieved from logs");
  450. return taskIds.iterator().next();
  451. }
  452. private static List<String> extractCeTaskIds(BuildResult buildResult) {
  453. String logs = buildResult.getLogs();
  454. return StreamSupport.stream(LINE_SPLITTER.split(logs).spliterator(), false)
  455. .filter(s -> s.contains("More about the report processing at"))
  456. .map(s -> s.substring(s.length() - 20, s.length()))
  457. .collect(Collectors.toList());
  458. }
  459. public static Map<String, Object> jsonToMap(String json) {
  460. Gson gson = new Gson();
  461. Type type = new TypeToken<Map<String, Object>>() {
  462. }.getType();
  463. return gson.fromJson(json, type);
  464. }
  465. /**
  466. * @deprecated replaced by {@code orchestrator.getServer().newHttpCall()}
  467. */
  468. @Deprecated
  469. public static Response call(String url, String... headers) {
  470. Request.Builder requestBuilder = new Request.Builder().get().url(url);
  471. for (int i = 0; i < headers.length; i += 2) {
  472. String headerName = headers[i];
  473. String headerValue = headers[i + 1];
  474. if (headerValue != null) {
  475. requestBuilder.addHeader(headerName, headerValue);
  476. }
  477. }
  478. try {
  479. return new OkHttpClient.Builder()
  480. .connectTimeout(30, TimeUnit.SECONDS)
  481. .readTimeout(30, TimeUnit.SECONDS)
  482. .build()
  483. .newCall(requestBuilder.build())
  484. .execute();
  485. } catch (IOException e) {
  486. throw Throwables.propagate(e);
  487. }
  488. }
  489. public static void expectBadRequestError(Runnable runnable) {
  490. expectHttpError(400, runnable);
  491. }
  492. public static void expectMissingError(Runnable runnable) {
  493. expectHttpError(404, runnable);
  494. }
  495. /**
  496. * Missing permissions
  497. */
  498. public static void expectForbiddenError(Runnable runnable) {
  499. expectHttpError(403, runnable);
  500. }
  501. /**
  502. * Not authenticated
  503. */
  504. public static void expectUnauthorizedError(Runnable runnable) {
  505. expectHttpError(401, runnable);
  506. }
  507. public static void expectNotFoundError(Runnable runnable) {
  508. expectHttpError(404, runnable);
  509. }
  510. public static void expectHttpError(int expectedCode, Runnable runnable) {
  511. try {
  512. runnable.run();
  513. Assert.fail("Ws call should have failed");
  514. } catch (org.sonarqube.ws.client.HttpException e) {
  515. assertThat(e.code()).isEqualTo(expectedCode);
  516. }
  517. }
  518. public static void expectHttpError(int expectedCode, String expectedMessage, Runnable runnable) {
  519. try {
  520. runnable.run();
  521. Assert.fail("Ws call should have failed");
  522. } catch (org.sonarqube.ws.client.HttpException e) {
  523. assertThat(e.code()).isEqualTo(expectedCode);
  524. assertThat(e.getMessage()).contains(expectedMessage);
  525. }
  526. }
  527. }