aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-alm-client/src/test/java
diff options
context:
space:
mode:
authorAurelien Poscia <aurelien.poscia@sonarsource.com>2023-11-30 09:58:20 +0100
committersonartech <sonartech@sonarsource.com>2023-12-22 20:03:01 +0000
commit68de595dc688e9fd09bd8925c94d0bba830c3869 (patch)
tree6ca9621267a13fcc2a752dc2a882b60057ee7761 /server/sonar-alm-client/src/test/java
parentc0c9226eb421d0581b269c74a083aad00a7ad679 (diff)
downloadsonarqube-68de595dc688e9fd09bd8925c94d0bba830c3869.tar.gz
sonarqube-68de595dc688e9fd09bd8925c94d0bba830c3869.zip
SONAR-21119 Provide method to get groups for GitLab & refactored GithubPaginatedHttpClient and GithubApplicationHttpClient to make them generic
Diffstat (limited to 'server/sonar-alm-client/src/test/java')
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/GenericPaginatedHttpClientImplTest.java (renamed from server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubPaginatedHttpClientImplTest.java)34
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/RatioBasedRateLimitCheckerTest.java (renamed from server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/RatioBasedRateLimitCheckerTest.java)4
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GenericApplicationHttpClientTest.java55
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java109
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java (renamed from server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabHttpClientTest.java)69
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabGlobalSettingsValidatorTest.java4
6 files changed, 181 insertions, 94 deletions
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubPaginatedHttpClientImplTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/GenericPaginatedHttpClientImplTest.java
index 5df514c857e..f9589290d53 100644
--- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubPaginatedHttpClientImplTest.java
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/GenericPaginatedHttpClientImplTest.java
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-package org.sonar.alm.client.github;
+package org.sonar.alm.client;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@@ -45,10 +45,10 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.sonar.alm.client.github.ApplicationHttpClient.GetResponse;
+import static org.sonar.alm.client.ApplicationHttpClient.GetResponse;
@RunWith(MockitoJUnitRunner.class)
-public class GithubPaginatedHttpClientImplTest {
+public class GenericPaginatedHttpClientImplTest {
private static final String APP_URL = "https://github.com/";
@@ -71,7 +71,13 @@ public class GithubPaginatedHttpClientImplTest {
ApplicationHttpClient appHttpClient;
@InjectMocks
- private GithubPaginatedHttpClient underTest;
+ private TestPaginatedHttpClient underTest;
+
+ private static class TestPaginatedHttpClient extends GenericPaginatedHttpClient {
+ protected TestPaginatedHttpClient(ApplicationHttpClient appHttpClient, RatioBasedRateLimitChecker rateLimitChecker) {
+ super(appHttpClient, rateLimitChecker);
+ }
+ }
@Test
public void get_whenNoPagination_ReturnsCorrectResponse() throws IOException {
@@ -141,7 +147,8 @@ public class GithubPaginatedHttpClientImplTest {
assertThatIllegalStateException()
.isThrownBy(() -> underTest.get(APP_URL, accessToken, ENDPOINT, result -> gson.fromJson(result, STRING_LIST_TYPE)))
- .withMessage("Error while executing a call to GitHub. Return code 400. Error message: failed.");
+ .withMessage("SonarQube was not able to retrieve resources from external system. Error while executing a paginated call to https://github.com/, endpoint:/next-endpoint. "
+ + "Error while executing a call to https://github.com/. Return code 400. Error message: failed.");
}
private static GetResponse mockFailedResponse(String content) {
@@ -166,4 +173,21 @@ public class GithubPaginatedHttpClientImplTest {
assertThat(logTester.logs(Level.WARN))
.containsExactly("Thread interrupted: interrupted");
}
+
+ @Test
+ public void getRepositoryCollaborators_whenDevOpsPlatformCallThrowsIOException_shouldLogAndReThrow() throws IOException {
+ AccessToken accessToken = mock();
+ when(appHttpClient.get(APP_URL, accessToken, "query?per_page=100")).thenThrow(new IOException("error"));
+
+ assertThatIllegalStateException()
+ .isThrownBy(() -> underTest.get(APP_URL, accessToken, "query", mock()))
+ .isInstanceOf(IllegalStateException.class)
+ .withMessage("SonarQube was not able to retrieve resources from external system. Error while executing a paginated call to https://github.com/, "
+ + "endpoint:query?per_page=100. error");
+
+ assertThat(logTester.logs()).hasSize(1);
+ assertThat(logTester.logs(Level.WARN))
+ .containsExactly("SonarQube was not able to retrieve resources from external system. "
+ + "Error while executing a paginated call to https://github.com/, endpoint:query?per_page=100.");
+ }
}
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/RatioBasedRateLimitCheckerTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/RatioBasedRateLimitCheckerTest.java
index d10633365c6..d6d2bfff6e5 100644
--- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/RatioBasedRateLimitCheckerTest.java
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/RatioBasedRateLimitCheckerTest.java
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-package org.sonar.alm.client.github;
+package org.sonar.alm.client;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
@@ -32,7 +32,7 @@ import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.sonar.alm.client.github.RatioBasedRateLimitChecker.RATE_RATIO_EXCEEDED_MESSAGE;
+import static org.sonar.alm.client.RatioBasedRateLimitChecker.RATE_RATIO_EXCEEDED_MESSAGE;
@RunWith(DataProviderRunner.class)
public class RatioBasedRateLimitCheckerTest {
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GenericApplicationHttpClientTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GenericApplicationHttpClientTest.java
index 53a6fcf08c9..dcd2fdab87c 100644
--- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GenericApplicationHttpClientTest.java
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GenericApplicationHttpClientTest.java
@@ -36,9 +36,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.event.Level;
import org.sonar.alm.client.ConstantTimeoutConfiguration;
+import org.sonar.alm.client.DevopsPlatformHeaders;
+import org.sonar.alm.client.GenericApplicationHttpClient;
import org.sonar.alm.client.TimeoutConfiguration;
-import org.sonar.alm.client.github.ApplicationHttpClient.GetResponse;
-import org.sonar.alm.client.github.ApplicationHttpClient.Response;
+import org.sonar.alm.client.ApplicationHttpClient.GetResponse;
+import org.sonar.alm.client.ApplicationHttpClient.Response;
import org.sonar.alm.client.github.security.AccessToken;
import org.sonar.alm.client.github.security.UserAccessToken;
import org.sonar.api.testfixtures.log.LogTester;
@@ -49,7 +51,7 @@ import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.fail;
-import static org.sonar.alm.client.github.ApplicationHttpClient.RateLimit;
+import static org.sonar.alm.client.ApplicationHttpClient.RateLimit;
@RunWith(DataProviderRunner.class)
public class GenericApplicationHttpClientTest {
@@ -76,7 +78,7 @@ public class GenericApplicationHttpClientTest {
logTester.clear();
}
- private class TestApplicationHttpClient extends GenericApplicationHttpClient {
+ private static class TestApplicationHttpClient extends GenericApplicationHttpClient {
public TestApplicationHttpClient(DevopsPlatformHeaders devopsPlatformHeaders, TimeoutConfiguration timeoutConfiguration) {
super(devopsPlatformHeaders, timeoutConfiguration);
}
@@ -183,7 +185,7 @@ public class GenericApplicationHttpClientTest {
public void get_returns_empty_endPoint_when_link_header_does_not_have_next_rel() throws IOException {
server.enqueue(new MockResponse().setBody(randomBody)
.setHeader("link", "<https://api.github.com/installation/repositories?per_page=5&page=4>; rel=\"prev\", " +
- "<https://api.github.com/installation/repositories?per_page=5&page=1>; rel=\"first\""));
+ "<https://api.github.com/installation/repositories?per_page=5&page=1>; rel=\"first\""));
GetResponse response = underTest.get(appUrl, accessToken, randomEndPoint);
@@ -212,18 +214,30 @@ public class GenericApplicationHttpClientTest {
assertThat(response.getNextEndPoint()).contains("https://api.github.com/installation/repositories?per_page=5&page=2");
}
+ @Test
+ public void get_returns_endPoint_when_link_header_is_from_gitlab() throws IOException {
+ String linkHeader = "<https://gitlab.com/api/v4/groups?all_available=false&order_by=name&owned=false&page=2&per_page=2&sort=asc&statistics=false&with_custom_attributes=false>; rel=\"next\", <https://gitlab.com/api/v4/groups?all_available=false&order_by=name&owned=false&page=1&per_page=2&sort=asc&statistics=false&with_custom_attributes=false>; rel=\"first\", <https://gitlab.com/api/v4/groups?all_available=false&order_by=name&owned=false&page=8&per_page=2&sort=asc&statistics=false&with_custom_attributes=false>; rel=\"last\"";
+ server.enqueue(new MockResponse().setBody(randomBody)
+ .setHeader("link", linkHeader));
+
+ GetResponse response = underTest.get(appUrl, accessToken, randomEndPoint);
+
+ assertThat(response.getNextEndPoint()).contains("https://gitlab.com/api/v4/groups?all_available=false"
+ + "&order_by=name&owned=false&page=2&per_page=2&sort=asc&statistics=false&with_custom_attributes=false");
+ }
+
@DataProvider
public static Object[][] linkHeadersWithNextRel() {
String expected = "https://api.github.com/installation/repositories?per_page=5&page=2";
return new Object[][] {
{"<" + expected + ">; rel=\"next\""},
{"<" + expected + ">; rel=\"next\", " +
- "<https://api.github.com/installation/repositories?per_page=5&page=1>; rel=\"first\""},
+ "<https://api.github.com/installation/repositories?per_page=5&page=1>; rel=\"first\""},
{"<https://api.github.com/installation/repositories?per_page=5&page=1>; rel=\"first\", " +
- "<" + expected + ">; rel=\"next\""},
+ "<" + expected + ">; rel=\"next\""},
{"<https://api.github.com/installation/repositories?per_page=5&page=1>; rel=\"first\", " +
- "<" + expected + ">; rel=\"next\", " +
- "<https://api.github.com/installation/repositories?per_page=5&page=5>; rel=\"last\""},
+ "<" + expected + ">; rel=\"next\", " +
+ "<https://api.github.com/installation/repositories?per_page=5&page=5>; rel=\"last\""},
};
}
@@ -416,14 +430,19 @@ public class GenericApplicationHttpClientTest {
@Test
public void get_whenRateLimitHeadersArePresent_returnsRateLimit() throws Exception {
- testRateLimitHeader(() -> underTest.get(appUrl, accessToken, randomEndPoint));
+ testRateLimitHeader(() -> underTest.get(appUrl, accessToken, randomEndPoint), false);
+ }
+
+ @Test
+ public void get_whenRateLimitHeadersArePresentAndUppercased_returnsRateLimit() throws Exception {
+ testRateLimitHeader(() -> underTest.get(appUrl, accessToken, randomEndPoint), true);
}
- private void testRateLimitHeader(Callable<Response> request ) throws Exception {
+ private void testRateLimitHeader(Callable<Response> request, boolean uppercasedHeaders) throws Exception {
server.enqueue(new MockResponse().setBody(randomBody)
- .setHeader("x-ratelimit-remaining", "1")
- .setHeader("x-ratelimit-limit", "10")
- .setHeader("x-ratelimit-reset", "1000"));
+ .setHeader(uppercasedHeaders ? "x-ratelimit-remaining" : "x-ratelimit-REMAINING", "1")
+ .setHeader(uppercasedHeaders ? "x-ratelimit-limit" : "X-RATELIMIT-LIMIT", "10")
+ .setHeader(uppercasedHeaders ? "x-ratelimit-reset" : "X-ratelimit-reset", "1000"));
Response response = request.call();
@@ -438,7 +457,7 @@ public class GenericApplicationHttpClientTest {
}
- private void testMissingRateLimitHeader(Callable<Response> request ) throws Exception {
+ private void testMissingRateLimitHeader(Callable<Response> request) throws Exception {
server.enqueue(new MockResponse().setBody(randomBody));
Response response = request.call();
@@ -448,7 +467,7 @@ public class GenericApplicationHttpClientTest {
@Test
public void delete_whenRateLimitHeadersArePresent_returnsRateLimit() throws Exception {
- testRateLimitHeader(() -> underTest.delete(appUrl, accessToken, randomEndPoint));
+ testRateLimitHeader(() -> underTest.delete(appUrl, accessToken, randomEndPoint), false);
}
@@ -460,7 +479,7 @@ public class GenericApplicationHttpClientTest {
@Test
public void patch_whenRateLimitHeadersArePresent_returnsRateLimit() throws Exception {
- testRateLimitHeader(() -> underTest.patch(appUrl, accessToken, randomEndPoint, "body"));
+ testRateLimitHeader(() -> underTest.patch(appUrl, accessToken, randomEndPoint, "body"), false);
}
@Test
@@ -470,7 +489,7 @@ public class GenericApplicationHttpClientTest {
@Test
public void post_whenRateLimitHeadersArePresent_returnsRateLimit() throws Exception {
- testRateLimitHeader(() -> underTest.post(appUrl, accessToken, randomEndPoint));
+ testRateLimitHeader(() -> underTest.post(appUrl, accessToken, randomEndPoint), false);
}
@Test
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java
index 6cf2f71dfc9..a7a3d2203d2 100644
--- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/GithubApplicationClientImplTest.java
@@ -36,7 +36,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.slf4j.event.Level;
-import org.sonar.alm.client.github.ApplicationHttpClient.RateLimit;
+import org.sonar.alm.client.ApplicationHttpClient.RateLimit;
import org.sonar.alm.client.github.api.GsonRepositoryCollaborator;
import org.sonar.alm.client.github.api.GsonRepositoryTeam;
import org.sonar.alm.client.github.config.GithubAppConfiguration;
@@ -68,7 +68,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.sonar.alm.client.github.ApplicationHttpClient.GetResponse;
+import static org.sonar.alm.client.ApplicationHttpClient.GetResponse;
@RunWith(DataProviderRunner.class)
public class GithubApplicationClientImplTest {
@@ -114,12 +114,12 @@ public class GithubApplicationClientImplTest {
@ClassRule
public static LogTester logTester = new LogTester().setLevel(LoggerLevel.WARN);
- private GenericApplicationHttpClient httpClient = mock();
+ private GithubApplicationHttpClient githubApplicationHttpClient = mock();
private GithubAppSecurity appSecurity = mock();
private GithubAppConfiguration githubAppConfiguration = mock();
private GitHubSettings gitHubSettings = mock();
- private PaginatedHttpClient githubPaginatedHttpClient = mock();
+ private GithubPaginatedHttpClient githubPaginatedHttpClient = mock();
private AppInstallationToken appInstallationToken = mock();
private GithubApplicationClient underTest;
@@ -129,7 +129,7 @@ public class GithubApplicationClientImplTest {
@Before
public void setup() {
when(githubAppConfiguration.getApiEndpoint()).thenReturn(appUrl);
- underTest = new GithubApplicationClientImpl(httpClient, appSecurity, gitHubSettings, githubPaginatedHttpClient);
+ underTest = new GithubApplicationClientImpl(githubApplicationHttpClient, appSecurity, gitHubSettings, githubPaginatedHttpClient);
logTester.clear();
}
@@ -179,7 +179,7 @@ public class GithubApplicationClientImplTest {
public void checkAppPermissions_IOException() throws IOException {
AppToken appToken = mockAppToken();
- when(httpClient.get(appUrl, appToken, "/app")).thenThrow(new IOException("OOPS"));
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app")).thenThrow(new IOException("OOPS"));
assertThatThrownBy(() -> underTest.checkAppPermissions(githubAppConfiguration))
.isInstanceOf(IllegalArgumentException.class)
@@ -191,7 +191,7 @@ public class GithubApplicationClientImplTest {
public void checkAppPermissions_ErrorCodes(int errorCode, String expectedMessage) throws IOException {
AppToken appToken = mockAppToken();
- when(httpClient.get(appUrl, appToken, "/app")).thenReturn(new ErrorGetResponse(errorCode, null));
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app")).thenReturn(new ErrorGetResponse(errorCode, null));
assertThatThrownBy(() -> underTest.checkAppPermissions(githubAppConfiguration))
.isInstanceOf(IllegalArgumentException.class)
@@ -211,7 +211,7 @@ public class GithubApplicationClientImplTest {
public void checkAppPermissions_MissingPermissions() throws IOException {
AppToken appToken = mockAppToken();
- when(httpClient.get(appUrl, appToken, "/app")).thenReturn(new OkGetResponse("{}"));
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app")).thenReturn(new OkGetResponse("{}"));
assertThatThrownBy(() -> underTest.checkAppPermissions(githubAppConfiguration))
.isInstanceOf(IllegalArgumentException.class)
@@ -230,7 +230,7 @@ public class GithubApplicationClientImplTest {
+ " }\n"
+ "}";
- when(httpClient.get(appUrl, appToken, "/app")).thenReturn(new OkGetResponse(json));
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app")).thenReturn(new OkGetResponse(json));
assertThatThrownBy(() -> underTest.checkAppPermissions(githubAppConfiguration))
.isInstanceOf(IllegalArgumentException.class)
@@ -249,7 +249,7 @@ public class GithubApplicationClientImplTest {
+ " }\n"
+ "}";
- when(httpClient.get(appUrl, appToken, "/app")).thenReturn(new OkGetResponse(json));
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app")).thenReturn(new OkGetResponse(json));
assertThatCode(() -> underTest.checkAppPermissions(githubAppConfiguration)).isNull();
}
@@ -258,7 +258,7 @@ public class GithubApplicationClientImplTest {
public void getInstallationId_returns_installation_id_of_given_account() throws IOException {
AppToken appToken = new AppToken(APP_JWT_TOKEN);
when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken);
- when(httpClient.get(appUrl, appToken, "/repos/torvalds/linux/installation"))
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/repos/torvalds/linux/installation"))
.thenReturn(new OkGetResponse("{" +
" \"id\": 2," +
" \"account\": {" +
@@ -281,7 +281,7 @@ public class GithubApplicationClientImplTest {
public void getInstallationId_return_empty_if_no_installation_found_for_githubAccount() throws IOException {
AppToken appToken = new AppToken(APP_JWT_TOKEN);
when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken);
- when(httpClient.get(appUrl, appToken, "/repos/torvalds/linux/installation"))
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/repos/torvalds/linux/installation"))
.thenReturn(new ErrorGetResponse(404, null));
assertThat(underTest.getInstallationId(githubAppConfiguration, "torvalds")).isEmpty();
@@ -290,44 +290,44 @@ public class GithubApplicationClientImplTest {
@Test
@UseDataProvider("githubServers")
public void createUserAccessToken_returns_empty_if_access_token_cant_be_created(String apiUrl, String appUrl) throws IOException {
- when(httpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
+ when(githubApplicationHttpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
.thenReturn(new Response(400, null));
assertThatThrownBy(() -> underTest.createUserAccessToken(appUrl, "clientId", "clientSecret", "code"))
.isInstanceOf(IllegalStateException.class);
- verify(httpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
+ verify(githubApplicationHttpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
}
@Test
@UseDataProvider("githubServers")
public void createUserAccessToken_fail_if_access_token_request_fails(String apiUrl, String appUrl) throws IOException {
- when(httpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
+ when(githubApplicationHttpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
.thenThrow(new IOException("OOPS"));
assertThatThrownBy(() -> underTest.createUserAccessToken(apiUrl, "clientId", "clientSecret", "code"))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Failed to create GitHub's user access token");
- verify(httpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
+ verify(githubApplicationHttpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
}
@Test
@UseDataProvider("githubServers")
public void createUserAccessToken_throws_illegal_argument_exception_if_access_token_code_is_expired(String apiUrl, String appUrl) throws IOException {
- when(httpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
+ when(githubApplicationHttpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
.thenReturn(new OkGetResponse("error_code=100&error=expired_or_invalid"));
assertThatThrownBy(() -> underTest.createUserAccessToken(apiUrl, "clientId", "clientSecret", "code"))
.isInstanceOf(IllegalArgumentException.class);
- verify(httpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
+ verify(githubApplicationHttpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
}
@Test
@UseDataProvider("githubServers")
public void createUserAccessToken_from_authorization_code_returns_access_token(String apiUrl, String appUrl) throws IOException {
String token = randomAlphanumeric(10);
- when(httpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
+ when(githubApplicationHttpClient.post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code"))
.thenReturn(new OkGetResponse("access_token=" + token + "&status="));
UserAccessToken userAccessToken = underTest.createUserAccessToken(apiUrl, "clientId", "clientSecret", "code");
@@ -335,14 +335,14 @@ public class GithubApplicationClientImplTest {
assertThat(userAccessToken)
.extracting(UserAccessToken::getValue, UserAccessToken::getAuthorizationHeaderPrefix)
.containsOnly(token, "token");
- verify(httpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
+ verify(githubApplicationHttpClient).post(appUrl, null, "/login/oauth/access_token?client_id=clientId&client_secret=clientSecret&code=code");
}
@Test
public void getApp_returns_id() throws IOException {
AppToken appToken = new AppToken(APP_JWT_TOKEN);
when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken);
- when(httpClient.get(appUrl, appToken, "/app"))
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app"))
.thenReturn(new OkGetResponse("{\"installations_count\": 2}"));
assertThat(underTest.getApp(githubAppConfiguration).getInstallationsCount()).isEqualTo(2L);
@@ -352,7 +352,7 @@ public class GithubApplicationClientImplTest {
public void getApp_whenStatusCodeIsNotOk_shouldThrowHttpException() throws IOException {
AppToken appToken = new AppToken(APP_JWT_TOKEN);
when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken);
- when(httpClient.get(appUrl, appToken, "/app"))
+ when(githubApplicationHttpClient.get(appUrl, appToken, "/app"))
.thenReturn(new ErrorGetResponse(418, "I'm a teapot"));
assertThatThrownBy(() -> underTest.getApp(githubAppConfiguration))
@@ -378,7 +378,7 @@ public class GithubApplicationClientImplTest {
String appUrl = "https://github.sonarsource.com";
AccessToken accessToken = new UserAccessToken(randomAlphanumeric(10));
- when(httpClient.get(appUrl, accessToken, String.format("/user/installations?page=%s&per_page=%s", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/user/installations?page=%s&per_page=%s", 1, 100)))
.thenThrow(new IOException("OOPS"));
assertThatThrownBy(() -> underTest.listOrganizations(appUrl, accessToken, 1, 100))
@@ -413,7 +413,7 @@ public class GithubApplicationClientImplTest {
+ " \"total_count\": 0\n"
+ "} ";
- when(httpClient.get(appUrl, accessToken, String.format("/user/installations?page=%s&per_page=%s", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/user/installations?page=%s&per_page=%s", 1, 100)))
.thenReturn(new OkGetResponse(responseJson));
GithubApplicationClient.Organizations organizations = underTest.listOrganizations(appUrl, accessToken, 1, 100);
@@ -504,7 +504,7 @@ public class GithubApplicationClientImplTest {
+ " ]\n"
+ "} ";
- when(httpClient.get(appUrl, accessToken, String.format("/user/installations?page=%s&per_page=%s", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/user/installations?page=%s&per_page=%s", 1, 100)))
.thenReturn(new OkGetResponse(responseJson));
GithubApplicationClient.Organizations organizations = underTest.listOrganizations(appUrl, accessToken, 1, 100);
@@ -581,18 +581,14 @@ public class GithubApplicationClientImplTest {
}
@Test
- public void getWhitelistedGithubAppInstallations_whenGithubReturnsError_shouldThrow() throws IOException {
+ public void getWhitelistedGithubAppInstallations_whenGithubReturnsError_shouldReThrow() {
AppToken appToken = new AppToken(APP_JWT_TOKEN);
when(appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey())).thenReturn(appToken);
- when(githubPaginatedHttpClient.get(any(), any(), any(), any())).thenThrow(new IOException("io exception"));
+ when(githubPaginatedHttpClient.get(any(), any(), any(), any())).thenThrow(new IllegalStateException("exception"));
assertThatThrownBy(() -> underTest.getWhitelistedGithubAppInstallations(githubAppConfiguration))
.isInstanceOf(IllegalStateException.class)
- .hasMessage(
- "SonarQube was not able to retrieve resources from GitHub. "
- + "This is likely due to a connectivity problem or a temporary network outage: "
- + "Error while executing a paginated call to GitHub - appUrl: Any URL, path: /app/installations. io exception"
- );
+ .hasMessage("exception");
}
@Test
@@ -600,7 +596,7 @@ public class GithubApplicationClientImplTest {
String appUrl = "https://github.sonarsource.com";
AccessToken accessToken = new UserAccessToken(randomAlphanumeric(10));
- when(httpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "org:test", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "org:test", 1, 100)))
.thenThrow(new IOException("OOPS"));
assertThatThrownBy(() -> underTest.listRepositories(appUrl, accessToken, "test", null, 1, 100))
@@ -635,7 +631,7 @@ public class GithubApplicationClientImplTest {
+ " \"total_count\": 0\n"
+ "}";
- when(httpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "fork:true+org:github", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "fork:true+org:github", 1, 100)))
.thenReturn(new OkGetResponse(responseJson));
GithubApplicationClient.Repositories repositories = underTest.listRepositories(appUrl, accessToken, "github", null, 1, 100);
@@ -723,7 +719,7 @@ public class GithubApplicationClientImplTest {
+ " ]\n"
+ "}";
- when(httpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "fork:true+org:github", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "fork:true+org:github", 1, 100)))
.thenReturn(new OkGetResponse(responseJson));
GithubApplicationClient.Repositories repositories = underTest.listRepositories(appUrl, accessToken, "github", null, 1, 100);
@@ -778,7 +774,7 @@ public class GithubApplicationClientImplTest {
+ " ]\n"
+ "}";
- when(httpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "world+fork:true+org:github", 1, 100)))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, String.format("/search/repositories?q=%s&page=%s&per_page=%s", "world+fork:true+org:github", 1, 100)))
.thenReturn(new GetResponse() {
@Override
public Optional<String> getNextEndPoint() {
@@ -811,7 +807,7 @@ public class GithubApplicationClientImplTest {
@Test
public void getRepository_returns_empty_when_repository_doesnt_exist() throws IOException {
- when(httpClient.get(any(), any(), any()))
+ when(githubApplicationHttpClient.get(any(), any(), any()))
.thenReturn(new Response(404, null));
Optional<GithubApplicationClient.Repository> repository = underTest.getRepository(appUrl, new UserAccessToken("temp"), "octocat/Hello-World");
@@ -823,7 +819,7 @@ public class GithubApplicationClientImplTest {
public void getRepository_fails_on_failure() throws IOException {
String repositoryKey = "octocat/Hello-World";
- when(httpClient.get(any(), any(), any()))
+ when(githubApplicationHttpClient.get(any(), any(), any()))
.thenThrow(new IOException("OOPS"));
UserAccessToken token = new UserAccessToken("temp");
@@ -974,7 +970,7 @@ public class GithubApplicationClientImplTest {
+ " }"
+ "}";
- when(httpClient.get(appUrl, accessToken, "/repos/octocat/Hello-World"))
+ when(githubApplicationHttpClient.get(appUrl, accessToken, "/repos/octocat/Hello-World"))
.thenReturn(new GetResponse() {
@Override
public Optional<String> getNextEndPoint() {
@@ -1022,7 +1018,7 @@ public class GithubApplicationClientImplTest {
@Test
public void createAppInstallationToken_returns_empty_if_post_throws_IOE() throws IOException {
mockAppToken();
- when(httpClient.post(anyString(), any(AccessToken.class), anyString())).thenThrow(IOException.class);
+ when(githubApplicationHttpClient.post(anyString(), any(AccessToken.class), anyString())).thenThrow(IOException.class);
Optional<AppInstallationToken> accessToken = underTest.createAppInstallationToken(githubAppConfiguration, INSTALLATION_ID);
assertThat(accessToken).isEmpty();
@@ -1037,7 +1033,7 @@ public class GithubApplicationClientImplTest {
Optional<AppInstallationToken> accessToken = underTest.createAppInstallationToken(githubAppConfiguration, INSTALLATION_ID);
assertThat(accessToken).isEmpty();
- verify(httpClient).post(appUrl, appToken, "/app/installations/" + INSTALLATION_ID + "/access_tokens");
+ verify(githubApplicationHttpClient).post(appUrl, appToken, "/app/installations/" + INSTALLATION_ID + "/access_tokens");
}
@Test
@@ -1048,7 +1044,7 @@ public class GithubApplicationClientImplTest {
Optional<AppInstallationToken> accessToken = underTest.createAppInstallationToken(githubAppConfiguration, INSTALLATION_ID);
assertThat(accessToken).hasValue(installToken);
- verify(httpClient).post(appUrl, appToken, "/app/installations/" + INSTALLATION_ID + "/access_tokens");
+ verify(githubApplicationHttpClient).post(appUrl, appToken, "/app/installations/" + INSTALLATION_ID + "/access_tokens");
}
@Test
@@ -1067,18 +1063,12 @@ public class GithubApplicationClientImplTest {
}
@Test
- public void getRepositoryTeams_whenGitHubCallThrowsIOException_shouldLogAndThrow() throws IOException {
- when(githubPaginatedHttpClient.get(eq(APP_URL), eq(appInstallationToken), eq(REPO_TEAMS_ENDPOINT), any())).thenThrow(new IOException("error"));
+ public void getRepositoryTeams_whenGitHubCallThrowsException_shouldRethrow() {
+ when(githubPaginatedHttpClient.get(eq(APP_URL), eq(appInstallationToken), eq(REPO_TEAMS_ENDPOINT), any())).thenThrow(new IllegalStateException("error"));
assertThatIllegalStateException()
.isThrownBy(() -> underTest.getRepositoryTeams(APP_URL, appInstallationToken, ORG_NAME, REPO_NAME))
- .isInstanceOf(IllegalStateException.class)
- .withMessage(
- "SonarQube was not able to retrieve resources from GitHub. This is likely due to a connectivity problem or a temporary network outage: Error while executing a paginated call to GitHub - appUrl: https://github.com/, path: /repos/ORG_NAME/repo1/teams. error");
-
- assertThat(logTester.logs()).hasSize(1);
- assertThat(logTester.logs(Level.WARN))
- .containsExactly("Error while executing a paginated call to GitHub - appUrl: https://github.com/, path: /repos/ORG_NAME/repo1/teams.");
+ .withMessage("error");
}
private static List<GsonRepositoryTeam> expectedTeams() {
@@ -1104,19 +1094,12 @@ public class GithubApplicationClientImplTest {
}
@Test
- public void getRepositoryCollaborators_whenGitHubCallThrowsIOException_shouldLogAndThrow() throws IOException {
- when(githubPaginatedHttpClient.get(eq(APP_URL), eq(appInstallationToken), eq(REPO_COLLABORATORS_ENDPOINT), any())).thenThrow(new IOException("error"));
+ public void getRepositoryCollaborators_whenGitHubCallThrowsException_shouldRethrow() {
+ when(githubPaginatedHttpClient.get(eq(APP_URL), eq(appInstallationToken), eq(REPO_COLLABORATORS_ENDPOINT), any())).thenThrow(new IllegalStateException("error"));
assertThatIllegalStateException()
.isThrownBy(() -> underTest.getRepositoryCollaborators(APP_URL, appInstallationToken, ORG_NAME, REPO_NAME))
- .isInstanceOf(IllegalStateException.class)
- .withMessage(
- "SonarQube was not able to retrieve resources from GitHub. This is likely due to a connectivity problem or a temporary network outage: "
- + "Error while executing a paginated call to GitHub - appUrl: https://github.com/, path: /repos/ORG_NAME/repo1/collaborators?affiliation=direct. error");
-
- assertThat(logTester.logs()).hasSize(1);
- assertThat(logTester.logs(Level.WARN))
- .containsExactly("Error while executing a paginated call to GitHub - appUrl: https://github.com/, path: /repos/ORG_NAME/repo1/collaborators?affiliation=direct.");
+ .withMessage("error");
}
private static String getResponseContent(String path) throws IOException {
@@ -1133,7 +1116,7 @@ public class GithubApplicationClientImplTest {
Response response = mock(Response.class);
when(response.getContent()).thenReturn(Optional.empty());
when(response.getCode()).thenReturn(HTTP_UNAUTHORIZED);
- when(httpClient.post(eq(appUrl), any(AppToken.class), eq("/app/installations/" + INSTALLATION_ID + "/access_tokens"))).thenReturn(response);
+ when(githubApplicationHttpClient.post(eq(appUrl), any(AppToken.class), eq("/app/installations/" + INSTALLATION_ID + "/access_tokens"))).thenReturn(response);
}
private AppToken mockAppToken() {
@@ -1149,7 +1132,7 @@ public class GithubApplicationClientImplTest {
" \"token\": \"" + token + "\"" +
"}"));
when(response.getCode()).thenReturn(HTTP_CREATED);
- when(httpClient.post(eq(appUrl), any(AppToken.class), eq("/app/installations/" + INSTALLATION_ID + "/access_tokens"))).thenReturn(response);
+ when(githubApplicationHttpClient.post(eq(appUrl), any(AppToken.class), eq("/app/installations/" + INSTALLATION_ID + "/access_tokens"))).thenReturn(response);
return new AppInstallationToken(token);
}
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabHttpClientTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java
index 48c0b2d0067..4ec9f5d33fe 100644
--- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabHttpClientTest.java
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java
@@ -20,31 +20,46 @@
package org.sonar.alm.client.gitlab;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
+import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.slf4j.event.Level;
import org.sonar.alm.client.ConstantTimeoutConfiguration;
import org.sonar.alm.client.TimeoutConfiguration;
import org.sonar.api.testfixtures.log.LogTester;
+import org.sonar.auth.gitlab.GsonGroup;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-public class GitlabHttpClientTest {
+public class GitlabApplicationClientTest {
@Rule
public LogTester logTester = new LogTester();
+
+ private GitlabPaginatedHttpClient gitlabPaginatedHttpClient = mock();
+
private final MockWebServer server = new MockWebServer();
- private GitlabHttpClient underTest;
+ private GitlabApplicationClient underTest;
private String gitlabUrl;
@Before
@@ -54,7 +69,7 @@ public class GitlabHttpClientTest {
gitlabUrl = urlWithEndingSlash.substring(0, urlWithEndingSlash.length() - 1);
TimeoutConfiguration timeoutConfiguration = new ConstantTimeoutConfiguration(10_000);
- underTest = new GitlabHttpClient(timeoutConfiguration);
+ underTest = new GitlabApplicationClient(gitlabPaginatedHttpClient, timeoutConfiguration);
}
@After
@@ -523,4 +538,52 @@ public class GitlabHttpClientTest {
+ "] " +
"failed with error message : [Failed to connect to " + server.getHostName());
}
+
+ @Test
+ public void getGroups_whenCallIsInError_rethrows() throws IOException {
+ String token = "token-toto";
+ GitlabToken gitlabToken = new GitlabToken(token);
+ when(gitlabPaginatedHttpClient.get(eq(gitlabUrl), eq(gitlabToken), eq("/groups"), any())).thenThrow(new IllegalStateException("exception"));
+
+ assertThatIllegalStateException()
+ .isThrownBy(() -> underTest.getGroups(gitlabUrl, token))
+ .withMessage("exception");
+ }
+
+ @Test
+ public void getGroups_whenCallIsSuccessful_deserializesAndReturnsCorrectlyGroups() throws IOException {
+ ArgumentCaptor<Function<String, List<GsonGroup>>> deserializerCaptor = ArgumentCaptor.forClass(Function.class);
+
+ String token = "token-toto";
+ GitlabToken gitlabToken = new GitlabToken(token);
+ List<GsonGroup> expectedGroups = expectedGroups();
+ when(gitlabPaginatedHttpClient.get(eq(gitlabUrl), eq(gitlabToken), eq("/groups"), deserializerCaptor.capture())).thenReturn(expectedGroups);
+
+ Set<GsonGroup> groups = underTest.getGroups(gitlabUrl, token);
+ assertThat(groups).containsExactlyInAnyOrderElementsOf(expectedGroups);
+
+ String responseContent = getResponseContent("groups-full-response.json");
+
+ List<GsonGroup> deserializedGroups = deserializerCaptor.getValue().apply(responseContent);
+ assertThat(deserializedGroups).usingRecursiveComparison().isEqualTo(expectedGroups);
+ }
+
+ private static List<GsonGroup> expectedGroups() {
+ GsonGroup gsonGroup = createGsonGroup("56232243", "sonarsource/cfamily", "this is a long description");
+ GsonGroup gsonGroup2 = createGsonGroup("78902256", "sonarsource/sonarqube/mmf-3052-ant1", "");
+ return List.of(gsonGroup, gsonGroup2);
+ }
+
+ private static GsonGroup createGsonGroup(String number, String fullPath, String description) {
+ GsonGroup gsonGroup = mock(GsonGroup.class);
+ when(gsonGroup.getId()).thenReturn(number);
+ when(gsonGroup.getFullPath()).thenReturn(fullPath);
+ when(gsonGroup.getDescription()).thenReturn(description);
+ return gsonGroup;
+ }
+
+ private static String getResponseContent(String path) throws IOException {
+ return IOUtils.toString(GitlabApplicationClientTest.class.getResourceAsStream(path), StandardCharsets.UTF_8);
+ }
+
}
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabGlobalSettingsValidatorTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabGlobalSettingsValidatorTest.java
index 6582f503024..13f1c4c9c47 100644
--- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabGlobalSettingsValidatorTest.java
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabGlobalSettingsValidatorTest.java
@@ -21,8 +21,6 @@ package org.sonar.alm.client.gitlab;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.sonar.alm.client.gitlab.GitlabGlobalSettingsValidator;
-import org.sonar.alm.client.gitlab.GitlabHttpClient;
import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.internal.Settings;
import org.sonar.db.alm.setting.AlmSettingDto;
@@ -37,7 +35,7 @@ public class GitlabGlobalSettingsValidatorTest {
private static final Encryption encryption = mock(Encryption.class);
private static final Settings settings = mock(Settings.class);
- private final GitlabHttpClient gitlabHttpClient = mock(GitlabHttpClient.class);
+ private final GitlabApplicationClient gitlabHttpClient = mock(GitlabApplicationClient.class);
private final GitlabGlobalSettingsValidator underTest = new GitlabGlobalSettingsValidator(gitlabHttpClient, settings);