3 * Copyright (C) 2009-2021 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.alm.client.bitbucketserver;
22 import java.io.IOException;
23 import okhttp3.mockwebserver.MockResponse;
24 import okhttp3.mockwebserver.MockWebServer;
25 import org.junit.After;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.sonar.alm.client.ConstantTimeoutConfiguration;
30 import static org.assertj.core.api.Assertions.assertThat;
31 import static org.assertj.core.api.Assertions.assertThatThrownBy;
32 import static org.assertj.core.api.Assertions.tuple;
34 public class BitbucketServerRestClientTest {
35 private final MockWebServer server = new MockWebServer();
36 private BitbucketServerRestClient underTest;
39 public void prepare() throws IOException {
42 underTest = new BitbucketServerRestClient(new ConstantTimeoutConfiguration(500));
46 public void stopServer() throws IOException {
51 public void get_repos() {
52 server.enqueue(new MockResponse()
53 .setHeader("Content-Type", "application/json;charset=UTF-8")
55 " \"isLastPage\": true,\n" +
58 " \"slug\": \"banana\",\n" +
60 " \"name\": \"banana\",\n" +
62 " \"key\": \"HOY\",\n" +
64 " \"name\": \"hoy\"\n" +
68 " \"slug\": \"potato\",\n" +
70 " \"name\": \"potato\",\n" +
72 " \"key\": \"HEY\",\n" +
74 " \"name\": \"hey\"\n" +
80 RepositoryList gsonBBSRepoList = underTest.getRepos(server.url("/").toString(), "token", "", "");
81 assertThat(gsonBBSRepoList.isLastPage()).isTrue();
82 assertThat(gsonBBSRepoList.getValues()).hasSize(2);
83 assertThat(gsonBBSRepoList.getValues()).extracting(Repository::getId, Repository::getName, Repository::getSlug,
84 g -> g.getProject().getId(), g -> g.getProject().getKey(), g -> g.getProject().getName())
85 .containsExactlyInAnyOrder(
86 tuple(2L, "banana", "banana", 2L, "HOY", "hoy"),
87 tuple(1L, "potato", "potato", 1L, "HEY", "hey"));
91 public void get_recent_repos() {
92 server.enqueue(new MockResponse()
93 .setHeader("Content-Type", "application/json;charset=UTF-8")
95 " \"isLastPage\": true,\n" +
98 " \"slug\": \"banana\",\n" +
100 " \"name\": \"banana\",\n" +
101 " \"project\": {\n" +
102 " \"key\": \"HOY\",\n" +
104 " \"name\": \"hoy\"\n" +
108 " \"slug\": \"potato\",\n" +
110 " \"name\": \"potato\",\n" +
111 " \"project\": {\n" +
112 " \"key\": \"HEY\",\n" +
114 " \"name\": \"hey\"\n" +
120 RepositoryList gsonBBSRepoList = underTest.getRecentRepo(server.url("/").toString(), "token");
121 assertThat(gsonBBSRepoList.isLastPage()).isTrue();
122 assertThat(gsonBBSRepoList.getValues()).hasSize(2);
123 assertThat(gsonBBSRepoList.getValues()).extracting(Repository::getId, Repository::getName, Repository::getSlug,
124 g -> g.getProject().getId(), g -> g.getProject().getKey(), g -> g.getProject().getName())
125 .containsExactlyInAnyOrder(
126 tuple(2L, "banana", "banana", 2L, "HOY", "hoy"),
127 tuple(1L, "potato", "potato", 1L, "HEY", "hey"));
131 public void get_repo() {
132 server.enqueue(new MockResponse()
133 .setHeader("Content-Type", "application/json;charset=UTF-8")
136 " \"slug\": \"banana-slug\"," +
138 " \"name\": \"banana\"," +
139 " \"project\": {\n" +
140 " \"key\": \"HOY\"," +
142 " \"name\": \"hoy\"" +
146 Repository repository = underTest.getRepo(server.url("/").toString(), "token", "", "");
147 assertThat(repository.getId()).isEqualTo(2L);
148 assertThat(repository.getName()).isEqualTo("banana");
149 assertThat(repository.getSlug()).isEqualTo("banana-slug");
150 assertThat(repository.getProject())
151 .extracting(Project::getId, Project::getKey, Project::getName)
152 .contains(3L, "HOY", "hoy");
156 public void get_projects() {
157 server.enqueue(new MockResponse()
158 .setHeader("Content-Type", "application/json;charset=UTF-8")
160 " \"isLastPage\": true,\n" +
163 " \"key\": \"HEY\",\n" +
165 " \"name\": \"hey\"\n" +
168 " \"key\": \"HOY\",\n" +
170 " \"name\": \"hoy\"\n" +
175 final ProjectList gsonBBSProjectList = underTest.getProjects(server.url("/").toString(), "token");
176 assertThat(gsonBBSProjectList.getValues()).hasSize(2);
177 assertThat(gsonBBSProjectList.getValues()).extracting(Project::getId, Project::getKey, Project::getName)
178 .containsExactlyInAnyOrder(
179 tuple(1L, "HEY", "hey"),
180 tuple(2L, "HOY", "hoy"));
184 public void getBranches_given0Branches_returnEmptyList(){
185 String bodyWith0Branches = "{\n" +
187 " \"limit\": 25,\n" +
188 " \"isLastPage\": true,\n" +
189 " \"values\": [],\n" +
192 server.enqueue(new MockResponse()
193 .setHeader("Content-Type", "application/json;charset=UTF-8")
194 .setBody(bodyWith0Branches));
196 BranchesList branches = underTest.getBranches(server.url("/").toString(), "token", "projectSlug", "repoSlug");
198 assertThat(branches.getBranches()).isEmpty();
202 public void getBranches_given1Branch_returnListWithOneBranch(){
203 String bodyWith1Branch = "{\n" +
205 " \"limit\": 25,\n" +
206 " \"isLastPage\": true,\n" +
207 " \"values\": [{\n" +
208 " \"id\": \"refs/heads/demo\",\n" +
209 " \"displayId\": \"demo\",\n" +
210 " \"type\": \"BRANCH\",\n" +
211 " \"latestCommit\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
212 " \"latestChangeset\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
213 " \"isDefault\": false\n" +
217 server.enqueue(new MockResponse()
218 .setHeader("Content-Type", "application/json;charset=UTF-8")
219 .setBody(bodyWith1Branch));
221 BranchesList branches = underTest.getBranches(server.url("/").toString(), "token", "projectSlug", "repoSlug");
222 assertThat(branches.getBranches()).hasSize(1);
224 Branch branch = branches.getBranches().get(0);
225 assertThat(branch.getName()).isEqualTo("demo");
226 assertThat(branch.isDefault()).isFalse();
231 public void getBranches_given2Branches_returnListWithTwoBranches(){
232 String bodyWith2Branches = "{\n" +
234 " \"limit\": 25,\n" +
235 " \"isLastPage\": true,\n" +
236 " \"values\": [{\n" +
237 " \"id\": \"refs/heads/demo\",\n" +
238 " \"displayId\": \"demo\",\n" +
239 " \"type\": \"BRANCH\",\n" +
240 " \"latestCommit\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
241 " \"latestChangeset\": \"3e30a6701af6f29f976e9a6609a6076b32a69ac3\",\n" +
242 " \"isDefault\": false\n" +
244 " \"id\": \"refs/heads/master\",\n" +
245 " \"displayId\": \"master\",\n" +
246 " \"type\": \"BRANCH\",\n" +
247 " \"latestCommit\": \"66633864d27c531ff43892f6dfea6d91632682fa\",\n" +
248 " \"latestChangeset\": \"66633864d27c531ff43892f6dfea6d91632682fa\",\n" +
249 " \"isDefault\": true\n" +
253 server.enqueue(new MockResponse()
254 .setHeader("Content-Type", "application/json;charset=UTF-8")
255 .setBody(bodyWith2Branches));
257 BranchesList branches = underTest.getBranches(server.url("/").toString(), "token", "projectSlug", "repoSlug");
259 assertThat(branches.getBranches()).hasSize(2);
263 public void invalid_url() {
264 assertThatThrownBy(() -> BitbucketServerRestClient.buildUrl("file://wrong-url", ""))
265 .isInstanceOf(IllegalArgumentException.class)
266 .hasMessage("url must start with http:// or https://");
270 public void malformed_json() {
271 server.enqueue(new MockResponse()
272 .setHeader("Content-Type", "application/json;charset=UTF-8")
274 "I'm malformed JSON"));
276 String serverUrl = server.url("/").toString();
277 assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
278 .isInstanceOf(IllegalArgumentException.class)
279 .hasMessage("Unable to contact Bitbucket server, got an unexpected response");
283 public void error_handling() {
284 server.enqueue(new MockResponse()
285 .setHeader("Content-Type", "application/json;charset=UTF-8")
286 .setResponseCode(400)
290 " \"context\": null,\n" +
291 " \"message\": \"Bad message\",\n" +
292 " \"exceptionName\": \"com.atlassian.bitbucket.auth.BadException\"\n" +
297 String serverUrl = server.url("/").toString();
298 assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
299 .isInstanceOf(IllegalArgumentException.class)
300 .hasMessage("Unable to contact Bitbucket server");
304 public void unauthorized_error() {
305 server.enqueue(new MockResponse()
306 .setHeader("Content-Type", "application/json;charset=UTF-8")
307 .setResponseCode(401)
311 " \"context\": null,\n" +
312 " \"message\": \"Bad message\",\n" +
313 " \"exceptionName\": \"com.atlassian.bitbucket.auth.BadException\"\n" +
318 String serverUrl = server.url("/").toString();
319 assertThatThrownBy(() -> underTest.getRepo(serverUrl, "token", "", ""))
320 .isInstanceOf(IllegalArgumentException.class)
321 .hasMessage("Invalid personal access token");