3 * Copyright (C) 2009-2024 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.server.v2.api.gitlab.config;
22 import com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import java.util.List;
25 import java.util.Optional;
27 import org.junit.Before;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.sonar.server.common.NonNullUpdatedValue;
31 import org.sonar.server.common.UpdatedValue;
32 import org.sonar.server.common.gitlab.config.GitlabConfiguration;
33 import org.sonar.server.common.gitlab.config.GitlabConfigurationService;
34 import org.sonar.server.common.gitlab.config.UpdateGitlabConfigurationRequest;
35 import org.sonar.server.exceptions.NotFoundException;
36 import org.sonar.server.tester.UserSessionRule;
37 import org.sonar.server.v2.api.ControllerTester;
38 import org.sonar.server.v2.api.gitlab.config.controller.DefaultGitlabConfigurationController;
39 import org.sonar.server.v2.api.gitlab.config.resource.GitlabConfigurationResource;
40 import org.sonar.server.v2.api.gitlab.config.response.GitlabConfigurationSearchRestResponse;
41 import org.springframework.http.MediaType;
42 import org.springframework.test.web.servlet.MockMvc;
43 import org.springframework.test.web.servlet.MvcResult;
45 import static org.assertj.core.api.Assertions.assertThat;
46 import static org.mockito.ArgumentMatchers.any;
47 import static org.mockito.Mockito.doThrow;
48 import static org.mockito.Mockito.mock;
49 import static org.mockito.Mockito.verify;
50 import static org.mockito.Mockito.when;
51 import static org.sonar.server.common.gitlab.config.ProvisioningType.AUTO_PROVISIONING;
52 import static org.sonar.server.common.gitlab.config.ProvisioningType.JIT;
53 import static org.sonar.server.v2.WebApiEndpoints.GITLAB_CONFIGURATION_ENDPOINT;
54 import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE;
55 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
56 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
57 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
58 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
59 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
60 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
62 public class DefaultGitlabConfigurationControllerTest {
63 private static final Gson GSON = new GsonBuilder().create();
65 private static final GitlabConfiguration GITLAB_CONFIGURATION = new GitlabConfiguration(
72 Set.of("group1", "group2"),
78 private static final GitlabConfigurationResource EXPECTED_GITLAB_CONF_RESOURCE = new GitlabConfigurationResource(
79 GITLAB_CONFIGURATION.id(),
80 GITLAB_CONFIGURATION.enabled(),
81 GITLAB_CONFIGURATION.applicationId(),
82 GITLAB_CONFIGURATION.url(),
83 GITLAB_CONFIGURATION.synchronizeGroups(),
84 List.of("group1", "group2"),
85 GITLAB_CONFIGURATION.allowUsersToSignUp(),
86 org.sonar.server.v2.api.gitlab.config.resource.ProvisioningType.valueOf(GITLAB_CONFIGURATION.provisioningType().name()),
89 private static final String EXPECTED_CONFIGURATION = """
93 "applicationId": "application-id",
95 "synchronizeGroups": true,
100 "provisioningType": "AUTO_PROVISIONING",
101 "allowUsersToSignUp": true,
102 "errorMessage": "error-message"
107 public UserSessionRule userSession = UserSessionRule.standalone();
108 private final GitlabConfigurationService gitlabConfigurationService = mock();
109 private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultGitlabConfigurationController(userSession, gitlabConfigurationService));
112 public void setUp() {
113 when(gitlabConfigurationService.validate(any())).thenReturn(Optional.of("error-message"));
117 public void fetchConfiguration_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
118 userSession.logIn().setNonSystemAdministrator();
120 mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/1"))
122 status().isForbidden(),
123 content().json("{\"message\":\"Insufficient privileges\"}"));
127 public void fetchConfiguration_whenConfigNotFound_throws() throws Exception {
128 userSession.logIn().setSystemAdministrator();
129 when(gitlabConfigurationService.getConfiguration("not-existing")).thenThrow(new NotFoundException("bla"));
131 mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/not-existing"))
133 status().isNotFound(),
134 content().json("{\"message\":\"bla\"}"));
138 public void fetchConfiguration_whenConfigFound_returnsIt() throws Exception {
139 userSession.logIn().setSystemAdministrator();
140 when(gitlabConfigurationService.getConfiguration("existing-id")).thenReturn(GITLAB_CONFIGURATION);
142 mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id"))
145 content().json(EXPECTED_CONFIGURATION));
149 public void search_whenNoParameters_shouldUseDefaultAndForwardToGroupMembershipService() throws Exception {
150 userSession.logIn().setSystemAdministrator();
151 when(gitlabConfigurationService.findConfigurations()).thenReturn(Optional.of(GITLAB_CONFIGURATION));
153 MvcResult mvcResult = mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT))
154 .andExpect(status().isOk())
157 GitlabConfigurationSearchRestResponse gitlabConfigurationResource = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GitlabConfigurationSearchRestResponse.class);
159 assertThat(gitlabConfigurationResource.page().pageSize()).isEqualTo(1000);
160 assertThat(gitlabConfigurationResource.page().pageIndex()).isEqualTo(1);
161 assertThat(gitlabConfigurationResource.page().total()).isEqualTo(1);
162 assertThat(gitlabConfigurationResource.gitlabConfigurations()).containsExactly(EXPECTED_GITLAB_CONF_RESOURCE);
166 public void search_whenNoParametersAndNoConfig_shouldReturnEmptyList() throws Exception {
167 userSession.logIn().setSystemAdministrator();
168 when(gitlabConfigurationService.findConfigurations()).thenReturn(Optional.empty());
170 MvcResult mvcResult = mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT))
171 .andExpect(status().isOk())
174 GitlabConfigurationSearchRestResponse gitlabConfigurationResource = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GitlabConfigurationSearchRestResponse.class);
176 assertThat(gitlabConfigurationResource.page().pageSize()).isEqualTo(1000);
177 assertThat(gitlabConfigurationResource.page().pageIndex()).isEqualTo(1);
178 assertThat(gitlabConfigurationResource.page().total()).isZero();
179 assertThat(gitlabConfigurationResource.gitlabConfigurations()).isEmpty();
183 public void updateConfiguration_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
184 userSession.logIn().setNonSystemAdministrator();
186 mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")
187 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
190 status().isForbidden(),
191 content().json("{\"message\":\"Insufficient privileges\"}"));
195 public void updateConfiguration_whenAllFieldsUpdated_performUpdates() throws Exception {
196 userSession.logIn().setSystemAdministrator();
197 when(gitlabConfigurationService.updateConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
202 "applicationId": "application-id",
203 "url": "www.url.com",
204 "secret": "newSecret",
205 "synchronizeGroups": true,
210 "provisioningType": "AUTO_PROVISIONING",
211 "allowUsersToSignUp": true,
212 "provisioningToken": "token"
216 mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")
217 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
221 content().json(EXPECTED_CONFIGURATION));
223 verify(gitlabConfigurationService).updateConfiguration(new UpdateGitlabConfigurationRequest(
225 NonNullUpdatedValue.withValueOrThrow(true),
226 NonNullUpdatedValue.withValueOrThrow("application-id"),
227 NonNullUpdatedValue.withValueOrThrow("www.url.com"),
228 NonNullUpdatedValue.withValueOrThrow("newSecret"),
229 NonNullUpdatedValue.withValueOrThrow(true),
230 NonNullUpdatedValue.withValueOrThrow(Set.of("group1", "group2")),
231 NonNullUpdatedValue.withValueOrThrow(true),
232 UpdatedValue.withValue("token"),
233 NonNullUpdatedValue.withValueOrThrow(AUTO_PROVISIONING)
238 public void updateConfiguration_whenSomeFieldsUpdated_performUpdates() throws Exception {
239 userSession.logIn().setSystemAdministrator();
240 when(gitlabConfigurationService.updateConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
245 "provisioningType": "JIT",
246 "allowUsersToSignUp": false,
247 "provisioningToken": null
251 mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")
252 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
256 content().json(EXPECTED_CONFIGURATION));
258 verify(gitlabConfigurationService).updateConfiguration(new UpdateGitlabConfigurationRequest(
260 NonNullUpdatedValue.withValueOrThrow(false),
261 NonNullUpdatedValue.undefined(),
262 NonNullUpdatedValue.undefined(),
263 NonNullUpdatedValue.undefined(),
264 NonNullUpdatedValue.undefined(),
265 NonNullUpdatedValue.undefined(), NonNullUpdatedValue.withValueOrThrow(false), UpdatedValue.withValue(null), NonNullUpdatedValue.withValueOrThrow(JIT)
270 public void create_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
271 userSession.logIn().setNonSystemAdministrator();
274 post(GITLAB_CONFIGURATION_ENDPOINT)
275 .contentType(MediaType.APPLICATION_JSON_VALUE)
279 "applicationId": "application-id",
280 "url": "www.url.com",
282 "synchronizeGroups": true,
287 "provisioningType": "AUTO_PROVISIONING",
288 "allowUsersToSignUp": true
292 status().isForbidden(),
293 content().json("{\"message\":\"Insufficient privileges\"}"));
297 public void create_whenConfigCreated_returnsIt() throws Exception {
298 userSession.logIn().setSystemAdministrator();
299 when(gitlabConfigurationService.createConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
302 post(GITLAB_CONFIGURATION_ENDPOINT)
303 .contentType(MediaType.APPLICATION_JSON_VALUE)
307 "applicationId": "application-id",
309 "url": "www.url.com",
310 "synchronizeGroups": true,
315 "provisioningType": "AUTO_PROVISIONING",
316 "allowUsersToSignUp": true
326 "applicationId": "application-id",
327 "url": "www.url.com",
328 "synchronizeGroups": true,
333 "provisioningType": "AUTO_PROVISIONING",
334 "allowUsersToSignUp": true
340 public void create_whenConfigCreatedWithoutOptionalParams_returnsIt() throws Exception {
341 userSession.logIn().setSystemAdministrator();
342 when(gitlabConfigurationService.createConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
345 post(GITLAB_CONFIGURATION_ENDPOINT)
346 .contentType(MediaType.APPLICATION_JSON_VALUE)
350 "applicationId": "application-id",
352 "url": "www.url.com",
353 "synchronizeGroups": true,
358 "provisioningType": "AUTO_PROVISIONING"
368 "applicationId": "application-id",
369 "url": "www.url.com",
370 "synchronizeGroups": true,
375 "provisioningType": "AUTO_PROVISIONING",
376 "allowUsersToSignUp": true
383 public void create_whenRequiredParameterIsMissing_shouldReturnBadRequest() throws Exception {
384 userSession.logIn().setSystemAdministrator();
387 post(GITLAB_CONFIGURATION_ENDPOINT)
388 .contentType(MediaType.APPLICATION_JSON_VALUE)
392 "applicationId": "application-id",
393 "url": "www.url.com",
394 "synchronizeGroups": true,
399 "provisioningType": "AUTO_PROVISIONING",
400 "allowUsersToSignUp": true
404 status().isBadRequest(),
406 "{\"message\":\"Value {} for field secret was rejected. Error: must not be empty.\"}"));
411 public void delete_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
412 userSession.logIn().setNonSystemAdministrator();
415 delete(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id"))
417 status().isForbidden(),
418 content().json("{\"message\":\"Insufficient privileges\"}"));
422 public void delete_whenConfigIsDeleted_returnsNoContent() throws Exception {
423 userSession.logIn().setSystemAdministrator();
426 delete(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id"))
428 status().isNoContent());
430 verify(gitlabConfigurationService).deleteConfiguration("existing-id");
434 public void delete_whenConfigNotFound_returnsNotFound() throws Exception {
435 userSession.logIn().setSystemAdministrator();
436 doThrow(new NotFoundException("Not found")).when(gitlabConfigurationService).deleteConfiguration("not-existing");
439 delete(GITLAB_CONFIGURATION_ENDPOINT + "/not-existing"))
441 status().isNotFound(),
442 content().json("{\"message\":\"Not found\"}"));