]> source.dussan.org Git - sonarqube.git/blob
3cef1d97d1d3f4f90ca158a6883faabbfbc57811
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.server.v2.api.gitlab.config;
21
22 import com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.Set;
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;
44
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;
61
62 public class DefaultGitlabConfigurationControllerTest {
63   private static final Gson GSON = new GsonBuilder().create();
64
65   private static final GitlabConfiguration GITLAB_CONFIGURATION = new GitlabConfiguration(
66     "existing-id",
67     true,
68     "application-id",
69     "www.url.com",
70     "secret",
71     true,
72     Set.of("group1", "group2"),
73     true,
74     AUTO_PROVISIONING,
75     "provisioning-token"
76   );
77
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()),
87     "error-message");
88
89   private static final String EXPECTED_CONFIGURATION = """
90     {
91       "id": "existing-id",
92       "enabled": true,
93       "applicationId": "application-id",
94       "url": "www.url.com",
95       "synchronizeGroups": true,
96       "allowedGroups": [
97         "group1",
98         "group2"
99       ],
100       "provisioningType": "AUTO_PROVISIONING",
101       "allowUsersToSignUp": true,
102       "errorMessage": "error-message"
103     }
104     """;
105
106   @Rule
107   public UserSessionRule userSession = UserSessionRule.standalone();
108   private final GitlabConfigurationService gitlabConfigurationService = mock();
109   private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultGitlabConfigurationController(userSession, gitlabConfigurationService));
110
111   @Before
112   public void setUp() {
113     when(gitlabConfigurationService.validate(any())).thenReturn(Optional.of("error-message"));
114   }
115
116   @Test
117   public void fetchConfiguration_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
118     userSession.logIn().setNonSystemAdministrator();
119
120     mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/1"))
121       .andExpectAll(
122         status().isForbidden(),
123         content().json("{\"message\":\"Insufficient privileges\"}"));
124   }
125
126   @Test
127   public void fetchConfiguration_whenConfigNotFound_throws() throws Exception {
128     userSession.logIn().setSystemAdministrator();
129     when(gitlabConfigurationService.getConfiguration("not-existing")).thenThrow(new NotFoundException("bla"));
130
131     mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/not-existing"))
132       .andExpectAll(
133         status().isNotFound(),
134         content().json("{\"message\":\"bla\"}"));
135   }
136
137   @Test
138   public void fetchConfiguration_whenConfigFound_returnsIt() throws Exception {
139     userSession.logIn().setSystemAdministrator();
140     when(gitlabConfigurationService.getConfiguration("existing-id")).thenReturn(GITLAB_CONFIGURATION);
141
142     mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id"))
143       .andExpectAll(
144         status().isOk(),
145         content().json(EXPECTED_CONFIGURATION));
146   }
147
148   @Test
149   public void search_whenNoParameters_shouldUseDefaultAndForwardToGroupMembershipService() throws Exception {
150     userSession.logIn().setSystemAdministrator();
151     when(gitlabConfigurationService.findConfigurations()).thenReturn(Optional.of(GITLAB_CONFIGURATION));
152
153     MvcResult mvcResult = mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT))
154       .andExpect(status().isOk())
155       .andReturn();
156
157     GitlabConfigurationSearchRestResponse gitlabConfigurationResource = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GitlabConfigurationSearchRestResponse.class);
158
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);
163   }
164
165   @Test
166   public void search_whenNoParametersAndNoConfig_shouldReturnEmptyList() throws Exception {
167     userSession.logIn().setSystemAdministrator();
168     when(gitlabConfigurationService.findConfigurations()).thenReturn(Optional.empty());
169
170     MvcResult mvcResult = mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT))
171       .andExpect(status().isOk())
172       .andReturn();
173
174     GitlabConfigurationSearchRestResponse gitlabConfigurationResource = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GitlabConfigurationSearchRestResponse.class);
175
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();
180   }
181
182   @Test
183   public void updateConfiguration_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
184     userSession.logIn().setNonSystemAdministrator();
185
186     mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")
187       .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
188       .content("{}"))
189       .andExpectAll(
190         status().isForbidden(),
191         content().json("{\"message\":\"Insufficient privileges\"}"));
192   }
193
194   @Test
195   public void updateConfiguration_whenAllFieldsUpdated_performUpdates() throws Exception {
196     userSession.logIn().setSystemAdministrator();
197     when(gitlabConfigurationService.updateConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
198
199     String payload = """
200       {
201             "enabled": true,
202             "applicationId": "application-id",
203             "url": "www.url.com",
204             "secret": "newSecret",
205             "synchronizeGroups": true,
206             "allowedGroups": [
207               "group1",
208               "group2"
209             ],
210             "provisioningType": "AUTO_PROVISIONING",
211             "allowUsersToSignUp": true,
212             "provisioningToken": "token"
213       }
214       """;
215
216     mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")
217       .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
218       .content(payload))
219       .andExpectAll(
220         status().isOk(),
221         content().json(EXPECTED_CONFIGURATION));
222
223     verify(gitlabConfigurationService).updateConfiguration(new UpdateGitlabConfigurationRequest(
224       "existing-id",
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)
234     ));
235   }
236
237   @Test
238   public void updateConfiguration_whenSomeFieldsUpdated_performUpdates() throws Exception {
239     userSession.logIn().setSystemAdministrator();
240     when(gitlabConfigurationService.updateConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
241
242     String payload = """
243       {
244             "enabled": false,
245             "provisioningType": "JIT",
246             "allowUsersToSignUp": false,
247             "provisioningToken": null
248       }
249       """;
250
251     mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")
252       .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
253       .content(payload))
254       .andExpectAll(
255         status().isOk(),
256         content().json(EXPECTED_CONFIGURATION));
257
258     verify(gitlabConfigurationService).updateConfiguration(new UpdateGitlabConfigurationRequest(
259       "existing-id",
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)
266     ));
267   }
268
269   @Test
270   public void create_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
271     userSession.logIn().setNonSystemAdministrator();
272
273     mockMvc.perform(
274       post(GITLAB_CONFIGURATION_ENDPOINT)
275         .contentType(MediaType.APPLICATION_JSON_VALUE)
276         .content("""
277             {
278                "enabled": true,
279                "applicationId": "application-id",
280                "url": "www.url.com",
281                "secret": "123",
282                "synchronizeGroups": true,
283                "allowedGroups": [
284                   "group1",
285                   "group2"
286                 ],
287                "provisioningType": "AUTO_PROVISIONING",
288                "allowUsersToSignUp": true
289              }
290           """))
291       .andExpectAll(
292         status().isForbidden(),
293         content().json("{\"message\":\"Insufficient privileges\"}"));
294   }
295
296   @Test
297   public void create_whenConfigCreated_returnsIt() throws Exception {
298     userSession.logIn().setSystemAdministrator();
299     when(gitlabConfigurationService.createConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
300
301     mockMvc.perform(
302       post(GITLAB_CONFIGURATION_ENDPOINT)
303         .contentType(MediaType.APPLICATION_JSON_VALUE)
304         .content("""
305             {
306               "enabled": true,
307               "applicationId": "application-id",
308               "secret": "123",
309               "url": "www.url.com",
310               "synchronizeGroups": true,
311               "allowedGroups": [
312                 "group1",
313                 "group2"
314               ],
315               "provisioningType": "AUTO_PROVISIONING",
316               "allowUsersToSignUp": true
317             }
318
319           """))
320       .andExpectAll(
321         status().isOk(),
322         content().json("""
323           {
324             "id": "existing-id",
325             "enabled": true,
326             "applicationId": "application-id",
327             "url": "www.url.com",
328             "synchronizeGroups": true,
329             "allowedGroups": [
330               "group1",
331               "group2"
332             ],
333             "provisioningType": "AUTO_PROVISIONING",
334             "allowUsersToSignUp": true
335           }
336           """));
337
338   }
339   @Test
340   public void create_whenConfigCreatedWithoutOptionalParams_returnsIt() throws Exception {
341     userSession.logIn().setSystemAdministrator();
342     when(gitlabConfigurationService.createConfiguration(any())).thenReturn(GITLAB_CONFIGURATION);
343
344     mockMvc.perform(
345       post(GITLAB_CONFIGURATION_ENDPOINT)
346         .contentType(MediaType.APPLICATION_JSON_VALUE)
347         .content("""
348             {
349               "enabled": true,
350               "applicationId": "application-id",
351               "secret": "123",
352               "url": "www.url.com",
353               "synchronizeGroups": true,
354               "allowedGroups": [
355                 "group1",
356                 "group2"
357               ],
358               "provisioningType": "AUTO_PROVISIONING"
359             }
360
361           """))
362       .andExpectAll(
363         status().isOk(),
364         content().json("""
365           {
366             "id": "existing-id",
367             "enabled": true,
368             "applicationId": "application-id",
369             "url": "www.url.com",
370             "synchronizeGroups": true,
371             "allowedGroups": [
372               "group1",
373               "group2"
374             ],
375             "provisioningType": "AUTO_PROVISIONING",
376             "allowUsersToSignUp": true
377           }
378           """));
379
380   }
381
382   @Test
383   public void create_whenRequiredParameterIsMissing_shouldReturnBadRequest() throws Exception {
384     userSession.logIn().setSystemAdministrator();
385
386     mockMvc.perform(
387       post(GITLAB_CONFIGURATION_ENDPOINT)
388         .contentType(MediaType.APPLICATION_JSON_VALUE)
389         .content("""
390           {
391             "enabled": true,
392             "applicationId": "application-id",
393             "url": "www.url.com",
394             "synchronizeGroups": true,
395             "allowedGroups": [
396               "group1",
397               "group2"
398             ],
399             "provisioningType": "AUTO_PROVISIONING",
400             "allowUsersToSignUp": true
401           }
402           """))
403       .andExpectAll(
404         status().isBadRequest(),
405         content().json(
406           "{\"message\":\"Value {} for field secret was rejected. Error: must not be empty.\"}"));
407
408   }
409
410   @Test
411   public void delete_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
412     userSession.logIn().setNonSystemAdministrator();
413
414     mockMvc.perform(
415       delete(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id"))
416       .andExpectAll(
417         status().isForbidden(),
418         content().json("{\"message\":\"Insufficient privileges\"}"));
419   }
420
421   @Test
422   public void delete_whenConfigIsDeleted_returnsNoContent() throws Exception {
423     userSession.logIn().setSystemAdministrator();
424
425     mockMvc.perform(
426       delete(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id"))
427       .andExpectAll(
428         status().isNoContent());
429
430     verify(gitlabConfigurationService).deleteConfiguration("existing-id");
431   }
432
433   @Test
434   public void delete_whenConfigNotFound_returnsNotFound() throws Exception {
435     userSession.logIn().setSystemAdministrator();
436     doThrow(new NotFoundException("Not found")).when(gitlabConfigurationService).deleteConfiguration("not-existing");
437
438     mockMvc.perform(
439       delete(GITLAB_CONFIGURATION_ENDPOINT + "/not-existing"))
440       .andExpectAll(
441         status().isNotFound(),
442         content().json("{\"message\":\"Not found\"}"));
443   }
444
445 }