]> source.dussan.org Git - sonarqube.git/blob
3c6efc91b4e65f56d61134841cf536989800ca27
[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 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.model.RestUser;
48 import org.sonar.server.v2.api.user.model.RestUserForAdmins;
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;
54
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.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE;
64 import static org.sonar.server.v2.WebApiEndpoints.USER_ENDPOINT;
65 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_INDEX;
66 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_SIZE;
67 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
68 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
69 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
70 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
71 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
72 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
73
74 public class DefaultUserControllerTest {
75
76   @Rule
77   public UserSessionRule userSession = UserSessionRule.standalone();
78   private final UserService userService = mock(UserService.class);
79   private final UsersSearchRestResponseGenerator responseGenerator = mock(UsersSearchRestResponseGenerator.class);
80   private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultUserController(userSession, userService, responseGenerator));
81
82   private static final Gson gson = new GsonBuilder().registerTypeAdapter(RestUser.class, new RestUserDeserializer()).create();
83
84   @Test
85   public void search_whenNoParameters_shouldUseDefaultAndForwardToUserService() throws Exception {
86     when(userService.findUsers(any())).thenReturn(new SearchResults<>(List.of(), 0));
87
88     mockMvc.perform(get(USER_ENDPOINT))
89       .andExpect(status().isOk());
90
91     ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
92     verify(userService).findUsers(requestCaptor.capture());
93     assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(Integer.valueOf(DEFAULT_PAGE_SIZE));
94     assertThat(requestCaptor.getValue().getPage()).isEqualTo(Integer.valueOf(DEFAULT_PAGE_INDEX));
95     assertThat(requestCaptor.getValue().isDeactivated()).isFalse();
96   }
97
98   @Test
99   public void search_whenParametersUsed_shouldForwardWithParameters() throws Exception {
100     when(userService.findUsers(any())).thenReturn(new SearchResults<>(List.of(), 0));
101     userSession.logIn().setSystemAdministrator();
102
103     mockMvc.perform(get(USER_ENDPOINT)
104         .param("active", "false")
105         .param("managed", "true")
106         .param("q", "q")
107         .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
108         .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100")
109         .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
110         .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100")
111         .param("pageSize", "100")
112         .param("pageIndex", "2"))
113       .andExpect(status().isOk());
114
115     ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
116     verify(userService).findUsers(requestCaptor.capture());
117     assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(100);
118     assertThat(requestCaptor.getValue().getPage()).isEqualTo(2);
119     assertThat(requestCaptor.getValue().isDeactivated()).isTrue();
120   }
121
122   @Test
123   public void search_whenAdminParametersUsedButNotAdmin_shouldFail() throws Exception {
124     mockMvc.perform(get(USER_ENDPOINT)
125       .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
126       .andExpectAll(
127         status().isForbidden(),
128         content().string("{\"message\":\"parameter sonarQubeLastConnectionDateFrom requires Administer System permission.\"}"));
129
130     mockMvc.perform(get(USER_ENDPOINT)
131       .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
132       .andExpectAll(
133         status().isForbidden(),
134         content().string("{\"message\":\"parameter sonarQubeLastConnectionDateTo requires Administer System permission.\"}"));
135
136     mockMvc.perform(get(USER_ENDPOINT)
137       .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
138       .andExpectAll(
139         status().isForbidden(),
140         content().string("{\"message\":\"parameter sonarLintLastConnectionDateFrom requires Administer System permission.\"}"));
141
142     mockMvc.perform(get(USER_ENDPOINT)
143       .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
144       .andExpectAll(
145         status().isForbidden(),
146         content().string("{\"message\":\"parameter sonarLintLastConnectionDateTo requires Administer System permission.\"}"));
147   }
148
149   @Test
150   public void search_whenUserServiceReturnUsers_shouldReturnThem() throws Exception {
151     UserInformation user1 = generateUserSearchResult("user1", true, true, false, 2, 3);
152     UserInformation user2 = generateUserSearchResult("user2", true, false, false, 3, 0);
153     UserInformation user3 = generateUserSearchResult("user3", true, false, true, 1, 1);
154     UserInformation user4 = generateUserSearchResult("user4", false, true, false, 0, 0);
155     List<UserInformation> users = List.of(user1, user2, user3, user4);
156     SearchResults<UserInformation> searchResult = new SearchResults<>(users, users.size());
157     when(userService.findUsers(any())).thenReturn(searchResult);
158     List<RestUser> restUserForAdmins = List.of(toRestUser(user1), toRestUser(user2), toRestUser(user3), toRestUser(user4));
159     when(responseGenerator.toUsersForResponse(eq(searchResult.searchResults()), any())).thenReturn(new UsersSearchRestResponse(restUserForAdmins, new PageRestResponse(1, 50, 4)));
160     userSession.logIn().setSystemAdministrator();
161
162     MvcResult mvcResult = mockMvc.perform(get(USER_ENDPOINT))
163       .andExpect(status().isOk())
164       .andReturn();
165
166     UsersSearchRestResponse actualUsersSearchRestResponse = gson.fromJson(mvcResult.getResponse().getContentAsString(), UsersSearchRestResponse.class);
167     assertThat(actualUsersSearchRestResponse.users())
168       .containsExactlyElementsOf(restUserForAdmins);
169     assertThat(actualUsersSearchRestResponse.page().total()).isEqualTo(users.size());
170
171   }
172
173   static class RestUserDeserializer extends TypeAdapter<RestUser> {
174
175     @Override
176     public void write(JsonWriter out, RestUser value) {
177       throw new IllegalStateException("not implemented");
178     }
179
180     @Override
181     public RestUser read(JsonReader reader) {
182       return gson.fromJson(reader, RestUserForAdmins.class);
183     }
184   }
185
186   private UserInformation generateUserSearchResult(String id, boolean active, boolean local, boolean managed, int groupsCount, int tokensCount) {
187     UserDto userDto = new UserDto()
188       .setLogin("login_" + id)
189       .setUuid("uuid_" + id)
190       .setName("name_" + id)
191       .setEmail(id + "@email.com")
192       .setActive(active)
193       .setLocal(local)
194       .setExternalLogin("externalLogin_" + id)
195       .setExternalId("externalId_" + id)
196       .setExternalIdentityProvider("externalIdentityProvider_" + id)
197       .setLastConnectionDate(0L)
198       .setLastSonarlintConnectionDate(1L);
199
200     List<String> groups = new ArrayList<>();
201     IntStream.range(1, groupsCount).forEach(i -> groups.add("group" + i));
202
203     return new UserInformation(userDto, managed, Optional.of("avatar_" + id), groups, tokensCount);
204   }
205
206   private RestUserForAdmins toRestUser(UserInformation userInformation) {
207     return new RestUserForAdmins(
208       userInformation.userDto().getLogin(),
209       userInformation.userDto().getLogin(),
210       userInformation.userDto().getName(),
211       userInformation.userDto().getEmail(),
212       userInformation.userDto().isActive(),
213       userInformation.userDto().isLocal(),
214       userInformation.managed(),
215       userInformation.userDto().getExternalLogin(),
216       userInformation.userDto().getExternalIdentityProvider(),
217       userInformation.avatar().orElse(""),
218       formatDateTime(userInformation.userDto().getLastConnectionDate()),
219       formatDateTime(userInformation.userDto().getLastSonarlintConnectionDate()),
220       userInformation.userDto().getSortedScmAccounts());
221   }
222
223   @Test
224   public void deactivate_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
225     userSession.logIn().setNonSystemAdministrator();
226
227     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
228       .andExpectAll(
229         status().isForbidden(),
230         content().json("{\"message\":\"Insufficient privileges\"}"));
231   }
232
233   @Test
234   public void deactivate_whenUserServiceThrowsNotFoundException_shouldReturnNotFound() throws Exception {
235     userSession.logIn().setSystemAdministrator();
236     doThrow(new NotFoundException("User not found.")).when(userService).deactivate("userToDelete", false);
237
238     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
239       .andExpectAll(
240         status().isNotFound(),
241         content().json("{\"message\":\"User not found.\"}"));
242   }
243
244   @Test
245   public void deactivate_whenUserServiceThrowsBadRequestException_shouldReturnBadRequest() throws Exception {
246     userSession.logIn().setSystemAdministrator();
247     doThrow(BadRequestException.create("Not allowed")).when(userService).deactivate("userToDelete", false);
248
249     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
250       .andExpectAll(
251         status().isBadRequest(),
252         content().json("{\"message\":\"Not allowed\"}"));
253   }
254
255   @Test
256   public void deactivate_whenUserTryingToDeactivateThemself_shouldReturnBadRequest() throws Exception {
257     userSession.logIn("userToDelete").setSystemAdministrator();
258
259     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
260       .andExpectAll(
261         status().isBadRequest(),
262         content().json("{\"message\":\"Self-deactivation is not possible\"}"));
263   }
264
265   @Test
266   public void deactivate_whenAnonymizeParameterIsNotBoolean_shouldReturnBadRequest() throws Exception {
267     userSession.logIn().setSystemAdministrator();
268
269     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "maybe"))
270       .andExpect(
271         status().isBadRequest());
272   }
273
274   @Test
275   public void deactivate_whenAnonymizeIsNotSpecified_shouldDeactivateUserWithoutAnonymization() throws Exception {
276     userSession.logIn().setSystemAdministrator();
277
278     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
279       .andExpect(status().isNoContent());
280
281     verify(userService).deactivate("userToDelete", false);
282   }
283
284   @Test
285   public void deactivate_whenAnonymizeFalse_shouldDeactivateUserWithoutAnonymization() throws Exception {
286     userSession.logIn().setSystemAdministrator();
287
288     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "false"))
289       .andExpect(status().isNoContent());
290
291     verify(userService).deactivate("userToDelete", false);
292   }
293
294   @Test
295   public void deactivate_whenAnonymizeTrue_shouldDeactivateUserWithAnonymization() throws Exception {
296     userSession.logIn().setSystemAdministrator();
297
298     mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete").param("anonymize", "true"))
299       .andExpect(status().isNoContent());
300
301     verify(userService).deactivate("userToDelete", true);
302   }
303
304   @Test
305   public void fetchUser_whenUserServiceThrowsNotFoundException_returnsNotFound() throws Exception {
306     when(userService.fetchUser("userLogin")).thenThrow(new NotFoundException("Not found"));
307     mockMvc.perform(get(USER_ENDPOINT + "/userLogin"))
308       .andExpectAll(
309         status().isNotFound(),
310         content().json("{\"message\":\"Not found\"}")
311       );
312
313   }
314
315   @Test
316   public void fetchUser_whenUserExists_shouldReturnUser() throws Exception {
317     UserInformation user = generateUserSearchResult("user1", true, true, false, 2, 3);
318     RestUserForAdmins restUserForAdmins = toRestUser(user);
319     when(userService.fetchUser("userLogin")).thenReturn(user);
320     when(responseGenerator.toRestUser(user)).thenReturn(restUserForAdmins);
321     MvcResult mvcResult = mockMvc.perform(get(USER_ENDPOINT + "/userLogin"))
322       .andExpect(status().isOk())
323       .andReturn();
324     RestUserForAdmins responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestUserForAdmins.class);
325     assertThat(responseUser).isEqualTo(restUserForAdmins);
326   }
327
328   @Test
329   public void create_whenNotAnAdmin_shouldReturnForbidden() throws Exception {
330     userSession.logIn().setNonSystemAdministrator();
331
332     mockMvc.perform(
333       post(USER_ENDPOINT)
334         .contentType(MediaType.APPLICATION_JSON_VALUE)
335         .content(gson.toJson(new UserCreateRestRequest(null, null, "login", "name", null, null))))
336       .andExpectAll(
337         status().isForbidden(),
338         content().json("{\"message\":\"Insufficient privileges\"}"));
339   }
340
341   @Test
342   public void create_whenNoLogin_shouldReturnBadRequest() throws Exception {
343     userSession.logIn().setSystemAdministrator();
344
345     mockMvc.perform(
346       post(USER_ENDPOINT)
347         .contentType(MediaType.APPLICATION_JSON_VALUE)
348         .content(gson.toJson(new UserCreateRestRequest(null, null, null, "name", null, null))))
349       .andExpectAll(
350         status().isBadRequest(),
351         content().json("{\"message\":\"Value {} for field login was rejected. Error: must not be null.\"}"));
352   }
353
354   @Test
355   public void create_whenNoName_shouldReturnBadRequest() throws Exception {
356     userSession.logIn().setSystemAdministrator();
357
358     mockMvc.perform(
359       post(USER_ENDPOINT)
360         .contentType(MediaType.APPLICATION_JSON_VALUE)
361         .content(gson.toJson(new UserCreateRestRequest(null, null, "login", null, null, null))))
362       .andExpectAll(
363         status().isBadRequest(),
364         content().json("{\"message\":\"Value {} for field name was rejected. Error: must not be null.\"}"));
365   }
366
367   @Test
368   public void create_whenUserServiceThrow_shouldReturnServerError() throws Exception {
369     userSession.logIn().setSystemAdministrator();
370     when(userService.createUser(any())).thenThrow(new IllegalArgumentException("IllegalArgumentException"));
371
372     mockMvc.perform(
373       post(USER_ENDPOINT)
374         .contentType(MediaType.APPLICATION_JSON_VALUE)
375         .content(gson.toJson(new UserCreateRestRequest("e@mail.com", true, "login", "name", "password", List.of("scm")))))
376       .andExpectAll(
377         status().isBadRequest(),
378         content().json("{\"message\":\"IllegalArgumentException\"}"));
379   }
380
381   @Test
382   public void create_whenUserServiceReturnUser_shouldReturnIt() throws Exception {
383     userSession.logIn().setSystemAdministrator();
384     UserInformation userInformation = generateUserSearchResult("1", true, true, false, 1, 2);
385     UserDto userDto = userInformation.userDto();
386     when(userService.createUser(any())).thenReturn(userInformation);
387     when(responseGenerator.toRestUser(userInformation)).thenReturn(toRestUser(userInformation));
388
389     MvcResult mvcResult = mockMvc.perform(
390       post(USER_ENDPOINT)
391         .contentType(MediaType.APPLICATION_JSON_VALUE)
392         .content(gson.toJson(new UserCreateRestRequest(
393           userDto.getEmail(), userDto.isLocal(), userDto.getLogin(), userDto.getName(), "password", userDto.getSortedScmAccounts()))))
394       .andExpect(status().isOk())
395       .andReturn();
396     RestUserForAdmins responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestUserForAdmins.class);
397     assertThat(responseUser).isEqualTo(toRestUser(userInformation));
398   }
399
400   @Test
401   public void updateUser_whenUserDoesntExist_shouldReturnNotFound() throws Exception {
402     userSession.logIn().setSystemAdministrator();
403     when(userService.updateUser(eq("userLogin"), any(UpdateUser.class))).thenThrow(new NotFoundException("Not found"));
404     mockMvc.perform(patch(USER_ENDPOINT + "/userLogin")
405       .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
406       .content("{}"))
407       .andExpectAll(
408         status().isNotFound(),
409         content().json("{\"message\":\"Not found\"}"));
410   }
411
412   @Test
413   public void updateUser_whenCallerIsNotAdmin_shouldReturnForbidden() throws Exception {
414     userSession.logIn().setNonSystemAdministrator();
415
416     mockMvc.perform(
417       patch(USER_ENDPOINT + "/userLogin")
418         .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
419         .content("{}"))
420       .andExpectAll(
421         status().isForbidden(),
422         content().json("{\"message\":\"Insufficient privileges\"}"));
423   }
424
425   @Test
426   public void updateUser_whenEmailIsProvided_shouldUpdateUserAndReturnUpdatedValue() throws Exception {
427     UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"email\":\"newemail@example.com\"}");
428     assertThat(userUpdate.email()).isEqualTo("newemail@example.com");
429     assertThat(userUpdate.name()).isNull();
430     assertThat(userUpdate.scmAccounts()).isNull();
431   }
432
433   private UpdateUser performPatchCallAndVerifyResponse(String payload) throws Exception {
434     userSession.logIn().setSystemAdministrator();
435     UserInformation userInformation = generateUserSearchResult("1", true, true, false, 1, 2);
436
437     when(userService.updateUser(eq("userLogin"), any())).thenReturn(userInformation);
438     when(responseGenerator.toRestUser(userInformation)).thenReturn(toRestUser(userInformation));
439
440     MvcResult mvcResult = mockMvc.perform(patch(USER_ENDPOINT + "/userLogin")
441       .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
442       .content(payload))
443       .andExpect(
444         status().isOk())
445       .andReturn();
446
447     RestUserForAdmins responseUser = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestUserForAdmins.class);
448     assertThat(responseUser).isEqualTo(toRestUser(userInformation));
449
450     ArgumentCaptor<UpdateUser> updateUserCaptor = ArgumentCaptor.forClass(UpdateUser.class);
451     verify(userService).updateUser(eq("userLogin"), updateUserCaptor.capture());
452     return updateUserCaptor.getValue();
453   }
454
455   @Test
456   public void updateUser_whenNameIsProvided_shouldUpdateUserAndReturnUpdatedValue() throws Exception {
457     UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"name\":\"new name\"}");
458     assertThat(userUpdate.email()).isNull();
459     assertThat(userUpdate.name()).isEqualTo("new name");
460     assertThat(userUpdate.scmAccounts()).isNull();
461   }
462
463   @Test
464   public void updateUser_whenScmAccountsAreProvided_shouldUpdateUserAndReturnUpdatedValue() throws Exception {
465     UpdateUser userUpdate = performPatchCallAndVerifyResponse("{\"scmAccounts\":[\"account1\",\"account2\"]}");
466     assertThat(userUpdate.email()).isNull();
467     assertThat(userUpdate.name()).isNull();
468     assertThat(userUpdate.scmAccounts()).containsExactly("account1", "account2");
469   }
470
471   @Test
472   public void updateUser_whenEmailIsInvalid_shouldReturnBadRequest() throws Exception {
473     performPatchCallAndExpectBadRequest("{\"email\":\"notavalidemail\"}", "Value notavalidemail for field email was rejected. Error: must be a well-formed email address.");
474   }
475
476   private void performPatchCallAndExpectBadRequest(String payload, String expectedMessage) throws Exception {
477     userSession.logIn().setSystemAdministrator();
478
479     MvcResult mvcResult = mockMvc.perform(patch(USER_ENDPOINT + "/userLogin")
480       .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
481       .content(payload))
482       .andExpect(
483         status().isBadRequest())
484       .andReturn();
485
486     RestError error = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestError.class);
487     assertThat(error.message()).isEqualTo(expectedMessage);
488   }
489
490   @Test
491   public void updateUser_whenEmailIsEmpty_shouldReturnBadRequest() throws Exception {
492     performPatchCallAndExpectBadRequest("{\"email\":\"\"}", "Value  for field email was rejected. Error: size must be between 1 and 100.");
493   }
494
495   @Test
496   public void updateUser_whenNameIsTooLong_shouldReturnBadRequest() throws Exception {
497     String tooLong = "toolong".repeat(30);
498     String payload = "{\"name\":\"" + tooLong + "\"}";
499     String message = "Value " + tooLong + " for field name was rejected. Error: size must be between 0 and 200.";
500     performPatchCallAndExpectBadRequest(payload, message);
501   }
502
503 }