]> source.dussan.org Git - sonarqube.git/blob
ccad66c8998bd73dc317f3ff6972db77836aa132
[sonarqube.git] /
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.server.v2.api.user.controller;
21
22 import com.google.gson.Gson;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.stream.IntStream;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.mockito.ArgumentCaptor;
30 import org.sonar.db.user.UserDto;
31 import org.sonar.server.common.SearchResults;
32 import org.sonar.server.common.user.service.UserSearchResult;
33 import org.sonar.server.common.user.service.UserService;
34 import org.sonar.server.common.user.service.UsersSearchRequest;
35 import org.sonar.server.exceptions.BadRequestException;
36 import org.sonar.server.exceptions.NotFoundException;
37 import org.sonar.server.tester.UserSessionRule;
38 import org.sonar.server.v2.api.ControllerTester;
39 import org.sonar.server.v2.api.response.PageRestResponse;
40 import org.sonar.server.v2.api.user.converter.UsersSearchRestResponseGenerator;
41 import org.sonar.server.v2.api.user.model.RestUser;
42 import org.sonar.server.v2.api.user.response.UsersSearchRestResponse;
43 import org.springframework.test.web.servlet.MockMvc;
44 import org.springframework.test.web.servlet.MvcResult;
45
46 import static org.assertj.core.api.Assertions.assertThat;
47 import static org.mockito.ArgumentMatchers.any;
48 import static org.mockito.ArgumentMatchers.eq;
49 import static org.mockito.Mockito.doThrow;
50 import static org.mockito.Mockito.mock;
51 import static org.mockito.Mockito.verify;
52 import static org.mockito.Mockito.when;
53 import static org.sonar.api.utils.DateUtils.formatDateTime;
54 import static org.sonar.server.v2.WebApiEndpoints.USER_ENDPOINT;
55 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_INDEX;
56 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_SIZE;
57 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
58 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
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 DefaultUserControllerTest {
63
64   @Rule
65   public UserSessionRule userSession = UserSessionRule.standalone();
66   private final UserService userService = mock(UserService.class);
67   private final UsersSearchRestResponseGenerator responseGenerator = mock(UsersSearchRestResponseGenerator.class);
68   private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultUserController(userSession, userService, responseGenerator));
69
70   private static final Gson gson = new Gson();
71
72   @Test
73   public void search_whenNoParameters_shouldUseDefaultAndForwardToUserService() throws Exception {
74     when(userService.findUsers(any())).thenReturn(new SearchResults<>(List.of(), 0));
75
76     mockMvc.perform(get(USER_ENDPOINT))
77       .andExpect(status().isOk());
78
79     ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
80     verify(userService).findUsers(requestCaptor.capture());
81     assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(Integer.valueOf(DEFAULT_PAGE_SIZE));
82     assertThat(requestCaptor.getValue().getPage()).isEqualTo(Integer.valueOf(DEFAULT_PAGE_INDEX));
83     assertThat(requestCaptor.getValue().isDeactivated()).isFalse();
84   }
85
86   @Test
87   public void search_whenParametersUsed_shouldForwardWithParameters() throws Exception {
88     when(userService.findUsers(any())).thenReturn(new SearchResults<>(List.of(), 0));
89     userSession.logIn().setSystemAdministrator();
90
91     mockMvc.perform(get(USER_ENDPOINT)
92         .param("active", "false")
93         .param("managed", "true")
94         .param("q", "q")
95         .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
96         .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100")
97         .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
98         .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100")
99         .param("pageSize", "100")
100         .param("pageIndex", "2"))
101       .andExpect(status().isOk());
102
103     ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
104     verify(userService).findUsers(requestCaptor.capture());
105     assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(100);
106     assertThat(requestCaptor.getValue().getPage()).isEqualTo(2);
107     assertThat(requestCaptor.getValue().isDeactivated()).isTrue();
108   }
109
110   @Test
111   public void search_whenAdminParametersUsedButNotAdmin_shouldFail() throws Exception {
112     mockMvc.perform(get(USER_ENDPOINT)
113       .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
114       .andExpectAll(
115         status().isForbidden(),
116         content().string("{\"message\":\"parameter sonarQubeLastConnectionDateFrom requires Administer System permission.\"}"));
117
118     mockMvc.perform(get(USER_ENDPOINT)
119       .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
120       .andExpectAll(
121         status().isForbidden(),
122         content().string("{\"message\":\"parameter sonarQubeLastConnectionDateTo requires Administer System permission.\"}"));
123
124     mockMvc.perform(get(USER_ENDPOINT)
125       .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
126       .andExpectAll(
127         status().isForbidden(),
128         content().string("{\"message\":\"parameter sonarLintLastConnectionDateFrom requires Administer System permission.\"}"));
129
130     mockMvc.perform(get(USER_ENDPOINT)
131       .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
132       .andExpectAll(
133         status().isForbidden(),
134         content().string("{\"message\":\"parameter sonarLintLastConnectionDateTo requires Administer System permission.\"}"));
135   }
136
137   @Test
138   public void search_whenUserServiceReturnUsers_shouldReturnThem() throws Exception {
139     UserSearchResult user1 = generateUserSearchResult("user1", true, true, false, 2, 3);
140     UserSearchResult user2 = generateUserSearchResult("user2", true, false, false, 3, 0);
141     UserSearchResult user3 = generateUserSearchResult("user3", true, false, true, 1, 1);
142     UserSearchResult user4 = generateUserSearchResult("user4", false, true, false, 0, 0);
143     List<UserSearchResult> users = List.of(user1, user2, user3, user4);
144     SearchResults<UserSearchResult> searchResult = new SearchResults<>(users, users.size());
145     when(userService.findUsers(any())).thenReturn(searchResult);
146     List<RestUser> restUsers = List.of(toRestUser(user1), toRestUser(user2), toRestUser(user3), toRestUser(user4));
147     when(responseGenerator.toUsersForResponse(eq(searchResult.searchResults()), any())).thenReturn(new UsersSearchRestResponse(restUsers, new PageRestResponse(1, 50, 4)));
148     userSession.logIn().setSystemAdministrator();
149
150     MvcResult mvcResult = mockMvc.perform(get(USER_ENDPOINT))
151       .andExpect(status().isOk())
152       .andReturn();
153
154     UsersSearchRestResponse actualUsersSearchRestResponse = gson.fromJson(mvcResult.getResponse().getContentAsString(), UsersSearchRestResponse.class);
155     assertThat(actualUsersSearchRestResponse.users())
156       .containsExactlyElementsOf(restUsers);
157     assertThat(actualUsersSearchRestResponse.pageRestResponse().total()).isEqualTo(users.size());
158
159   }
160
161   private UserSearchResult generateUserSearchResult(String id, boolean active, boolean local, boolean managed, int groupsCount, int tokensCount) {
162     UserDto userDto = new UserDto()
163       .setLogin("login_" + id)
164       .setUuid("uuid_" + id)
165       .setName("name_" + id)
166       .setEmail(id + "@email.com")
167       .setActive(active)
168       .setLocal(local)
169       .setExternalLogin("externalLogin_" + id)
170       .setExternalId("externalId_" + id)
171       .setExternalIdentityProvider("externalIdentityProvider_" + id)
172       .setLastConnectionDate(0L)
173       .setLastSonarlintConnectionDate(1L);
174
175     List<String> groups = new ArrayList<>();
176     IntStream.range(1, groupsCount).forEach(i -> groups.add("group" + i));
177
178     return new UserSearchResult(userDto, managed, Optional.of("avatar_" + id), groups, tokensCount);
179   }
180
181   private RestUser toRestUser(UserSearchResult userSearchResult) {
182     return new RestUser(
183       userSearchResult.userDto().getLogin(),
184       userSearchResult.userDto().getLogin(),
185       userSearchResult.userDto().getName(),
186       userSearchResult.userDto().getEmail(),
187       userSearchResult.userDto().isActive(),
188       userSearchResult.userDto().isLocal(),
189       userSearchResult.managed(),
190       userSearchResult.userDto().getExternalLogin(),
191       userSearchResult.userDto().getExternalIdentityProvider(),
192       userSearchResult.avatar().orElse(""),
193       formatDateTime(userSearchResult.userDto().getLastConnectionDate()),
194       formatDateTime(userSearchResult.userDto().getLastSonarlintConnectionDate()),
195       userSearchResult.groups().size(),
196       userSearchResult.tokensCount(),
197       userSearchResult.userDto().getSortedScmAccounts());
198   }
199
200   @Test
201   public void deactivate_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
202     userSession.logIn().setNonSystemAdministrator();
203
204     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
205       .andExpectAll(
206         status().isForbidden(),
207         content().json("{\"message\":\"Insufficient privileges\"}"));
208   }
209
210   @Test
211   public void deactivate_whenUserServiceThrowsNotFoundException_shouldReturnNotFound() throws Exception {
212     userSession.logIn().setSystemAdministrator();
213     doThrow(new NotFoundException("User not found.")).when(userService).deactivate("userToDelete", false);
214
215     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
216       .andExpectAll(
217         status().isNotFound(),
218         content().json("{\"message\":\"User not found.\"}"));
219   }
220
221   @Test
222   public void deactivate_whenUserServiceThrowsBadRequestException_shouldReturnBadRequest() throws Exception {
223     userSession.logIn().setSystemAdministrator();
224     doThrow(BadRequestException.create("Not allowed")).when(userService).deactivate("userToDelete", false);
225
226     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
227       .andExpectAll(
228         status().isBadRequest(),
229         content().json("{\"message\":\"Not allowed\"}"));
230   }
231
232   @Test
233   public void deactivate_whenUserTryingToDeactivateThemself_shouldReturnBadRequest() throws Exception {
234     userSession.logIn("userToDelete").setSystemAdministrator();
235
236     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
237       .andExpectAll(
238         status().isBadRequest(),
239         content().json("{\"message\":\"Self-deactivation is not possible\"}"));
240   }
241
242   @Test
243   public void deactivate_whenAnonymizeParameterIsNotBoolean_shouldReturnBadRequest() throws Exception {
244     userSession.logIn().setSystemAdministrator();
245
246     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete?anonymize=maybe"))
247       .andExpect(
248         status().isBadRequest());
249   }
250
251   @Test
252   public void deactivate_whenAnonymizeIsNotSpecified_shouldDeactivateUserWithoutAnonymization() throws Exception {
253     userSession.logIn().setSystemAdministrator();
254
255     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
256       .andExpect(status().isNoContent());
257
258     verify(userService).deactivate("userToDelete", false);
259   }
260
261   @Test
262   public void deactivate_whenAnonymizeFalse_shouldDeactivateUserWithoutAnonymization() throws Exception {
263     userSession.logIn().setSystemAdministrator();
264
265     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "false"))
266       .andExpect(status().isNoContent());
267
268     verify(userService).deactivate("userToDelete", false);
269   }
270
271   @Test
272   public void deactivate_whenAnonymizeTrue_shouldDeactivateUserWithAnonymization() throws Exception {
273     userSession.logIn().setSystemAdministrator();
274
275     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "true"))
276       .andExpect(status().isNoContent());
277
278     verify(userService).deactivate("userToDelete", true);
279   }
280
281   @Test
282   public void fetchUser_whenUserServiceThrowsNotFoundException_returnsNotFound() throws Exception {
283     when(userService.fetchUser("userLogin")).thenThrow(new NotFoundException("Not found"));
284     mockMvc.perform(get(USER_ENDPOINT + "/userLogin"))
285       .andExpectAll(
286         status().isNotFound(),
287         content().json("{\"message\":\"Not found\"}")
288       );
289
290   }
291
292   @Test
293   public void fetchUser_whenUserExists_shouldReturnUser() throws Exception {
294     UserSearchResult user = generateUserSearchResult("user1", true, true, false, 2, 3);
295     RestUser restUser = toRestUser(user);
296     when(userService.fetchUser("userLogin")).thenReturn(user);
297     when(responseGenerator.toRestUser(user)).thenReturn(restUser);
298     MvcResult mvcResult = mockMvc.perform(get(USER_ENDPOINT + "/userLogin"))
299       .andExpect(status().isOk())
300       .andReturn();
301     RestUser responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestUser.class);
302     assertThat(responseUser).isEqualTo(restUser);
303
304   }
305 }