Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

BitbucketServerRestClientTest.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 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 org.sonar.alm.client.bitbucketserver;
  21. import java.io.IOException;
  22. import java.util.function.Function;
  23. import com.tngtech.java.junit.dataprovider.DataProvider;
  24. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  25. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  26. import okhttp3.MediaType;
  27. import okhttp3.mockwebserver.MockResponse;
  28. import okhttp3.mockwebserver.MockWebServer;
  29. import okhttp3.mockwebserver.SocketPolicy;
  30. import okio.Buffer;
  31. import org.junit.After;
  32. import org.junit.Before;
  33. import org.junit.Rule;
  34. import org.junit.Test;
  35. import org.junit.runner.RunWith;
  36. import org.sonar.alm.client.ConstantTimeoutConfiguration;
  37. import org.sonar.api.testfixtures.log.LogTester;
  38. import static org.assertj.core.api.Assertions.assertThat;
  39. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  40. import static org.assertj.core.api.Assertions.tuple;
  41. @RunWith(DataProviderRunner.class)
  42. public class BitbucketServerRestClientTest {
  43. private final MockWebServer server = new MockWebServer();
  44. private static final String REPOS_BODY = "{\n" +
  45. " \"isLastPage\": true,\n" +
  46. " \"values\": [\n" +
  47. " {\n" +
  48. " \"slug\": \"banana\",\n" +
  49. " \"id\": 2,\n" +
  50. " \"name\": \"banana\",\n" +
  51. " \"project\": {\n" +
  52. " \"key\": \"HOY\",\n" +
  53. " \"id\": 2,\n" +
  54. " \"name\": \"hoy\"\n" +
  55. " }\n" +
  56. " },\n" +
  57. " {\n" +
  58. " \"slug\": \"potato\",\n" +
  59. " \"id\": 1,\n" +
  60. " \"name\": \"potato\",\n" +
  61. " \"project\": {\n" +
  62. " \"key\": \"HEY\",\n" +
  63. " \"id\": 1,\n" +
  64. " \"name\": \"hey\"\n" +
  65. " }\n" +
  66. " }\n" +
  67. " ]\n" +
  68. "}";
  69. @Rule
  70. public LogTester logTester = new LogTester();
  71. private BitbucketServerRestClient underTest;
  72. @Before
  73. public void prepare() throws IOException {
  74. server.start();
  75. underTest = new BitbucketServerRestClient(new ConstantTimeoutConfiguration(500));
  76. }
  77. @After
  78. public void stopServer() throws IOException {
  79. server.shutdown();
  80. }
  81. @Test
  82. public void get_repos() {
  83. server.enqueue(new MockResponse()
  84. .setHeader("Content-Type", "application/json;charset=UTF-8")
  85. .setBody("{\n" +
  86. " \"isLastPage\": true,\n" +
  87. " \"values\": [\n" +
  88. " {\n" +
  89. " \"slug\": \"banana\",\n" +
  90. " \"id\": 2,\n" +
  91. " \"name\": \"banana\",\n" +
  92. " \"project\": {\n" +
  93. " \"key\": \"HOY\",\n" +
  94. " \"id\": 2,\n" +
  95. " \"name\": \"hoy\"\n" +
  96. " }\n" +
  97. " },\n" +
  98. " {\n" +
  99. " \"slug\": \"potato\",\n" +
  100. " \"id\": 1,\n" +
  101. " \"name\": \"potato\",\n" +
  102. " \"project\": {\n" +
  103. " \"key\": \"HEY\",\n" +
  104. " \"id\": 1,\n" +
  105. " \"name\": \"hey\"\n" +
  106. " }\n" +
  107. " }\n" +
  108. " ]\n" +
  109. "}"));
  110. RepositoryList gsonBBSRepoList = underTest.getRepos(server.url("/").toString(), "token", "", "");
  111. assertThat(gsonBBSRepoList.isLastPage()).isTrue();
  112. assertThat(gsonBBSRepoList.getValues()).hasSize(2);
  113. assertThat(gsonBBSRepoList.getValues()).extracting(Repository::getId, Repository::getName, Repository::getSlug,
  114. g -> g.getProject().getId(), g -> g.getProject().getKey(), g -> g.getProject().getName())
  115. .containsExactlyInAnyOrder(
  116. tuple(2L, "banana", "banana", 2L, "HOY", "hoy"),
  117. tuple(1L, "potato", "potato", 1L, "HEY", "hey"));
  118. }
  119. @Test
  120. public void get_recent_repos() {
  121. server.enqueue(new MockResponse()
  122. .setHeader("Content-Type", "application/json;charset=UTF-8")
  123. .setBody("{\n" +
  124. " \"isLastPage\": true,\n" +
  125. " \"values\": [\n" +
  126. " {\n" +
  127. " \"slug\": \"banana\",\n" +
  128. " \"id\": 2,\n" +
  129. " \"name\": \"banana\",\n" +
  130. " \"project\": {\n" +
  131. " \"key\": \"HOY\",\n" +
  132. " \"id\": 2,\n" +
  133. " \"name\": \"hoy\"\n" +
  134. " }\n" +
  135. " },\n" +
  136. " {\n" +
  137. " \"slug\": \"potato\",\n" +
  138. " \"id\": 1,\n" +
  139. " \"name\": \"potato\",\n" +
  140. " \"project\": {\n" +
  141. " \"key\": \"HEY\",\n" +
  142. " \"id\": 1,\n" +
  143. " \"name\": \"hey\"\n" +
  144. " }\n" +
  145. " }\n" +
  146. " ]\n" +
  147. "}"));
  148. RepositoryList gsonBBSRepoList = underTest.getRecentRepo(server.url("/").toString(), "token");
  149. assertThat(gsonBBSRepoList.isLastPage()).isTrue();
  150. assertThat(gsonBBSRepoList.getValues()).hasSize(2);
  151. assertThat(gsonBBSRepoList.getValues()).extracting(Repository::getId, Repository::getName, Repository::getSlug,
  152. g -> g.getProject().getId(), g -> g.getProject().getKey(), g -> g.getProject().getName())
  153. .containsExactlyInAnyOrder(
  154. tuple(2L, "banana", "banana", 2L, "HOY", "hoy"),
  155. tuple(1L, "potato", "potato", 1L, "HEY", "hey"));
  156. }
  157. @Test
  158. public void get_repo() {
  159. server.enqueue(new MockResponse()
  160. .setHeader("Content-Type", "application/json;charset=UTF-8")
  161. .setBody(
  162. " {" +
  163. " \"slug\": \"banana-slug\"," +
  164. " \"id\": 2,\n" +
  165. " \"name\": \"banana\"," +
  166. " \"project\": {\n" +
  167. " \"key\": \"HOY\"," +
  168. " \"id\": 3,\n" +
  169. " \"name\": \"hoy\"" +
  170. " }" +
  171. " }"));
  172. Repository repository = underTest.getRepo(server.url("/").toString(), "token", "", "");
  173. assertThat(repository.getId()).isEqualTo(2L);
  174. assertThat(repository.getName()).isEqualTo("banana");
  175. assertThat(repository.getSlug()).isEqualTo("banana-slug");
  176. assertThat(repository.getProject())
  177. .extracting(Project::getId, Project::getKey, Project::getName)
  178. .contains(3L, "HOY", "hoy");
  179. }
  180. @Test
  181. public void get_projects() {
  182. server.enqueue(new MockResponse()
  183. .setHeader("Content-Type", "application/json;charset=UTF-8")
  184. .setBody("{\n" +
  185. " \"isLastPage\": true,\n" +
  186. " \"values\": [\n" +
  187. " {\n" +
  188. " \"key\": \"HEY\",\n" +
  189. " \"id\": 1,\n" +
  190. " \"name\": \"hey\"\n" +
  191. " },\n" +
  192. " {\n" +
  193. " \"key\": \"HOY\",\n" +
  194. " \"id\": 2,\n" +
  195. " \"name\": \"hoy\"\n" +
  196. " }\n" +
  197. " ]\n" +
  198. "}"));
  199. final ProjectList gsonBBSProjectList = underTest.getProjects(server.url("/").toString(), "token");
  200. assertThat(gsonBBSProjectList.getValues()).hasSize(2);
  201. assertThat(gsonBBSProjectList.getValues()).extracting(Project::getId, Project::getKey, Project::getName)
  202. .containsExactlyInAnyOrder(
  203. tuple(1L, "HEY", "hey"),
  204. tuple(2L, "HOY", "hoy"));
  205. }
  206. @Test
  207. public void get_projects_failed() {
  208. server.enqueue(new MockResponse()
  209. .setBody(new Buffer().write(new byte[4096]))
  210. .setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY));
  211. String serverUrl = server.url("/").toString();
  212. assertThatThrownBy(() -> underTest.getProjects(serverUrl, "token"))
  213. .isInstanceOf(IllegalArgumentException.class)
  214. .hasMessage("Unable to contact Bitbucket server");
  215. assertThat(String.join(", ", logTester.logs())).contains("Unable to contact Bitbucket server");
  216. }
  217. @Test
  218. public void getBranches_given0Branches_returnEmptyList() {
  219. String bodyWith0Branches = "{\n" +
  220. " \"size\": 0,\n" +
  221. " \"limit\": 25,\n" +
  222. " \"isLastPage\": true,\n" +
  223. " \"values\": [],\n" +
  224. " \"start\": 0\n" +
  225. "}";
  226. server.enqueue(new MockResponse()
  227. .setHeader("Content-Type", "application/json;charset=UTF-8")
  228. .setBody(bodyWith0Branches));
  229. BranchesList branches = underTest.getBranches(server.url("/").toString(), "token", "projectSlug", "repoSlug");
  230. assertThat(branches.getBranches()).isEmpty();
  231. }
  232. @Test
  233. public void getBranches_given1Branch_returnListWithOneBranch() {
  234. String bodyWith1Branch = "{\n" +
  235. " \"size\": 1,\n" +
  236. " \"limit\": 25,\n" +
  237. " \"isLastPage\": true,\n" +
  238. " \"values\": [{\n" +
  239. " \"id\": \"refs/heads/demo\",\n" +
  240. " \"displayId\": \"demo\",\n" +
  241. " \"type\": \"BRANCH\",\n" +
  242. " \"latestCommit\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
  243. " \"latestChangeset\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
  244. " \"isDefault\": false\n" +
  245. " }],\n" +
  246. " \"start\": 0\n" +
  247. "}";
  248. server.enqueue(new MockResponse()
  249. .setHeader("Content-Type", "application/json;charset=UTF-8")
  250. .setBody(bodyWith1Branch));
  251. BranchesList branches = underTest.getBranches(server.url("/").toString(), "token", "projectSlug", "repoSlug");
  252. assertThat(branches.getBranches()).hasSize(1);
  253. Branch branch = branches.getBranches().get(0);
  254. assertThat(branch.getName()).isEqualTo("demo");
  255. assertThat(branch.isDefault()).isFalse();
  256. }
  257. @Test
  258. public void getBranches_given2Branches_returnListWithTwoBranches() {
  259. String bodyWith2Branches = "{\n" +
  260. " \"size\": 2,\n" +
  261. " \"limit\": 25,\n" +
  262. " \"isLastPage\": true,\n" +
  263. " \"values\": [{\n" +
  264. " \"id\": \"refs/heads/demo\",\n" +
  265. " \"displayId\": \"demo\",\n" +
  266. " \"type\": \"BRANCH\",\n" +
  267. " \"latestCommit\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
  268. " \"latestChangeset\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
  269. " \"isDefault\": false\n" +
  270. " }, {\n" +
  271. " \"id\": \"refs/heads/master\",\n" +
  272. " \"displayId\": \"master\",\n" +
  273. " \"type\": \"BRANCH\",\n" +
  274. " \"latestCommit\": \"66633864d27c531ff43892f6dfea6d91632682fa\",\n" +
  275. " \"latestChangeset\": \"66633864d27c531ff43892f6dfea6d91632682fa\",\n" +
  276. " \"isDefault\": true\n" +
  277. " }],\n" +
  278. " \"start\": 0\n" +
  279. "}";
  280. server.enqueue(new MockResponse()
  281. .setHeader("Content-Type", "application/json;charset=UTF-8")
  282. .setBody(bodyWith2Branches));
  283. BranchesList branches = underTest.getBranches(server.url("/").toString(), "token", "projectSlug", "repoSlug");
  284. assertThat(branches.getBranches()).hasSize(2);
  285. }
  286. @Test
  287. public void invalid_empty_url() {
  288. assertThatThrownBy(() -> BitbucketServerRestClient.buildUrl(null, ""))
  289. .isInstanceOf(IllegalArgumentException.class)
  290. .hasMessage("url must start with http:// or https://");
  291. }
  292. @Test
  293. public void invalid_url() {
  294. assertThatThrownBy(() -> BitbucketServerRestClient.buildUrl("file://wrong-url", ""))
  295. .isInstanceOf(IllegalArgumentException.class)
  296. .hasMessage("url must start with http:// or https://");
  297. }
  298. @Test
  299. public void malformed_json() {
  300. server.enqueue(new MockResponse()
  301. .setHeader("Content-Type", "application/json;charset=UTF-8")
  302. .setBody("I'm malformed JSON"));
  303. String serverUrl = server.url("/").toString();
  304. assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
  305. .isInstanceOf(IllegalArgumentException.class)
  306. .hasMessage("Unexpected response from Bitbucket server");
  307. assertThat(String.join(", ", logTester.logs()))
  308. .contains("Unexpected response from Bitbucket server : [I'm malformed JSON]");
  309. }
  310. @Test
  311. public void fail_json_error_handling() {
  312. assertThatThrownBy(() -> underTest.applyHandler(body -> underTest.buildGson().fromJson(body, Object.class), "not json"))
  313. .isInstanceOf(IllegalArgumentException.class)
  314. .hasMessage("Unable to contact Bitbucket server, got an unexpected response");
  315. assertThat(String.join(", ", logTester.logs()))
  316. .contains("Unable to contact Bitbucket server. Unexpected body response was : [not json]");
  317. }
  318. @Test
  319. public void validate_handler_call_on_empty_body() {
  320. server.enqueue(new MockResponse().setResponseCode(200)
  321. .setBody(""));
  322. assertThat(underTest.doGet("token", server.url("/"), Function.identity()))
  323. .isEmpty();
  324. }
  325. @Test
  326. public void error_handling() {
  327. server.enqueue(new MockResponse()
  328. .setHeader("Content-Type", "application/json;charset=UTF-8")
  329. .setResponseCode(400)
  330. .setBody("{\n" +
  331. " \"errors\": [\n" +
  332. " {\n" +
  333. " \"context\": null,\n" +
  334. " \"message\": \"Bad message\",\n" +
  335. " \"exceptionName\": \"com.atlassian.bitbucket.auth.BadException\"\n" +
  336. " }\n" +
  337. " ]\n" +
  338. "}"));
  339. String serverUrl = server.url("/").toString();
  340. assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
  341. .isInstanceOf(IllegalArgumentException.class)
  342. .hasMessage("Unable to contact Bitbucket server");
  343. }
  344. @Test
  345. public void unauthorized_error() {
  346. server.enqueue(new MockResponse()
  347. .setHeader("Content-Type", "application/json;charset=UTF-8")
  348. .setResponseCode(401)
  349. .setBody("{\n" +
  350. " \"errors\": [\n" +
  351. " {\n" +
  352. " \"context\": null,\n" +
  353. " \"message\": \"Bad message\",\n" +
  354. " \"exceptionName\": \"com.atlassian.bitbucket.auth.BadException\"\n" +
  355. " }\n" +
  356. " ]\n" +
  357. "}"));
  358. String serverUrl = server.url("/").toString();
  359. assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
  360. .isInstanceOf(IllegalArgumentException.class)
  361. .hasMessage("Invalid personal access token");
  362. }
  363. @DataProvider
  364. public static Object[][] expectedErrorMessageFromHttpNoJsonBody() {
  365. return new Object[][] {
  366. {200, "content ready", "application/json;charset=UTF-8", "Unexpected response from Bitbucket server"},
  367. {201, "content ready!", "application/xhtml+xml", "Unexpected response from Bitbucket server"},
  368. {401, "<p>unauthorized</p>", "application/json;charset=UTF-8", "Invalid personal access token"},
  369. {401, "<p>unauthorized</p>", "application/json", "Invalid personal access token"},
  370. {401, "<not-authorized>401</not-authorized>", "application/xhtml+xml", "Invalid personal access token"},
  371. {403, "<p>forbidden</p>", "application/json;charset=UTF-8", "Unable to contact Bitbucket server"},
  372. {404, "<p>not found</p>","application/json;charset=UTF-8", "Error 404. The requested Bitbucket server is unreachable."},
  373. {406, "<p>not accepted</p>", "application/json;charset=UTF-8", "Unable to contact Bitbucket server"},
  374. {409, "<p>conflict</p>", "application/json;charset=UTF-8", "Unable to contact Bitbucket server"}
  375. };
  376. }
  377. @Test
  378. @UseDataProvider("expectedErrorMessageFromHttpNoJsonBody")
  379. public void fail_response_when_http_no_json_body(int responseCode, String body, String headerContent, String expectedErrorMessage) {
  380. server.enqueue(new MockResponse()
  381. .setHeader("Content-Type", headerContent)
  382. .setResponseCode(responseCode)
  383. .setBody(body));
  384. String serverUrl = server.url("/").toString();
  385. assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
  386. .isInstanceOf(IllegalArgumentException.class)
  387. .hasMessage(expectedErrorMessage);
  388. }
  389. @Test
  390. public void fail_validate_on_io_exception() throws IOException {
  391. server.shutdown();
  392. String serverUrl = server.url("/").toString();
  393. assertThatThrownBy(() -> underTest.validateUrl(serverUrl))
  394. .isInstanceOf(IllegalArgumentException.class)
  395. .hasMessage("Unable to contact Bitbucket server");
  396. assertThat(String.join(", ", logTester.logs())).contains("Unable to contact Bitbucket server");
  397. }
  398. @Test
  399. public void fail_validate_url_on_non_json_result_log_correctly_the_response() {
  400. server.enqueue(new MockResponse()
  401. .setHeader("Content-Type", "application/json;charset=UTF-8")
  402. .setResponseCode(500)
  403. .setBody("not json"));
  404. String serverUrl = server.url("/").toString();
  405. assertThatThrownBy(() -> underTest.validateReadPermission(serverUrl, "token"))
  406. .isInstanceOf(IllegalArgumentException.class)
  407. .hasMessage("Unable to contact Bitbucket server");
  408. assertThat(String.join(", ", logTester.logs())).contains("Unable to contact Bitbucket server: 500 not json");
  409. }
  410. @Test
  411. public void fail_validate_url_on_text_result_log_the_returned_payload() {
  412. server.enqueue(new MockResponse()
  413. .setResponseCode(500)
  414. .setBody("this is a text payload"));
  415. String serverUrl = server.url("/").toString();
  416. assertThatThrownBy(() -> underTest.validateReadPermission(serverUrl, "token"))
  417. .isInstanceOf(IllegalArgumentException.class)
  418. .hasMessage("Unable to contact Bitbucket server");
  419. assertThat(String.join(", ", logTester.logs())).contains("Unable to contact Bitbucket server: 500 this is a text payload");
  420. }
  421. @Test
  422. public void validate_url_success() {
  423. server.enqueue(new MockResponse().setResponseCode(200)
  424. .setBody(REPOS_BODY));
  425. underTest.validateUrl(server.url("/").toString());
  426. }
  427. @Test
  428. public void validate_url_fail_when_not_starting_with_protocol() {
  429. assertThatThrownBy(() -> underTest.validateUrl("any_url_not_starting_with_http.com"))
  430. .isInstanceOf(IllegalArgumentException.class)
  431. .hasMessage("url must start with http:// or https://");
  432. }
  433. @Test
  434. public void validate_token_success() {
  435. server.enqueue(new MockResponse().setResponseCode(200)
  436. .setBody("{\n" +
  437. " \"size\":10,\n" +
  438. " \"limit\":25,\n" +
  439. " \"isLastPage\":true,\n" +
  440. " \"values\":[\n" +
  441. " {\n" +
  442. " \"name\":\"jean.michel\",\n" +
  443. " \"emailAddress\":\"jean.michel@sonarsource.com\",\n" +
  444. " \"id\":2,\n" +
  445. " \"displayName\":\"Jean Michel\",\n" +
  446. " \"active\":true,\n" +
  447. " \"slug\":\"jean.michel\",\n" +
  448. " \"type\":\"NORMAL\",\n" +
  449. " \"links\":{\n" +
  450. " \"self\":[\n" +
  451. " {\n" +
  452. " \"href\":\"https://bitbucket-testing.valiantys.sonarsource.com/users/jean.michel\"\n" +
  453. " }\n" +
  454. " ]\n" +
  455. " }\n" +
  456. " },\n" +
  457. " {\n" +
  458. " \"name\":\"prince.de.lu\",\n" +
  459. " \"emailAddress\":\"prince.de.lu@sonarsource.com\",\n" +
  460. " \"id\":103,\n" +
  461. " \"displayName\":\"Prince de Lu\",\n" +
  462. " \"active\":true,\n" +
  463. " \"slug\":\"prince.de.lu\",\n" +
  464. " \"type\":\"NORMAL\",\n" +
  465. " \"links\":{\n" +
  466. " \"self\":[\n" +
  467. " {\n" +
  468. " \"href\":\"https://bitbucket-testing.valiantys.sonarsource.com/users/prince.de.lu\"\n" +
  469. " }\n" +
  470. " ]\n" +
  471. " }\n" +
  472. " },\n" +
  473. " ],\n" +
  474. " \"start\":0\n" +
  475. "}"));
  476. underTest.validateToken(server.url("/").toString(), "token");
  477. }
  478. @Test
  479. public void validate_read_permission_success() {
  480. server.enqueue(new MockResponse().setResponseCode(200)
  481. .setBody(REPOS_BODY));
  482. underTest.validateReadPermission(server.url("/").toString(), "token");
  483. }
  484. @Test
  485. public void fail_validate_url_when_on_http_error() {
  486. server.enqueue(new MockResponse().setResponseCode(500)
  487. .setBody("something unexpected"));
  488. String serverUrl = server.url("/").toString();
  489. assertThatThrownBy(() -> underTest.validateUrl(serverUrl))
  490. .isInstanceOf(IllegalArgumentException.class)
  491. .hasMessage("Unable to contact Bitbucket server");
  492. }
  493. @Test
  494. public void fail_validate_url_when_not_found_is_returned() {
  495. server.enqueue(new MockResponse().setResponseCode(404)
  496. .setBody("something unexpected"));
  497. String serverUrl = server.url("/").toString();
  498. assertThatThrownBy(() -> underTest.validateUrl(serverUrl))
  499. .isInstanceOf(BitbucketServerException.class)
  500. .hasMessage("Error 404. The requested Bitbucket server is unreachable.")
  501. .extracting(e -> ((BitbucketServerException) e).getHttpStatus()).isEqualTo(404);
  502. }
  503. @Test
  504. public void fail_validate_url_when_body_is_empty() {
  505. server.enqueue(new MockResponse().setResponseCode(404).setBody(""));
  506. String serverUrl = server.url("/").toString();
  507. assertThatThrownBy(() -> underTest.validateUrl(serverUrl))
  508. .isInstanceOf(BitbucketServerException.class)
  509. .hasMessage("Error 404. The requested Bitbucket server is unreachable.")
  510. .extracting(e -> ((BitbucketServerException) e).getHttpStatus()).isEqualTo(404);
  511. }
  512. @Test
  513. public void fail_validate_url_when_validate_url_return_non_json_payload() {
  514. server.enqueue(new MockResponse().setResponseCode(400)
  515. .setBody("this is not a json payload"));
  516. String serverUrl = server.url("/").toString();
  517. assertThatThrownBy(() -> underTest.validateUrl(serverUrl))
  518. .isInstanceOf(IllegalArgumentException.class)
  519. .hasMessage("Unable to contact Bitbucket server");
  520. }
  521. @Test
  522. public void fail_validate_url_when_returning_non_json_payload_with_a_200_code() {
  523. server.enqueue(new MockResponse().setResponseCode(200)
  524. .setBody("this is not a json payload"));
  525. String serverUrl = server.url("/").toString();
  526. assertThatThrownBy(() -> underTest.validateUrl(serverUrl))
  527. .isInstanceOf(IllegalArgumentException.class)
  528. .hasMessage("Unexpected response from Bitbucket server");
  529. assertThat(String.join(", ", logTester.logs()))
  530. .contains("Unexpected response from Bitbucket server : [this is not a json payload]");
  531. }
  532. @Test
  533. public void fail_validate_token_when_server_return_non_json_payload() {
  534. server.enqueue(new MockResponse().setResponseCode(400)
  535. .setBody("this is not a json payload"));
  536. String serverUrl = server.url("/").toString();
  537. assertThatThrownBy(() -> underTest.validateToken(serverUrl, "token"))
  538. .isInstanceOf(IllegalArgumentException.class)
  539. .hasMessage("Unable to contact Bitbucket server");
  540. }
  541. @Test
  542. public void fail_validate_token_when_returning_non_json_payload_with_a_200_code() {
  543. server.enqueue(new MockResponse().setResponseCode(200)
  544. .setBody("this is not a json payload"));
  545. String serverUrl = server.url("/").toString();
  546. assertThatThrownBy(() -> underTest.validateToken(serverUrl, "token"))
  547. .isInstanceOf(IllegalArgumentException.class)
  548. .hasMessage("Unexpected response from Bitbucket server");
  549. assertThat(String.join(", ", logTester.logs()))
  550. .contains("Unexpected response from Bitbucket server : [this is not a json payload]");
  551. }
  552. @Test
  553. public void fail_validate_token_when_using_an_invalid_token() {
  554. server.enqueue(new MockResponse().setResponseCode(401)
  555. .setBody("com.atlassian.bitbucket.AuthorisationException You are not permitted to access this resource"));
  556. String serverUrl = server.url("/").toString();
  557. assertThatThrownBy(() -> underTest.validateToken(serverUrl, "token"))
  558. .isInstanceOf(IllegalArgumentException.class)
  559. .hasMessage("Invalid personal access token");
  560. }
  561. @Test
  562. public void fail_validate_read_permission_when_server_return_non_json_payload() {
  563. server.enqueue(new MockResponse().setResponseCode(400)
  564. .setBody("this is not a json payload"));
  565. String serverUrl = server.url("/").toString();
  566. assertThatThrownBy(() -> underTest.validateReadPermission(serverUrl, "token"))
  567. .isInstanceOf(IllegalArgumentException.class)
  568. .hasMessage("Unable to contact Bitbucket server");
  569. }
  570. @Test
  571. public void fail_validate_read_permission_when_returning_non_json_payload_with_a_200_code() {
  572. server.enqueue(new MockResponse().setResponseCode(200)
  573. .setBody("this is not a json payload"));
  574. String serverUrl = server.url("/").toString();
  575. assertThatThrownBy(() -> underTest.validateReadPermission(serverUrl, "token"))
  576. .isInstanceOf(IllegalArgumentException.class)
  577. .hasMessage("Unexpected response from Bitbucket server");
  578. assertThat(String.join(", ", logTester.logs()))
  579. .contains("Unexpected response from Bitbucket server : [this is not a json payload]");
  580. }
  581. @Test
  582. public void fail_validate_read_permission_when_permissions_are_not_granted() {
  583. server.enqueue(new MockResponse().setResponseCode(401)
  584. .setBody("com.atlassian.bitbucket.AuthorisationException You are not permitted to access this resource"));
  585. String serverUrl = server.url("/").toString();
  586. assertThatThrownBy(() -> underTest.validateReadPermission(serverUrl, "token"))
  587. .isInstanceOf(IllegalArgumentException.class)
  588. .hasMessage("Invalid personal access token");
  589. }
  590. @Test
  591. public void check_mediaTypes_equality() {
  592. assertThat(underTest.equals(null, null)).isFalse();
  593. assertThat(underTest.equals(MediaType.parse("application/json"), null)).isFalse();
  594. assertThat(underTest.equals(null, MediaType.parse("application/json"))).isFalse();
  595. assertThat(underTest.equals(MediaType.parse("application/ json"), MediaType.parse("text/html; charset=UTF-8"))).isFalse();
  596. assertThat(underTest.equals(MediaType.parse("application/Json"), MediaType.parse("application/JSON"))).isTrue();
  597. }
  598. }