You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SearchActionIT.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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.user.ws;
  21. import java.time.Instant;
  22. import java.time.OffsetDateTime;
  23. import java.time.temporal.ChronoUnit;
  24. import java.util.Set;
  25. import java.util.stream.IntStream;
  26. import java.util.stream.Stream;
  27. import org.assertj.core.api.InstanceOfAssertFactories;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.sonar.api.server.ws.WebService;
  31. import org.sonar.api.server.ws.WebService.Param;
  32. import org.sonar.api.utils.DateUtils;
  33. import org.sonar.core.util.UuidFactory;
  34. import org.sonar.db.DbTester;
  35. import org.sonar.db.scim.ScimUserDao;
  36. import org.sonar.db.user.GroupDto;
  37. import org.sonar.db.user.UserDto;
  38. import org.sonar.server.common.avatar.AvatarResolverImpl;
  39. import org.sonar.server.common.user.service.UserService;
  40. import org.sonar.server.exceptions.BadRequestException;
  41. import org.sonar.server.exceptions.ServerException;
  42. import org.sonar.server.management.ManagedInstanceService;
  43. import org.sonar.server.tester.UserSessionRule;
  44. import org.sonar.server.ws.TestRequest;
  45. import org.sonar.server.ws.WsActionTester;
  46. import org.sonarqube.ws.Common.Paging;
  47. import org.sonarqube.ws.Users.SearchWsResponse;
  48. import org.sonarqube.ws.Users.SearchWsResponse.User;
  49. import static java.util.Arrays.asList;
  50. import static java.util.Collections.emptyList;
  51. import static java.util.Collections.singletonList;
  52. import static java.util.function.Function.identity;
  53. import static java.util.stream.Collectors.toMap;
  54. import static org.assertj.core.api.Assertions.assertThat;
  55. import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
  56. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  57. import static org.assertj.core.api.Assertions.tuple;
  58. import static org.mockito.ArgumentMatchers.any;
  59. import static org.mockito.ArgumentMatchers.anyBoolean;
  60. import static org.mockito.Mockito.mock;
  61. import static org.mockito.Mockito.when;
  62. import static org.sonar.api.utils.DateUtils.formatDateTime;
  63. import static org.sonar.test.JsonAssert.assertJson;
  64. public class SearchActionIT {
  65. @Rule
  66. public UserSessionRule userSession = UserSessionRule.standalone();
  67. @Rule
  68. public DbTester db = DbTester.create();
  69. private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class);
  70. private final UserService userService = new UserService(db.getDbClient(), new AvatarResolverImpl(), managedInstanceService);
  71. private final SearchWsReponseGenerator searchWsReponseGenerator = new SearchWsReponseGenerator(userSession);
  72. private final WsActionTester ws = new WsActionTester(new SearchAction(userSession, userService, searchWsReponseGenerator));
  73. @Test
  74. public void search_for_all_active_users() {
  75. UserDto user1 = db.users().insertUser();
  76. UserDto user2 = db.users().insertUser();
  77. UserDto user3 = db.users().insertUser(u -> u.setActive(false));
  78. userSession.logIn();
  79. SearchWsResponse response = ws.newRequest()
  80. .executeProtobuf(SearchWsResponse.class);
  81. assertThat(response.getUsersList())
  82. .extracting(User::getLogin, User::getName)
  83. .containsExactlyInAnyOrder(
  84. tuple(user1.getLogin(), user1.getName()),
  85. tuple(user2.getLogin(), user2.getName()));
  86. }
  87. @Test
  88. public void search_deactivated_users() {
  89. UserDto user1 = db.users().insertUser(u -> u.setActive(false));
  90. UserDto user2 = db.users().insertUser(u -> u.setActive(true));
  91. userSession.logIn();
  92. SearchWsResponse response = ws.newRequest()
  93. .setParam("deactivated", "true")
  94. .executeProtobuf(SearchWsResponse.class);
  95. assertThat(response.getUsersList())
  96. .extracting(User::getLogin, User::getName)
  97. .containsExactlyInAnyOrder(
  98. tuple(user1.getLogin(), user1.getName()));
  99. }
  100. @Test
  101. public void search_with_query() {
  102. userSession.logIn();
  103. UserDto user = db.users().insertUser(u -> u
  104. .setLogin("user-%_%-login")
  105. .setName("user-name")
  106. .setEmail("user@mail.com")
  107. .setLocal(true)
  108. .setScmAccounts(singletonList("user1")));
  109. assertThat(ws.newRequest()
  110. .setParam("q", "user-%_%-")
  111. .executeProtobuf(SearchWsResponse.class).getUsersList())
  112. .extracting(User::getLogin)
  113. .containsExactlyInAnyOrder(user.getLogin());
  114. assertThat(ws.newRequest()
  115. .setParam("q", "user@MAIL.com")
  116. .executeProtobuf(SearchWsResponse.class).getUsersList())
  117. .extracting(User::getLogin)
  118. .containsExactlyInAnyOrder(user.getLogin());
  119. assertThat(ws.newRequest()
  120. .setParam("q", "user-name")
  121. .executeProtobuf(SearchWsResponse.class).getUsersList())
  122. .extracting(User::getLogin)
  123. .containsExactlyInAnyOrder(user.getLogin());
  124. }
  125. @Test
  126. public void return_avatar() {
  127. UserDto user = db.users().insertUser(u -> u.setEmail("john@doe.com"));
  128. userSession.logIn();
  129. SearchWsResponse response = ws.newRequest()
  130. .executeProtobuf(SearchWsResponse.class);
  131. assertThat(response.getUsersList())
  132. .extracting(User::getLogin, User::getAvatar)
  133. .containsExactlyInAnyOrder(tuple(user.getLogin(), "6a6c19fea4a3676970167ce51f39e6ee"));
  134. }
  135. @Test
  136. public void return_isManagedFlag() {
  137. UserDto nonManagedUser = db.users().insertUser(u -> u.setEmail("john@doe.com"));
  138. UserDto managedUser = db.users().insertUser(u -> u.setEmail("externalUser@doe.com"));
  139. mockUsersAsManaged(managedUser.getUuid());
  140. userSession.logIn().setSystemAdministrator();
  141. SearchWsResponse response = ws.newRequest()
  142. .executeProtobuf(SearchWsResponse.class);
  143. assertThat(response.getUsersList())
  144. .extracting(User::getLogin, User::getManaged)
  145. .containsExactlyInAnyOrder(
  146. tuple(managedUser.getLogin(), true),
  147. tuple(nonManagedUser.getLogin(), false)
  148. );
  149. }
  150. @Test
  151. public void search_whenFilteringByManagedAndInstanceNotManaged_throws() {
  152. userSession.logIn().setSystemAdministrator();
  153. TestRequest testRequest = ws.newRequest()
  154. .setParam("managed", "true");
  155. assertThatExceptionOfType(BadRequestException.class)
  156. .isThrownBy(() -> testRequest.executeProtobuf(SearchWsResponse.class))
  157. .withMessage("The 'managed' parameter is only available for managed instances.");
  158. }
  159. @Test
  160. public void search_whenFilteringByManagedAndInstanceManaged_returnsCorrectResults() {
  161. UserDto nonManagedUser = db.users().insertUser(u -> u.setEmail("john@doe.com"));
  162. UserDto managedUser = db.users().insertUser(u -> u.setEmail("externalUser@doe.com"));
  163. db.users().enableScimForUser(managedUser);
  164. mockUsersAsManaged(managedUser.getUuid());
  165. mockInstanceExternallyManagedAndFilterForManagedUsers();
  166. userSession.logIn().setSystemAdministrator();
  167. SearchWsResponse response = ws.newRequest()
  168. .setParam("managed", "true")
  169. .executeProtobuf(SearchWsResponse.class);
  170. assertThat(response.getUsersList())
  171. .extracting(User::getLogin, User::getManaged)
  172. .containsExactlyInAnyOrder(
  173. tuple(managedUser.getLogin(), true)
  174. );
  175. }
  176. @Test
  177. public void search_whenFilteringByNonManagedAndInstanceManaged_returnsCorrectResults() {
  178. UserDto nonManagedUser = db.users().insertUser(u -> u.setEmail("john@doe.com"));
  179. UserDto managedUser = db.users().insertUser(u -> u.setEmail("externalUser@doe.com"));
  180. db.users().enableScimForUser(managedUser);
  181. mockUsersAsManaged(managedUser.getUuid());
  182. mockInstanceExternallyManagedAndFilterForManagedUsers();
  183. userSession.logIn().setSystemAdministrator();
  184. SearchWsResponse response = ws.newRequest()
  185. .setParam("managed", "false")
  186. .executeProtobuf(SearchWsResponse.class);
  187. assertThat(response.getUsersList())
  188. .extracting(User::getLogin, User::getManaged)
  189. .containsExactlyInAnyOrder(
  190. tuple(nonManagedUser.getLogin(), false)
  191. );
  192. }
  193. private void mockInstanceExternallyManagedAndFilterForManagedUsers() {
  194. when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
  195. when(managedInstanceService.getManagedUsersSqlFilter(anyBoolean()))
  196. .thenAnswer(invocation -> {
  197. Boolean managed = invocation.getArgument(0, Boolean.class);
  198. return new ScimUserDao(mock(UuidFactory.class)).getManagedUserSqlFilter(managed);
  199. });
  200. }
  201. @Test
  202. public void return_scm_accounts() {
  203. UserDto user = db.users().insertUser(u -> u.setScmAccounts(asList("john1", "john2")));
  204. userSession.logIn();
  205. SearchWsResponse response = ws.newRequest()
  206. .executeProtobuf(SearchWsResponse.class);
  207. assertThat(response.getUsersList())
  208. .extracting(User::getLogin, u -> u.getScmAccounts().getScmAccountsList())
  209. .containsExactlyInAnyOrder(tuple(user.getLogin(), asList("john1", "john2")));
  210. }
  211. @Test
  212. public void return_tokens_count_when_system_administer() {
  213. UserDto user = db.users().insertUser();
  214. db.users().insertToken(user);
  215. db.users().insertToken(user);
  216. userSession.logIn().setSystemAdministrator();
  217. assertThat(ws.newRequest()
  218. .executeProtobuf(SearchWsResponse.class).getUsersList())
  219. .extracting(User::getLogin, User::getTokensCount)
  220. .containsExactlyInAnyOrder(tuple(user.getLogin(), 2));
  221. userSession.logIn();
  222. assertThat(ws.newRequest()
  223. .executeProtobuf(SearchWsResponse.class).getUsersList())
  224. .extracting(User::getLogin, User::hasTokensCount)
  225. .containsExactlyInAnyOrder(tuple(user.getLogin(), false));
  226. }
  227. @Test
  228. public void return_email_only_when_system_administer() {
  229. UserDto user = db.users().insertUser();
  230. userSession.logIn().setSystemAdministrator();
  231. assertThat(ws.newRequest()
  232. .executeProtobuf(SearchWsResponse.class).getUsersList())
  233. .extracting(User::getLogin, User::getEmail)
  234. .containsExactlyInAnyOrder(tuple(user.getLogin(), user.getEmail()));
  235. userSession.logIn();
  236. assertThat(ws.newRequest()
  237. .executeProtobuf(SearchWsResponse.class).getUsersList())
  238. .extracting(User::getLogin, User::hasEmail)
  239. .containsExactlyInAnyOrder(tuple(user.getLogin(), false));
  240. }
  241. @Test
  242. public void return_user_not_having_email() {
  243. UserDto user = db.users().insertUser(u -> u.setEmail(null));
  244. userSession.logIn().setSystemAdministrator();
  245. SearchWsResponse response = ws.newRequest()
  246. .executeProtobuf(SearchWsResponse.class);
  247. assertThat(response.getUsersList())
  248. .extracting(User::getLogin, User::hasEmail)
  249. .containsExactlyInAnyOrder(tuple(user.getLogin(), false));
  250. }
  251. @Test
  252. public void return_groups_only_when_system_administer() {
  253. UserDto user = db.users().insertUser();
  254. GroupDto group1 = db.users().insertGroup("group1");
  255. GroupDto group2 = db.users().insertGroup("group2");
  256. GroupDto group3 = db.users().insertGroup("group3");
  257. db.users().insertMember(group1, user);
  258. db.users().insertMember(group2, user);
  259. userSession.logIn().setSystemAdministrator();
  260. assertThat(ws.newRequest()
  261. .executeProtobuf(SearchWsResponse.class).getUsersList())
  262. .extracting(User::getLogin, u -> u.getGroups().getGroupsList())
  263. .containsExactlyInAnyOrder(tuple(user.getLogin(), asList(group1.getName(), group2.getName())));
  264. userSession.logIn();
  265. assertThat(ws.newRequest()
  266. .executeProtobuf(SearchWsResponse.class).getUsersList())
  267. .extracting(User::getLogin, User::hasGroups)
  268. .containsExactlyInAnyOrder(tuple(user.getLogin(), false));
  269. }
  270. @Test
  271. public void return_external_information() {
  272. UserDto user = db.users().insertUser();
  273. userSession.logIn().setSystemAdministrator();
  274. SearchWsResponse response = ws.newRequest()
  275. .executeProtobuf(SearchWsResponse.class);
  276. assertThat(response.getUsersList())
  277. .extracting(User::getLogin, User::getExternalIdentity, User::getExternalProvider)
  278. .containsExactlyInAnyOrder(tuple(user.getLogin(), user.getExternalLogin(), user.getExternalIdentityProvider()));
  279. }
  280. @Test
  281. public void return_external_identity_only_when_system_administer() {
  282. UserDto user = db.users().insertUser();
  283. userSession.logIn().setSystemAdministrator();
  284. assertThat(ws.newRequest()
  285. .executeProtobuf(SearchWsResponse.class).getUsersList())
  286. .extracting(User::getLogin, User::getExternalIdentity)
  287. .containsExactlyInAnyOrder(tuple(user.getLogin(), user.getExternalLogin()));
  288. userSession.logIn();
  289. assertThat(ws.newRequest()
  290. .executeProtobuf(SearchWsResponse.class).getUsersList())
  291. .extracting(User::getLogin, User::hasExternalIdentity)
  292. .containsExactlyInAnyOrder(tuple(user.getLogin(), false));
  293. }
  294. @Test
  295. public void only_return_login_and_name_when_not_logged() {
  296. UserDto user = db.users().insertUser();
  297. db.users().insertToken(user);
  298. GroupDto group = db.users().insertGroup();
  299. db.users().insertMember(group, user);
  300. userSession.anonymous();
  301. SearchWsResponse response = ws.newRequest()
  302. .executeProtobuf(SearchWsResponse.class);
  303. assertThat(response.getUsersList())
  304. .extracting(User::getLogin, User::getName, User::hasTokensCount, User::hasScmAccounts, User::hasAvatar, User::hasGroups, User::hasManaged)
  305. .containsExactlyInAnyOrder(tuple(user.getLogin(), user.getName(), false, false, false, false, false));
  306. }
  307. @Test
  308. public void return_last_connection_date_when_system_administer() {
  309. UserDto userWithLastConnectionDate = db.users().insertUser();
  310. db.users().updateLastConnectionDate(userWithLastConnectionDate, 10_000_000_000L);
  311. UserDto userWithoutLastConnectionDate = db.users().insertUser();
  312. userSession.logIn().setSystemAdministrator();
  313. SearchWsResponse response = ws.newRequest()
  314. .executeProtobuf(SearchWsResponse.class);
  315. assertThat(response.getUsersList())
  316. .extracting(User::getLogin, User::hasLastConnectionDate, User::getLastConnectionDate)
  317. .containsExactlyInAnyOrder(
  318. tuple(userWithLastConnectionDate.getLogin(), true, formatDateTime(10_000_000_000L)),
  319. tuple(userWithoutLastConnectionDate.getLogin(), false, ""));
  320. }
  321. @Test
  322. public void return_all_fields_for_logged_user() {
  323. UserDto user = db.users().insertUser();
  324. db.users().updateLastConnectionDate(user, 10_000_000_000L);
  325. db.users().insertToken(user);
  326. db.users().insertToken(user);
  327. GroupDto group = db.users().insertGroup();
  328. db.users().insertMember(group, user);
  329. UserDto otherUser = db.users().insertUser();
  330. userSession.logIn(user);
  331. assertThat(ws.newRequest().setParam("q", user.getLogin())
  332. .executeProtobuf(SearchWsResponse.class).getUsersList())
  333. .extracting(User::getLogin, User::getName, User::getEmail, User::getExternalIdentity, User::getExternalProvider,
  334. User::hasScmAccounts, User::hasAvatar, User::hasGroups, User::getTokensCount, User::hasLastConnectionDate, User::hasManaged)
  335. .containsExactlyInAnyOrder(
  336. tuple(user.getLogin(), user.getName(), user.getEmail(), user.getExternalLogin(), user.getExternalIdentityProvider(), true, true, true, 2, true, true));
  337. userSession.logIn(otherUser);
  338. assertThat(ws.newRequest().setParam("q", user.getLogin())
  339. .executeProtobuf(SearchWsResponse.class).getUsersList())
  340. .extracting(User::getLogin, User::getName, User::hasEmail, User::hasExternalIdentity, User::hasExternalProvider,
  341. User::hasScmAccounts, User::hasAvatar, User::hasGroups, User::hasTokensCount, User::hasLastConnectionDate)
  342. .containsExactlyInAnyOrder(
  343. tuple(user.getLogin(), user.getName(), false, false, true, true, true, false, false, false));
  344. }
  345. @Test
  346. public void search_whenNoPagingInformationProvided_setsDefaultValues() {
  347. userSession.logIn();
  348. IntStream.rangeClosed(0, 9).forEach(i -> db.users().insertUser(u -> u.setLogin("user-" + i).setName("User " + i)));
  349. SearchWsResponse response = ws.newRequest()
  350. .executeProtobuf(SearchWsResponse.class);
  351. assertThat(response.getPaging().getTotal()).isEqualTo(10);
  352. assertThat(response.getPaging().getPageIndex()).isEqualTo(1);
  353. assertThat(response.getPaging().getPageSize()).isEqualTo(50);
  354. }
  355. @Test
  356. public void search_with_paging() {
  357. userSession.logIn();
  358. IntStream.rangeClosed(0, 9).forEach(i -> db.users().insertUser(u -> u.setLogin("user-" + i).setName("User " + i)));
  359. SearchWsResponse response = ws.newRequest()
  360. .setParam(Param.PAGE_SIZE, "5")
  361. .executeProtobuf(SearchWsResponse.class);
  362. assertThat(response.getUsersList())
  363. .extracting(User::getLogin)
  364. .containsExactly("user-0", "user-1", "user-2", "user-3", "user-4");
  365. assertThat(response.getPaging())
  366. .extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal)
  367. .containsExactly(1, 5, 10);
  368. response = ws.newRequest()
  369. .setParam(Param.PAGE_SIZE, "5")
  370. .setParam(Param.PAGE, "2")
  371. .executeProtobuf(SearchWsResponse.class);
  372. assertThat(response.getUsersList())
  373. .extracting(User::getLogin)
  374. .containsExactly("user-5", "user-6", "user-7", "user-8", "user-9");
  375. assertThat(response.getPaging())
  376. .extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal)
  377. .containsExactly(2, 5, 10);
  378. }
  379. @Test
  380. public void return_empty_result_when_no_user() {
  381. userSession.logIn();
  382. SearchWsResponse response = ws.newRequest()
  383. .executeProtobuf(SearchWsResponse.class);
  384. assertThat(response.getUsersList()).isEmpty();
  385. assertThat(response.getPaging().getTotal()).isZero();
  386. }
  387. @Test
  388. public void test_json_example() {
  389. UserDto fmallet = db.users().insertUser(u -> u.setLogin("fmallet").setName("Freddy Mallet").setEmail("f@m.com")
  390. .setLocal(true)
  391. .setScmAccounts(emptyList())
  392. .setExternalLogin("fmallet")
  393. .setExternalIdentityProvider("sonarqube"));
  394. long lastConnection = DateUtils.parseOffsetDateTime("2019-03-27T09:51:50+0100").toInstant().toEpochMilli();
  395. fmallet = db.users().updateLastConnectionDate(fmallet, lastConnection);
  396. fmallet = db.users().updateSonarLintLastConnectionDate(fmallet, lastConnection);
  397. UserDto simon = db.users().insertUser(u -> u.setLogin("sbrandhof").setName("Simon").setEmail("s.brandhof@company.tld")
  398. .setLocal(false)
  399. .setExternalLogin("sbrandhof@ldap.com")
  400. .setExternalIdentityProvider("sonarqube")
  401. .setScmAccounts(asList("simon.brandhof", "s.brandhof@company.tld")));
  402. mockUsersAsManaged(simon.getUuid());
  403. GroupDto sonarUsers = db.users().insertGroup("sonar-users");
  404. GroupDto sonarAdministrators = db.users().insertGroup("sonar-administrators");
  405. db.users().insertMember(sonarUsers, simon);
  406. db.users().insertMember(sonarUsers, fmallet);
  407. db.users().insertMember(sonarAdministrators, fmallet);
  408. db.users().insertToken(simon);
  409. db.users().insertToken(simon);
  410. db.users().insertToken(simon);
  411. db.users().insertToken(fmallet);
  412. userSession.logIn().setSystemAdministrator();
  413. String response = ws.newRequest().execute().getInput();
  414. assertJson(response).isSimilarTo(getClass().getResource("search-example.json"));
  415. }
  416. @Test
  417. public void test_definition() {
  418. WebService.Action action = ws.getDef();
  419. assertThat(action).isNotNull();
  420. assertThat(action.isPost()).isFalse();
  421. assertThat(action.responseExampleAsString()).isNotEmpty();
  422. assertThat(action.params()).hasSize(9);
  423. }
  424. @Test
  425. public void search_whenFilteringConnectionDate_shouldApplyFilter() {
  426. userSession.logIn().setSystemAdministrator();
  427. final Instant lastConnection = Instant.now();
  428. UserDto user = db.users().insertUser(u -> u
  429. .setLogin("user-%_%-login")
  430. .setName("user-name")
  431. .setEmail("user@mail.com")
  432. .setLocal(true)
  433. .setScmAccounts(singletonList("user1")));
  434. user = db.users().updateLastConnectionDate(user, lastConnection.toEpochMilli());
  435. user = db.users().updateSonarLintLastConnectionDate(user, lastConnection.toEpochMilli());
  436. assertThat(ws.newRequest()
  437. .setParam("q", "user-%_%-")
  438. .executeProtobuf(SearchWsResponse.class).getUsersList())
  439. .extracting(User::getLogin)
  440. .containsExactlyInAnyOrder(user.getLogin());
  441. assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_FROM, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), true);
  442. assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_FROM, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), false);
  443. assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_TO, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), false);
  444. assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_TO, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), true);
  445. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), true);
  446. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), false);
  447. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), false);
  448. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), true);
  449. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection, user.getLogin(), true);
  450. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection, user.getLogin(), true);
  451. }
  452. @Test
  453. public void search_whenNoLastConnection_shouldReturnForBeforeOnly() {
  454. userSession.logIn().setSystemAdministrator();
  455. final Instant lastConnection = Instant.now();
  456. UserDto user = db.users().insertUser(u -> u
  457. .setLogin("user-%_%-login")
  458. .setName("user-name")
  459. .setEmail("user@mail.com")
  460. .setLocal(true)
  461. .setScmAccounts(singletonList("user1")));
  462. assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_FROM, lastConnection, user.getLogin(), false);
  463. assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_TO, lastConnection, user.getLogin(), true);
  464. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection, user.getLogin(), false);
  465. assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection, user.getLogin(), true);
  466. }
  467. @Test
  468. public void search_whenNotAdmin_shouldThrowForbidden() {
  469. userSession.logIn();
  470. Stream.of(SearchAction.LAST_CONNECTION_DATE_FROM, SearchAction.LAST_CONNECTION_DATE_TO,
  471. SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO)
  472. .map(param -> ws.newRequest().setParam(param, formatDateTime(OffsetDateTime.now())))
  473. .forEach(SearchActionIT::assertForbiddenException);
  474. }
  475. private static void assertForbiddenException(TestRequest testRequest) {
  476. assertThatThrownBy(() -> testRequest.executeProtobuf(SearchWsResponse.class))
  477. .asInstanceOf(InstanceOfAssertFactories.type(ServerException.class))
  478. .extracting(ServerException::httpCode)
  479. .isEqualTo(403);
  480. }
  481. private void assertUserWithFilter(String field, Instant filterValue, String userLogin, boolean isExpectedToBeThere) {
  482. var assertion = assertThat(ws.newRequest()
  483. .setParam("q", "user-%_%-")
  484. .setParam(field, DateUtils.formatDateTime(filterValue.toEpochMilli()))
  485. .executeProtobuf(SearchWsResponse.class).getUsersList());
  486. if (isExpectedToBeThere) {
  487. assertion
  488. .extracting(User::getLogin)
  489. .containsExactlyInAnyOrder(userLogin);
  490. } else {
  491. assertion.isEmpty();
  492. }
  493. }
  494. private void mockUsersAsManaged(String... userUuids) {
  495. when(managedInstanceService.getUserUuidToManaged(any(), any())).thenAnswer(invocation ->
  496. {
  497. Set<?> allUsersUuids = invocation.getArgument(1, Set.class);
  498. return allUsersUuids.stream()
  499. .map(userUuid -> (String) userUuid)
  500. .collect(toMap(identity(), userUuid -> Set.of(userUuids).contains(userUuid)));
  501. }
  502. );
  503. }
  504. }