/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.db.user; import java.util.Collection; import java.util.Collections; import java.util.List; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.user.UserQuery; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.RowNotFoundException; import static java.util.Arrays.asList; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.db.user.GroupTesting.newGroupDto; import static org.sonar.db.user.UserTesting.newUserDto; public class UserDaoTest { private static final long NOW = 1_500_000_000_000L; private System2 system2 = mock(System2.class); @Rule public ExpectedException thrown = ExpectedException.none(); @Rule public DbTester db = DbTester.create(system2); private DbClient dbClient = db.getDbClient(); private DbSession session = db.getSession(); private UserDao underTest = db.getDbClient().userDao(); @Before public void setUp() throws Exception { when(system2.now()).thenReturn(NOW); } @Test public void selectUsersIds() { db.prepareDbUnit(getClass(), "selectUsersByIds.xml"); Collection<UserDto> users = underTest.selectByIds(session, asList(100, 101, 987)); assertThat(users).hasSize(2); assertThat(users).extracting("login").containsOnly("marius", "inactive_user"); assertThat(underTest.selectByIds(session, Collections.emptyList())).isEmpty(); } @Test public void selectUserByLogin_ignore_inactive() { db.prepareDbUnit(getClass(), "selectActiveUserByLogin.xml"); UserDto user = underTest.selectUserById(session, 50); assertThat(user.getLogin()).isEqualTo("inactive_user"); user = underTest.selectActiveUserByLogin(session, "inactive_user"); assertThat(user).isNull(); } @Test public void selectUserByLogin_not_found() { db.prepareDbUnit(getClass(), "selectActiveUserByLogin.xml"); UserDto user = underTest.selectActiveUserByLogin(session, "not_found"); assertThat(user).isNull(); } @Test public void selectUsersByLogins() { db.prepareDbUnit(getClass(), "selectUsersByLogins.xml"); Collection<UserDto> users = underTest.selectByLogins(session, asList("marius", "inactive_user", "other")); assertThat(users).hasSize(2); assertThat(users).extracting("login").containsOnly("marius", "inactive_user"); } @Test public void selectUsersByLogins_empty_logins() { // no need to access db Collection<UserDto> users = underTest.selectByLogins(session, Collections.emptyList()); assertThat(users).isEmpty(); } @Test public void selectByOrderedLogins() { underTest.insert(session, newUserDto().setLogin("U1").setActive(true)); underTest.insert(session, newUserDto().setLogin("U2").setActive(true)); session.commit(); Iterable<UserDto> users = underTest.selectByOrderedLogins(session, asList("U1", "U2", "U3")); assertThat(users).extracting("login").containsExactly("U1", "U2"); users = underTest.selectByOrderedLogins(session, asList("U2", "U3", "U1")); assertThat(users).extracting("login").containsExactly("U2", "U1"); assertThat(underTest.selectByOrderedLogins(session, Collections.emptyList())).isEmpty(); } @Test public void selectUsersByQuery_all() { db.prepareDbUnit(getClass(), "selectUsersByQuery.xml"); UserQuery query = UserQuery.builder().includeDeactivated().build(); List<UserDto> users = underTest.selectUsers(session, query); assertThat(users).hasSize(2); } @Test public void selectUsersByQuery_only_actives() { db.prepareDbUnit(getClass(), "selectUsersByQuery.xml"); UserQuery query = UserQuery.ALL_ACTIVES; List<UserDto> users = underTest.selectUsers(session, query); assertThat(users).hasSize(1); assertThat(users.get(0).getName()).isEqualTo("Marius"); } @Test public void selectUsersByQuery_filter_by_login() { db.prepareDbUnit(getClass(), "selectUsersByQuery.xml"); UserQuery query = UserQuery.builder().logins("marius", "john").build(); List<UserDto> users = underTest.selectUsers(session, query); assertThat(users).hasSize(1); assertThat(users.get(0).getName()).isEqualTo("Marius"); } @Test public void selectUsersByQuery_search_by_login_text() { db.prepareDbUnit(getClass(), "selectUsersByText.xml"); UserQuery query = UserQuery.builder().searchText("sbr").build(); List<UserDto> users = underTest.selectUsers(session, query); assertThat(users).hasSize(1); assertThat(users.get(0).getLogin()).isEqualTo("sbrandhof"); } @Test public void selectUsersByQuery_search_by_name_text() { db.prepareDbUnit(getClass(), "selectUsersByText.xml"); UserQuery query = UserQuery.builder().searchText("Simon").build(); List<UserDto> users = underTest.selectUsers(session, query); assertThat(users).hasSize(1); assertThat(users.get(0).getLogin()).isEqualTo("sbrandhof"); } @Test public void selectUsersByQuery_escape_special_characters_in_like() { db.prepareDbUnit(getClass(), "selectUsersByText.xml"); UserQuery query = UserQuery.builder().searchText("%s%").build(); // we expect really a login or name containing the 3 characters "%s%" List<UserDto> users = underTest.selectUsers(session, query); assertThat(users).isEmpty(); } @Test public void selectUsers_returns_both_only_root_or_only_non_root_depending_on_mustBeRoot_and_mustNotBeRoot_calls_on_query() { UserDto user1 = insertUser(true); UserDto root1 = insertRootUser(newUserDto()); UserDto user2 = insertUser(true); UserDto root2 = insertRootUser(newUserDto()); assertThat(underTest.selectUsers(session, UserQuery.builder().build())) .extracting(UserDto::getLogin) .containsOnly(user1.getLogin(), user2.getLogin(), root1.getLogin(), root2.getLogin()); assertThat(underTest.selectUsers(session, UserQuery.builder().mustBeRoot().build())) .extracting(UserDto::getLogin) .containsOnly(root1.getLogin(), root2.getLogin()); assertThat(underTest.selectUsers(session, UserQuery.builder().mustNotBeRoot().build())) .extracting(UserDto::getLogin) .containsOnly(user1.getLogin(), user2.getLogin()); } @Test public void countRootUsersButLogin_returns_0_when_there_is_no_user_at_all() { assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(0); } @Test public void countRootUsersButLogin_returns_0_when_there_is_no_root() { underTest.insert(session, newUserDto()); session.commit(); assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(0); } @Test public void countRootUsersButLogin_returns_0_when_there_is_no_active_root() { insertNonRootUser(newUserDto()); insertInactiveRootUser(newUserDto()); session.commit(); assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(0); } @Test public void countRootUsersButLogin_returns_count_of_all_active_roots_when_there_specified_login_does_not_exist() { insertRootUser(newUserDto()); insertNonRootUser(newUserDto()); insertRootUser(newUserDto()); insertRootUser(newUserDto()); insertInactiveRootUser(newUserDto()); insertInactiveRootUser(newUserDto()); session.commit(); assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(3); } @Test public void countRootUsersButLogin_returns_count_of_all_active_roots_when_specified_login_is_not_root() { insertRootUser(newUserDto()); String login = insertNonRootUser(newUserDto()).getLogin(); insertRootUser(newUserDto()); insertRootUser(newUserDto()); insertInactiveRootUser(newUserDto()); insertInactiveRootUser(newUserDto()); session.commit(); assertThat(underTest.countRootUsersButLogin(session, login)).isEqualTo(3); } @Test public void countRootUsersButLogin_returns_count_of_all_active_roots_when_specified_login_is_inactive_root() { insertRootUser(newUserDto()); insertNonRootUser(newUserDto()); insertRootUser(newUserDto()); insertRootUser(newUserDto()); String inactiveRootLogin = insertInactiveRootUser(newUserDto()).getLogin(); insertInactiveRootUser(newUserDto()); session.commit(); assertThat(underTest.countRootUsersButLogin(session, inactiveRootLogin)).isEqualTo(3); } @Test public void countRootUsersButLogin_returns_count_of_all_active_roots_minus_one_when_specified_login_is_active_root() { insertRootUser(newUserDto()); insertNonRootUser(newUserDto()); insertRootUser(newUserDto()); String rootLogin = insertRootUser(newUserDto()).getLogin(); insertInactiveRootUser(newUserDto()); insertInactiveRootUser(newUserDto()); session.commit(); assertThat(underTest.countRootUsersButLogin(session, rootLogin)).isEqualTo(2); } private UserDto insertInactiveRootUser(UserDto dto) { insertRootUser(dto); dto.setActive(false); underTest.update(session, dto); session.commit(); return dto; } private UserDto insertRootUser(UserDto dto) { underTest.insert(session, dto); underTest.setRoot(session, dto.getLogin(), true); session.commit(); return dto; } private UserDto insertNonRootUser(UserDto dto) { underTest.insert(session, dto); session.commit(); return dto; } @Test public void insert_user() { Long date = DateUtils.parseDate("2014-06-20").getTime(); UserDto userDto = new UserDto() .setId(1) .setLogin("john") .setName("John") .setEmail("jo@hn.com") .setScmAccounts(",jo.hn,john2,") .setActive(true) .setSalt("1234") .setCryptedPassword("abcd") .setExternalIdentity("johngithub") .setExternalIdentityProvider("github") .setLocal(true) .setCreatedAt(date) .setUpdatedAt(date); underTest.insert(db.getSession(), userDto); db.getSession().commit(); UserDto user = underTest.selectActiveUserByLogin(session, "john"); assertThat(user).isNotNull(); assertThat(user.getId()).isNotNull(); assertThat(user.getLogin()).isEqualTo("john"); assertThat(user.getName()).isEqualTo("John"); assertThat(user.getEmail()).isEqualTo("jo@hn.com"); assertThat(user.isActive()).isTrue(); assertThat(user.getScmAccounts()).isEqualTo(",jo.hn,john2,"); assertThat(user.getSalt()).isEqualTo("1234"); assertThat(user.getCryptedPassword()).isEqualTo("abcd"); assertThat(user.getExternalIdentity()).isEqualTo("johngithub"); assertThat(user.getExternalIdentityProvider()).isEqualTo("github"); assertThat(user.isLocal()).isTrue(); assertThat(user.isRoot()).isFalse(); assertThat(user.getCreatedAt()).isEqualTo(date); assertThat(user.getUpdatedAt()).isEqualTo(date); } @Test public void update_user() { UserDto existingUser = new UserDto() .setLogin("john") .setName("John") .setEmail("jo@hn.com") .setCreatedAt(1418215735482L) .setUpdatedAt(1418215735482L) .setActive(true) .setLocal(true); db.getDbClient().userDao().insert(db.getSession(), existingUser); db.getSession().commit(); UserDto userDto = new UserDto() .setId(1) .setLogin("john") .setName("John Doo") .setEmail("jodoo@hn.com") .setScmAccounts(",jo.hn,john2,johndoo,") .setActive(false) .setSalt("12345") .setCryptedPassword("abcde") .setExternalIdentity("johngithub") .setExternalIdentityProvider("github") .setLocal(false) .setUpdatedAt(1500000000000L); underTest.update(db.getSession(), userDto); db.getSession().commit(); UserDto user = underTest.selectUserById(db.getSession(), existingUser.getId()); assertThat(user).isNotNull(); assertThat(user.getId()).isEqualTo(existingUser.getId()); assertThat(user.getLogin()).isEqualTo("john"); assertThat(user.getName()).isEqualTo("John Doo"); assertThat(user.getEmail()).isEqualTo("jodoo@hn.com"); assertThat(user.isActive()).isFalse(); assertThat(user.getScmAccounts()).isEqualTo(",jo.hn,john2,johndoo,"); assertThat(user.getSalt()).isEqualTo("12345"); assertThat(user.getCryptedPassword()).isEqualTo("abcde"); assertThat(user.getExternalIdentity()).isEqualTo("johngithub"); assertThat(user.getExternalIdentityProvider()).isEqualTo("github"); assertThat(user.isLocal()).isFalse(); assertThat(user.isRoot()).isFalse(); assertThat(user.getCreatedAt()).isEqualTo(1418215735482L); assertThat(user.getUpdatedAt()).isEqualTo(1500000000000L); } @Test public void deactivate_user() throws Exception { UserDto user = newActiveUser(); insertUserGroup(user); UserDto otherUser = newActiveUser(); session.commit(); underTest.deactivateUserById(session, user.getId()); UserDto userReloaded = underTest.selectUserById(session, user.getId()); assertThat(userReloaded.isActive()).isFalse(); assertThat(userReloaded.getEmail()).isNull(); assertThat(userReloaded.getScmAccounts()).isNull(); assertThat(userReloaded.getSalt()).isNull(); assertThat(userReloaded.getCryptedPassword()).isNull(); assertThat(userReloaded.getExternalIdentity()).isNull(); assertThat(userReloaded.getExternalIdentityProvider()).isNull(); assertThat(userReloaded.isRoot()).isFalse(); assertThat(userReloaded.getUpdatedAt()).isEqualTo(NOW); assertThat(underTest.selectUserById(session, otherUser.getId())).isNotNull(); } @Test public void does_not_fail_to_deactivate_missing_user() { underTest.deactivateUserById(session, 123); } @Test public void select_by_login() { db.prepareDbUnit(getClass(), "select_by_login.xml"); UserDto dto = underTest.selectOrFailByLogin(session, "marius"); assertThat(dto.getId()).isEqualTo(101); assertThat(dto.getLogin()).isEqualTo("marius"); assertThat(dto.getName()).isEqualTo("Marius"); assertThat(dto.getEmail()).isEqualTo("marius@lesbronzes.fr"); assertThat(dto.isActive()).isTrue(); assertThat(dto.getScmAccountsAsList()).containsOnly("ma", "marius33"); assertThat(dto.getSalt()).isEqualTo("79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8365"); assertThat(dto.getCryptedPassword()).isEqualTo("650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"); assertThat(dto.isRoot()).isFalse(); assertThat(dto.getCreatedAt()).isEqualTo(1418215735482L); assertThat(dto.getUpdatedAt()).isEqualTo(1418215735485L); dto = underTest.selectOrFailByLogin(session, "sbrandhof"); assertThat(dto.isRoot()).isTrue(); } @Test public void select_nullable_by_scm_account() { db.prepareDbUnit(getClass(), "select_nullable_by_scm_account.xml"); List<UserDto> results = underTest.selectByScmAccountOrLoginOrEmail(session, "ma"); assertThat(results).hasSize(1); assertThat(results.get(0).getLogin()).isEqualTo("marius"); results = underTest.selectByScmAccountOrLoginOrEmail(session, "marius"); assertThat(results).hasSize(1); assertThat(results.get(0).getLogin()).isEqualTo("marius"); results = underTest.selectByScmAccountOrLoginOrEmail(session, "marius@lesbronzes.fr"); assertThat(results).hasSize(1); assertThat(results.get(0).getLogin()).isEqualTo("marius"); results = underTest.selectByScmAccountOrLoginOrEmail(session, "marius@lesbronzes.fr"); assertThat(results).hasSize(1); assertThat(results.get(0).getLogin()).isEqualTo("marius"); results = underTest.selectByScmAccountOrLoginOrEmail(session, "m"); assertThat(results).isEmpty(); results = underTest.selectByScmAccountOrLoginOrEmail(session, "unknown"); assertThat(results).isEmpty(); } @Test public void select_nullable_by_scm_account_return_many_results_when_same_email_is_used_by_many_users() { db.prepareDbUnit(getClass(), "select_nullable_by_scm_account_return_many_results_when_same_email_is_used_by_many_users.xml"); List<UserDto> results = underTest.selectByScmAccountOrLoginOrEmail(session, "marius@lesbronzes.fr"); assertThat(results).hasSize(2); } @Test public void select_by_login_with_unknown_login() { try { underTest.selectOrFailByLogin(session, "unknown"); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(RowNotFoundException.class).hasMessage("User with login 'unknown' has not been found"); } } @Test public void select_nullable_by_login() { db.prepareDbUnit(getClass(), "select_by_login.xml"); assertThat(underTest.selectByLogin(session, "marius")).isNotNull(); assertThat(underTest.selectByLogin(session, "unknown")).isNull(); } @Test public void exists_by_email() throws Exception { UserDto activeUser = newActiveUser(); UserDto disableUser = insertUser(false); assertThat(underTest.doesEmailExist(session, activeUser.getEmail())).isTrue(); assertThat(underTest.doesEmailExist(session, disableUser.getEmail())).isFalse(); assertThat(underTest.doesEmailExist(session, "unknown")).isFalse(); } @Test public void setRoot_does_not_fail_on_non_existing_login() { underTest.setRoot(session, "unkown", true); underTest.setRoot(session, "unkown", false); } @Test public void setRoot_set_root_flag_of_specified_user_to_specified_value_and_updates_udpateAt() { String login = newActiveUser().getLogin(); UserDto otherUser = newActiveUser(); assertThat(underTest.selectByLogin(session, login).isRoot()).isEqualTo(false); assertThat(underTest.selectByLogin(session, otherUser.getLogin()).isRoot()).isEqualTo(false); // does not fail when changing to same value when(system2.now()).thenReturn(15_000L); commit(() -> underTest.setRoot(session, login, false)); verifyRootAndUpdatedAt(login, false, 15_000L); verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); // change value when(system2.now()).thenReturn(26_000L); commit(() -> underTest.setRoot(session, login, true)); verifyRootAndUpdatedAt(login, true, 26_000L); verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); // does not fail when changing to same value when(system2.now()).thenReturn(37_000L); commit(() -> underTest.setRoot(session, login, true)); verifyRootAndUpdatedAt(login, true, 37_000L); verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); // change value back when(system2.now()).thenReturn(48_000L); commit(() -> underTest.setRoot(session, login, false)); verifyRootAndUpdatedAt(login, false, 48_000L); verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); } private void verifyRootAndUpdatedAt(String login1, boolean root, long updatedAt) { UserDto userDto = underTest.selectByLogin(session, login1); assertThat(userDto.isRoot()).isEqualTo(root); assertThat(userDto.getUpdatedAt()).isEqualTo(updatedAt); } @Test public void setRoot_has_no_effect_on_root_flag_of_inactive_user() { String nonRootInactiveUser = insertUser(false).getLogin(); commit(() -> underTest.setRoot(session, nonRootInactiveUser, true)); assertThat(underTest.selectByLogin(session, nonRootInactiveUser).isRoot()).isFalse(); // create inactive root user UserDto rootUser = newActiveUser(); commit(() -> underTest.setRoot(session, rootUser.getLogin(), true)); rootUser.setActive(false); commit(() -> underTest.update(session, rootUser)); UserDto inactiveRootUser = underTest.selectByLogin(session, rootUser.getLogin()); assertThat(inactiveRootUser.isRoot()).isTrue(); assertThat(inactiveRootUser.isActive()).isFalse(); commit(() -> underTest.setRoot(session, inactiveRootUser.getLogin(), false)); assertThat(underTest.selectByLogin(session, inactiveRootUser.getLogin()).isRoot()).isTrue(); } private void commit(Runnable runnable) { runnable.run(); session.commit(); } private UserDto newActiveUser() { return insertUser(true); } private UserDto insertUser(boolean active) { UserDto dto = newUserDto().setActive(active); underTest.insert(session, dto); return dto; } private UserGroupDto insertUserGroup(UserDto user) { GroupDto group = newGroupDto().setName(randomAlphanumeric(30)); dbClient.groupDao().insert(session, group); UserGroupDto dto = new UserGroupDto().setUserId(user.getId()).setGroupId(group.getId()); dbClient.userGroupDao().insert(session, dto); return dto; } }