/* * SonarQube * Copyright (C) 2009-2025 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.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.ArgumentCaptor; import org.sonar.api.impl.utils.TestSystem2; import org.sonar.api.utils.DateUtils; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.model.UserNewValue; import static org.apache.commons.lang3.RandomStringUtils.secure; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.sonar.db.user.GroupTesting.newGroupDto; import static org.sonar.db.user.UserTesting.newUserDto; class UserDaoWithPersisterIT { private static final long NOW = 1_500_000_000_000L; private final AuditPersister auditPersister = mock(AuditPersister.class); private final TestSystem2 system2 = new TestSystem2().setNow(NOW); private final ArgumentCaptor newValueCaptor = ArgumentCaptor.forClass(UserNewValue.class); @RegisterExtension private final DbTester db = DbTester.create(system2, auditPersister); private final DbClient dbClient = db.getDbClient(); private final UserDao underTest = db.getDbClient().userDao(); @Test void insertUserIsPersisted() { UserDto userDto = new UserDto() .setLogin("john") .setName("John") .setEmail("jo@hn.com") .setExternalLogin("john-1") .setExternalIdentityProvider("sonarqube") .setExternalId("EXT_ID"); underTest.insert(db.getSession(), userDto); db.getSession().commit(); UserDto user = underTest.selectActiveUserByLogin(db.getSession(), "john"); verify(auditPersister).addUser(eq(db.getSession()), newValueCaptor.capture()); UserNewValue newValue = newValueCaptor.getValue(); assertThat(newValue) .extracting(UserNewValue::getUserUuid, UserNewValue::getUserLogin) .containsExactly(user.getUuid(), user.getLogin()); assertThat(newValue.toString()).doesNotContain("name"); } @Test void updateUserIsPersisted() { UserDto user = db.users().insertUser(u -> u .setLogin("john") .setName("John") .setEmail("jo@hn.com") .setActive(true) .setLocal(true) .setResetPassword(false)); UserDto updatedUser = newUserDto() .setUuid(user.getUuid()) .setLogin("johnDoo") .setName("John Doo") .setEmail("jodoo@hn.com") .setScmAccounts(List.of("jo.hn", "john2", "johndoo")) .setActive(false) .setResetPassword(true) .setSalt("12345") .setCryptedPassword("abcde") .setHashMethod("PBKDF2") .setExternalLogin("johngithub") .setExternalIdentityProvider("github") .setExternalId("EXT_ID") .setLocal(false) .setHomepageType("project") .setHomepageParameter("OB1") .setLastConnectionDate(10_000_000_000L); underTest.update(db.getSession(), updatedUser); verify(auditPersister).updateUser(eq(db.getSession()), newValueCaptor.capture()); UserNewValue newValue = newValueCaptor.getValue(); assertThat(newValue) .extracting(UserNewValue::getUserUuid, UserNewValue::getUserLogin, UserNewValue::getName, UserNewValue::getEmail, UserNewValue::isActive, UserNewValue::getScmAccounts, UserNewValue::getExternalId, UserNewValue::getExternalLogin, UserNewValue::getExternalIdentityProvider, UserNewValue::isLocal, UserNewValue::getLastConnectionDate) .containsExactly(updatedUser.getUuid(), updatedUser.getLogin(), updatedUser.getName(), updatedUser.getEmail(), updatedUser.isActive(), updatedUser.getSortedScmAccounts(), updatedUser.getExternalId(), updatedUser.getExternalLogin(), updatedUser.getExternalIdentityProvider(), updatedUser.isLocal(), updatedUser.getLastConnectionDate()); assertThat(newValue.toString()) .contains("name") .contains(DateUtils.formatDateTime(updatedUser.getLastConnectionDate())); } @Test void updateUserWithoutTrackIsNotPersisted() { UserDto user = db.users().insertUser(u -> u .setLogin("john") .setName("John") .setEmail("jo@hn.com") .setActive(true) .setLocal(true) .setResetPassword(false)); verify(auditPersister).addUser(eq(db.getSession()), newValueCaptor.capture()); UserDto updatedUser = newUserDto() .setUuid(user.getUuid()) .setLogin("johnDoo"); underTest.update(db.getSession(), updatedUser, false); verifyNoMoreInteractions(auditPersister); } @Test void deactivateUserIsPersisted() { UserDto user = insertActiveUser(); insertUserGroup(user); underTest.update(db.getSession(), user.setLastConnectionDate(10_000_000_000L)); db.getSession().commit(); underTest.deactivateUser(db.getSession(), user); verify(auditPersister).deactivateUser(eq(db.getSession()), newValueCaptor.capture()); assertThat(newValueCaptor.getValue()) .extracting(UserNewValue::getUserUuid, UserNewValue::getUserLogin) .containsExactly(user.getUuid(), user.getLogin()); } private UserDto insertActiveUser() { UserDto dto = newUserDto().setActive(true); underTest.insert(db.getSession(), dto); return dto; } private UserGroupDto insertUserGroup(UserDto user) { GroupDto group = newGroupDto().setName(secure().nextAlphanumeric(30)); dbClient.groupDao().insert(db.getSession(), group); UserGroupDto dto = new UserGroupDto().setUserUuid(user.getUuid()).setGroupUuid(group.getUuid()); dbClient.userGroupDao().insert(db.getSession(), dto, group.getName(), user.getLogin()); return dto; } }