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.user.controller;
22 import com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import com.google.gson.TypeAdapter;
25 import com.google.gson.stream.JsonReader;
26 import com.google.gson.stream.JsonWriter;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Optional;
30 import java.util.stream.IntStream;
31 import org.junit.Rule;
32 import org.junit.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.sonar.db.user.UserDto;
35 import org.sonar.server.common.SearchResults;
36 import org.sonar.server.common.user.service.UserInformation;
37 import org.sonar.server.common.user.service.UserService;
38 import org.sonar.server.common.user.service.UsersSearchRequest;
39 import org.sonar.server.exceptions.BadRequestException;
40 import org.sonar.server.exceptions.NotFoundException;
41 import org.sonar.server.tester.UserSessionRule;
42 import org.sonar.server.user.UpdateUser;
43 import org.sonar.server.v2.api.ControllerTester;
44 import org.sonar.server.v2.api.model.RestError;
45 import org.sonar.server.v2.api.response.PageRestResponse;
46 import org.sonar.server.v2.api.user.converter.UsersSearchRestResponseGenerator;
47 import org.sonar.server.v2.api.user.response.UserRestResponse;
48 import org.sonar.server.v2.api.user.response.UserRestResponseForAdmins;
49 import org.sonar.server.v2.api.user.request.UserCreateRestRequest;
50 import org.sonar.server.v2.api.user.response.UsersSearchRestResponse;
51 import org.springframework.http.MediaType;
52 import org.springframework.test.web.servlet.MockMvc;
53 import org.springframework.test.web.servlet.MvcResult;
55 import static org.assertj.core.api.Assertions.assertThat;
56 import static org.mockito.ArgumentMatchers.any;
57 import static org.mockito.ArgumentMatchers.eq;
58 import static org.mockito.Mockito.doThrow;
59 import static org.mockito.Mockito.mock;
60 import static org.mockito.Mockito.verify;
61 import static org.mockito.Mockito.when;
62 import static org.sonar.api.utils.DateUtils.formatDateTime;
63 import static org.sonar.api.utils.DateUtils.parseOffsetDateTime;
64 import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE;
65 import static org.sonar.server.v2.WebApiEndpoints.USER_ENDPOINT;
66 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_INDEX;
67 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_SIZE;
68 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
69 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
70 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
71 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
72 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
73 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
75 public class DefaultUserControllerTest {
78 public UserSessionRule userSession = UserSessionRule.standalone();
79 private final UserService userService = mock(UserService.class);
80 private final UsersSearchRestResponseGenerator responseGenerator = mock(UsersSearchRestResponseGenerator.class);
81 private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultUserController(userSession, userService, responseGenerator));
83 private static final Gson gson = new GsonBuilder().registerTypeAdapter(UserRestResponse.class, new RestUserDeserializer()).create();
86 public void search_whenNoParameters_shouldUseDefaultAndForwardToUserService() throws Exception {
87 when(userService.findUsers(any())).thenReturn(new SearchResults<>(List.of(), 0));
89 mockMvc.perform(get(USER_ENDPOINT))
90 .andExpect(status().isOk());
92 ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
93 verify(userService).findUsers(requestCaptor.capture());
94 assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(Integer.valueOf(DEFAULT_PAGE_SIZE));
95 assertThat(requestCaptor.getValue().getPage()).isEqualTo(Integer.valueOf(DEFAULT_PAGE_INDEX));
96 assertThat(requestCaptor.getValue().isDeactivated()).isFalse();
100 public void search_whenParametersUsed_shouldForwardWithParameters() throws Exception {
101 when(userService.findUsers(any())).thenReturn(new SearchResults<>(List.of(), 0));
102 userSession.logIn().setSystemAdministrator();
104 mockMvc.perform(get(USER_ENDPOINT)
105 .param("active", "false")
106 .param("managed", "true")
108 .param("externalIdentity", "externalIdentity")
109 .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
110 .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100")
111 .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
112 .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100")
113 .param("groupId", "groupId1")
114 .param("groupId!", "groupId2")
115 .param("pageSize", "100")
116 .param("pageIndex", "2"))
117 .andExpect(status().isOk());
119 ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
120 verify(userService).findUsers(requestCaptor.capture());
122 assertThat(requestCaptor.getValue().isDeactivated()).isTrue();
123 assertThat(requestCaptor.getValue().isManaged()).isTrue();
124 assertThat(requestCaptor.getValue().getQuery()).isEqualTo("q");
125 assertThat(requestCaptor.getValue().getExternalLogin()).contains("externalIdentity");
126 assertThat(requestCaptor.getValue().getLastConnectionDateFrom()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
127 assertThat(requestCaptor.getValue().getLastConnectionDateTo()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
128 assertThat(requestCaptor.getValue().getSonarLintLastConnectionDateFrom()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
129 assertThat(requestCaptor.getValue().getSonarLintLastConnectionDateTo()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
130 assertThat(requestCaptor.getValue().getGroupUuid()).contains("groupId1");
131 assertThat(requestCaptor.getValue().getExcludedGroupUuid()).contains("groupId2");
132 assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(100);
133 assertThat(requestCaptor.getValue().getPage()).isEqualTo(2);
137 public void search_whenAdminParametersUsedButNotAdmin_shouldFail() throws Exception {
138 mockMvc.perform(get(USER_ENDPOINT)
139 .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
141 status().isForbidden(),
142 content().string("{\"message\":\"Parameter sonarQubeLastConnectionDateFrom requires Administer System permission.\"}"));
144 mockMvc.perform(get(USER_ENDPOINT)
145 .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
147 status().isForbidden(),
148 content().string("{\"message\":\"Parameter sonarQubeLastConnectionDateTo requires Administer System permission.\"}"));
150 mockMvc.perform(get(USER_ENDPOINT)
151 .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
153 status().isForbidden(),
154 content().string("{\"message\":\"Parameter sonarLintLastConnectionDateFrom requires Administer System permission.\"}"));
156 mockMvc.perform(get(USER_ENDPOINT)
157 .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
159 status().isForbidden(),
160 content().string("{\"message\":\"Parameter sonarLintLastConnectionDateTo requires Administer System permission.\"}"));
162 mockMvc.perform(get(USER_ENDPOINT)
163 .param("externalIdentity", "externalIdentity"))
165 status().isForbidden(),
166 content().string("{\"message\":\"Parameter externalIdentity requires Administer System permission.\"}"));
168 mockMvc.perform(get(USER_ENDPOINT)
169 .param("groupId", "groupId"))
171 status().isForbidden(),
172 content().string("{\"message\":\"Parameter groupId requires Administer System permission.\"}"));
174 mockMvc.perform(get(USER_ENDPOINT)
175 .param("groupId!", "groupId"))
177 status().isForbidden(),
178 content().string("{\"message\":\"Parameter groupId! requires Administer System permission.\"}"));
182 public void search_whenUserServiceReturnUsers_shouldReturnThem() throws Exception {
183 UserInformation user1 = generateUserSearchResult("user1", true, true, false, 2, 3);
184 UserInformation user2 = generateUserSearchResult("user2", true, false, false, 3, 0);
185 UserInformation user3 = generateUserSearchResult("user3", true, false, true, 1, 1);
186 UserInformation user4 = generateUserSearchResult("user4", false, true, false, 0, 0);
187 List<UserInformation> users = List.of(user1, user2, user3, user4);
188 SearchResults<UserInformation> searchResult = new SearchResults<>(users, users.size());
189 when(userService.findUsers(any())).thenReturn(searchResult);
190 List<UserRestResponse> restUserForAdmins = List.of(toRestUser(user1), toRestUser(user2), toRestUser(user3), toRestUser(user4));
191 when(responseGenerator.toUsersForResponse(eq(searchResult.searchResults()), any())).thenReturn(new UsersSearchRestResponse(restUserForAdmins, new PageRestResponse(1, 50, 4)));
192 userSession.logIn().setSystemAdministrator();
194 MvcResult mvcResult = mockMvc.perform(get(USER_ENDPOINT))
195 .andExpect(status().isOk())
198 UsersSearchRestResponse actualUsersSearchRestResponse = gson.fromJson(mvcResult.getResponse().getContentAsString(), UsersSearchRestResponse.class);
199 assertThat(actualUsersSearchRestResponse.users())
200 .containsExactlyElementsOf(restUserForAdmins);
201 assertThat(actualUsersSearchRestResponse.page().total()).isEqualTo(users.size());
205 static class RestUserDeserializer extends TypeAdapter<UserRestResponse> {
208 public void write(JsonWriter out, UserRestResponse value) {
209 throw new IllegalStateException("not implemented");
213 public UserRestResponse read(JsonReader reader) {
214 return gson.fromJson(reader, UserRestResponseForAdmins.class);
218 private UserInformation generateUserSearchResult(String id, boolean active, boolean local, boolean managed, int groupsCount, int tokensCount) {
219 UserDto userDto = new UserDto()
220 .setLogin("login_" + id)
221 .setUuid("uuid_" + id)
222 .setName("name_" + id)
223 .setEmail(id + "@email.com")
226 .setExternalLogin("externalLogin_" + id)
227 .setExternalId("externalId_" + id)
228 .setExternalIdentityProvider("externalIdentityProvider_" + id)
229 .setLastConnectionDate(0L)
230 .setLastSonarlintConnectionDate(1L);
232 List<String> groups = new ArrayList<>();
233 IntStream.range(1, groupsCount).forEach(i -> groups.add("group" + i));
235 return new UserInformation(userDto, managed, Optional.of("avatar_" + id), groups, tokensCount);
238 private UserRestResponseForAdmins toRestUser(UserInformation userInformation) {
239 return new UserRestResponseForAdmins(
240 userInformation.userDto().getLogin(),
241 userInformation.userDto().getLogin(),
242 userInformation.userDto().getName(),
243 userInformation.userDto().getEmail(),
244 userInformation.userDto().isActive(),
245 userInformation.userDto().isLocal(),
246 userInformation.managed(),
247 userInformation.userDto().getExternalLogin(),
248 userInformation.userDto().getExternalIdentityProvider(),
249 userInformation.avatar().orElse(""),
250 formatDateTime(userInformation.userDto().getLastConnectionDate()),
251 formatDateTime(userInformation.userDto().getLastSonarlintConnectionDate()),
252 userInformation.userDto().getSortedScmAccounts());
256 public void deactivate_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
257 userSession.logIn().setNonSystemAdministrator();
259 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
261 status().isForbidden(),
262 content().json("{\"message\":\"Insufficient privileges\"}"));
266 public void deactivate_whenUserServiceThrowsNotFoundException_shouldReturnNotFound() throws Exception {
267 userSession.logIn().setSystemAdministrator();
268 doThrow(new NotFoundException("User not found.")).when(userService).deactivate("userToDelete", false);
270 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
272 status().isNotFound(),
273 content().json("{\"message\":\"User not found.\"}"));
277 public void deactivate_whenUserServiceThrowsBadRequestException_shouldReturnBadRequest() throws Exception {
278 userSession.logIn().setSystemAdministrator();
279 doThrow(BadRequestException.create("Not allowed")).when(userService).deactivate("userToDelete", false);
281 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
283 status().isBadRequest(),
284 content().json("{\"message\":\"Not allowed\"}"));
288 public void deactivate_whenUserTryingToDeactivateThemself_shouldReturnBadRequest() throws Exception {
289 UserSessionRule userToDelete = userSession.logIn("userToDelete").setSystemAdministrator();
291 mockMvc.perform(delete(USER_ENDPOINT + "/" + userToDelete.getUuid()))
293 status().isBadRequest(),
294 content().json("{\"message\":\"Self-deactivation is not possible\"}"));
298 public void deactivate_whenAnonymizeParameterIsNotBoolean_shouldReturnBadRequest() throws Exception {
299 userSession.logIn().setSystemAdministrator();
301 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "maybe"))
303 status().isBadRequest());
307 public void deactivate_whenAnonymizeIsNotSpecified_shouldDeactivateUserWithoutAnonymization() throws Exception {
308 userSession.logIn().setSystemAdministrator();
310 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
311 .andExpect(status().isNoContent());
313 verify(userService).deactivate("userToDelete", false);
317 public void deactivate_whenAnonymizeFalse_shouldDeactivateUserWithoutAnonymization() throws Exception {
318 userSession.logIn().setSystemAdministrator();
320 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "false"))
321 .andExpect(status().isNoContent());
323 verify(userService).deactivate("userToDelete", false);
327 public void deactivate_whenAnonymizeTrue_shouldDeactivateUserWithAnonymization() throws Exception {
328 userSession.logIn().setSystemAdministrator();
330 mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "true"))
331 .andExpect(status().isNoContent());
333 verify(userService).deactivate("userToDelete", true);
337 public void fetchUser_whenUserServiceThrowsNotFoundException_returnsNotFound() throws Exception {
338 when(userService.fetchUser("userLogin")).thenThrow(new NotFoundException("Not found"));
339 mockMvc.perform(get(USER_ENDPOINT + "/userLogin"))
341 status().isNotFound(),
342 content().json("{\"message\":\"Not found\"}")
348 public void fetchUser_whenUserExists_shouldReturnUser() throws Exception {
349 UserInformation user = generateUserSearchResult("user1", true, true, false, 2, 3);
350 UserRestResponseForAdmins restUserForAdmins = toRestUser(user);
351 when(userService.fetchUser("userLogin")).thenReturn(user);
352 when(responseGenerator.toRestUser(user)).thenReturn(restUserForAdmins);
353 MvcResult mvcResult = mockMvc.perform(get(USER_ENDPOINT + "/userLogin"))
354 .andExpect(status().isOk())
356 UserRestResponseForAdmins responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), UserRestResponseForAdmins.class);
357 assertThat(responseUser).isEqualTo(restUserForAdmins);
361 public void create_whenNotAnAdmin_shouldReturnForbidden() throws Exception {
362 userSession.logIn().setNonSystemAdministrator();
366 .contentType(MediaType.APPLICATION_JSON_VALUE)
367 .content(gson.toJson(new UserCreateRestRequest(null, null, "login", "name", null, null))))
369 status().isForbidden(),
370 content().json("{\"message\":\"Insufficient privileges\"}"));
374 public void create_whenNoLogin_shouldReturnBadRequest() throws Exception {
375 userSession.logIn().setSystemAdministrator();
379 .contentType(MediaType.APPLICATION_JSON_VALUE)
380 .content(gson.toJson(new UserCreateRestRequest(null, null, null, "name", null, null))))
382 status().isBadRequest(),
383 content().json("{\"message\":\"Value {} for field login was rejected. Error: must not be null.\"}"));
387 public void create_whenNoName_shouldReturnBadRequest() throws Exception {
388 userSession.logIn().setSystemAdministrator();
392 .contentType(MediaType.APPLICATION_JSON_VALUE)
393 .content(gson.toJson(new UserCreateRestRequest(null, null, "login", null, null, null))))
395 status().isBadRequest(),
396 content().json("{\"message\":\"Value {} for field name was rejected. Error: must not be null.\"}"));
400 public void create_whenUserServiceThrow_shouldReturnServerError() throws Exception {
401 userSession.logIn().setSystemAdministrator();
402 when(userService.createUser(any())).thenThrow(new IllegalArgumentException("IllegalArgumentException"));
406 .contentType(MediaType.APPLICATION_JSON_VALUE)
407 .content(gson.toJson(new UserCreateRestRequest("e@mail.com", true, "login", "name", "password", List.of("scm")))))
409 status().isBadRequest(),
410 content().json("{\"message\":\"IllegalArgumentException\"}"));
414 public void create_whenUserServiceReturnUser_shouldReturnIt() throws Exception {
415 userSession.logIn().setSystemAdministrator();
416 UserInformation userInformation = generateUserSearchResult("1", true, true, false, 1, 2);
417 UserDto userDto = userInformation.userDto();
418 when(userService.createUser(any())).thenReturn(userInformation);
419 when(responseGenerator.toRestUser(userInformation)).thenReturn(toRestUser(userInformation));
421 MvcResult mvcResult = mockMvc.perform(
423 .contentType(MediaType.APPLICATION_JSON_VALUE)
424 .content(gson.toJson(new UserCreateRestRequest(
425 userDto.getEmail(), userDto.isLocal(), userDto.getLogin(), userDto.getName(), "password", userDto.getSortedScmAccounts()))))
426 .andExpect(status().isOk())
428 UserRestResponseForAdmins responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), UserRestResponseForAdmins.class);
429 assertThat(responseUser).isEqualTo(toRestUser(userInformation));
433 public void updateUser_whenUserDoesntExist_shouldReturnNotFound() throws Exception {
434 userSession.logIn().setSystemAdministrator();
435 when(userService.updateUser(eq("userLogin"), any(UpdateUser.class))).thenThrow(new NotFoundException("Not found"));
436 mockMvc.perform(patch(USER_ENDPOINT + "/userLogin")
437 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
440 status().isNotFound(),
441 content().json("{\"message\":\"Not found\"}"));
445 public void updateUser_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception {
446 userSession.logIn().setNonSystemAdministrator();
449 patch(USER_ENDPOINT + "/userLogin")
450 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
453 status().isForbidden(),
454 content().json("{\"message\":\"Insufficient privileges\"}"));
458 public void updateUser_whenEmailIsProvided_shouldUpdateUserAndReturnUpdatedValue() throws Exception {
459 UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"email\":\"newemail@example.com\"}");
460 assertThat(userUpdate.email()).isEqualTo("newemail@example.com");
461 assertThat(userUpdate.name()).isNull();
462 assertThat(userUpdate.scmAccounts()).isNull();
466 public void updateUser_whenNameIsProvided_shouldUpdateUserAndReturnUpdatedValue() throws Exception {
467 UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"name\":\"new name\"}");
468 assertThat(userUpdate.email()).isNull();
469 assertThat(userUpdate.name()).isEqualTo("new name");
470 assertThat(userUpdate.scmAccounts()).isNull();
474 public void updateUser_whenScmAccountsAreProvided_shouldUpdateUserAndReturnUpdatedValue() throws Exception {
475 UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"scmAccounts\":[\"account1\",\"account2\"]}");
476 assertThat(userUpdate.email()).isNull();
477 assertThat(userUpdate.name()).isNull();
478 assertThat(userUpdate.scmAccounts()).containsExactly("account1", "account2");
482 public void updateUser_whenEmailIsInvalid_shouldReturnBadRequest() throws Exception {
483 performPatchCallAndExpectBadRequest("{\"email\":\"notavalidemail\"}", "Value notavalidemail for field email was rejected. Error: must be a well-formed email address.");
487 public void updateUser_whenEmailIsEmpty_shouldReturnBadRequest() throws Exception {
488 performPatchCallAndExpectBadRequest("{\"email\":\"\"}", "Value for field email was rejected. Error: size must be between 1 and 100.");
492 public void updateUser_whenNameIsTooLong_shouldReturnBadRequest() throws Exception {
493 String tooLong = "toolong".repeat(30);
494 String payload = "{\"name\":\"" + tooLong + "\"}";
495 String message = "Value " + tooLong + " for field name was rejected. Error: size must be between 0 and 200.";
496 performPatchCallAndExpectBadRequest(payload, message);
500 public void updateUser_whenLoginIsProvided_shouldUpdateLogin() throws Exception {
501 UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"login\":\"newLogin\"}");
502 assertThat(userUpdate.login()).isEqualTo("newLogin");
506 public void updateUser_whenExternalProviderIsProvided_shouldUpdate() throws Exception {
507 UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"externalProvider\":\"newExternalProvider\"}");
508 assertThat(userUpdate.externalIdentityProvider()).isEqualTo("newExternalProvider");
511 public void updateUser_whenExternalProviderLoginIsProvided_shouldUpdate() throws Exception {
512 UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"externalLogin\":\"newExternalProviderLogin\"}");
513 assertThat(userUpdate.externalIdentityProviderLogin()).isEqualTo("newExternalProviderLogin");
517 public void updateUser_whenLoginIsEmpty_shouldReturnBadRequest() throws Exception {
518 performPatchCallAndExpectBadRequest("{\"login\":\"\"}", "Value for field login was rejected. Error: size must be between 2 and 100.");
521 private void performPatchCallAndExpectBadRequest(String payload, String expectedMessage) throws Exception {
522 userSession.logIn().setSystemAdministrator();
524 MvcResult mvcResult = mockMvc.perform(patch(USER_ENDPOINT + "/userLogin")
525 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
528 status().isBadRequest())
531 RestError error = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestError.class);
532 assertThat(error.message()).isEqualTo(expectedMessage);
535 private UpdateUser performPatchCallAndVerifyResponse(String payload) throws Exception {
536 userSession.logIn().setSystemAdministrator();
537 UserInformation mock = mock();
538 when(userService.fetchUser("userUuid")).thenReturn(mock);
539 UserInformation userInformation = generateUserSearchResult("1", true, true, false, 1, 2);
541 when(userService.updateUser(eq("userUuid"), any())).thenReturn(userInformation);
542 when(responseGenerator.toRestUser(userInformation)).thenReturn(toRestUser(userInformation));
544 MvcResult mvcResult = mockMvc.perform(patch(USER_ENDPOINT + "/userUuid")
545 .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
551 UserRestResponseForAdmins responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), UserRestResponseForAdmins.class);
552 assertThat(responseUser).isEqualTo(toRestUser(userInformation));
554 ArgumentCaptor<UpdateUser> updateUserCaptor = ArgumentCaptor.forClass(UpdateUser.class);
555 verify(userService).updateUser(eq("userUuid"), updateUserCaptor.capture());
556 return updateUserCaptor.getValue();