-INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, HASH_METHOD, IS_ROOT, ONBOARDED, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, '$2a$12$uCkkXmhW5ThVK8mpBvnXOOJRLd64LJeHTeCkSuB3lfaR2N0AYBaSi', null, 'BCRYPT', false, false, '1418215735482', '1418215735482');
+INSERT INTO USERS(ID, UUID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, HASH_METHOD, IS_ROOT, ONBOARDED, CREATED_AT, UPDATED_AT) VALUES (1, 'UuidnciQUUs7Zd3KPvFD', 'admin', 'Administrator', '', 'admin', 'sonarqube', true, '$2a$12$uCkkXmhW5ThVK8mpBvnXOOJRLd64LJeHTeCkSuB3lfaR2N0AYBaSi', null, 'BCRYPT', false, false, '1418215735482', '1418215735482');
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
INSERT INTO GROUPS(ID, ORGANIZATION_UUID, NAME, DESCRIPTION, CREATED_AT, UPDATED_AT) VALUES (1, 'AVdqnciQUUs7Zd3KPvFD', 'sonar-administrators', 'System administrators', '2011-09-26 22:27:51.0', '2011-09-26 22:27:51.0');
CREATE TABLE "USERS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "UUID" VARCHAR(40),
"LOGIN" VARCHAR(255),
"NAME" VARCHAR(200),
"EMAIL" VARCHAR(100),
import javax.annotation.Nonnull;
import org.sonar.api.user.UserQuery;
import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.RowNotFoundException;
public class UserDao implements Dao {
private final System2 system2;
+ private final UuidFactory uuidFactory;
- public UserDao(System2 system2) {
+
+ public UserDao(System2 system2, UuidFactory uuidFactory) {
this.system2 = system2;
+ this.uuidFactory = uuidFactory;
}
@CheckForNull
public UserDto insert(DbSession session, UserDto dto) {
long now = system2.now();
- mapper(session).insert(dto, now);
- dto.setCreatedAt(now);
- dto.setUpdatedAt(now);
+ mapper(session).insert(dto.setUuid(uuidFactory.create()).setCreatedAt(now).setUpdatedAt(now));
return dto;
}
public UserDto update(DbSession session, UserDto dto) {
- long now = system2.now();
- mapper(session).update(dto, now);
- dto.setUpdatedAt(now);
+ mapper(session).update(dto.setUpdatedAt(system2.now()));
return dto;
}
public class UserDto {
public static final char SCM_ACCOUNTS_SEPARATOR = '\n';
+ /** Technical unique identifier, can't be null */
+ private String uuid;
private Integer id;
private String login;
private String name;
private boolean root = false;
private boolean onboarded = false;
+ public String getUuid() {
+ return uuid;
+ }
+
+ UserDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
public Integer getId() {
return id;
}
*/
long countRootUsersButLogin(@Param("login") String login);
- void insert(@Param("user") UserDto userDto, @Param("now") long now);
+ void insert(@Param("user") UserDto userDto);
- void update(@Param("user") UserDto userDto, @Param("now") long now);
+ void update(@Param("user") UserDto userDto);
void setRoot(@Param("login") String login, @Param("root") boolean root, @Param("now") long now);
<sql id="userColumns">
u.id as id,
+ u.uuid as uuid,
u.login as login,
u.name as name,
u.email as email,
<insert id="insert" parameterType="map" keyColumn="id" useGeneratedKeys="true" keyProperty="user.id">
insert into users (
+ uuid,
login,
name,
email,
homepage_type,
homepage_parameter
) values (
+ #{user.uuid,jdbcType=VARCHAR},
#{user.login,jdbcType=VARCHAR},
#{user.name,jdbcType=VARCHAR},
#{user.email,jdbcType=VARCHAR},
#{user.hashMethod,jdbcType=VARCHAR},
#{user.root,jdbcType=BOOLEAN},
#{user.onboarded,jdbcType=BOOLEAN},
- #{now,jdbcType=BIGINT},
- #{now,jdbcType=BIGINT},
+ #{user.createdAt,jdbcType=BIGINT},
+ #{user.updatedAt,jdbcType=BIGINT},
#{user.homepageType,jdbcType=VARCHAR},
#{user.homepageParameter,jdbcType=VARCHAR}
)
salt = #{user.salt, jdbcType=VARCHAR},
crypted_password = #{user.cryptedPassword, jdbcType=BIGINT},
hash_method = #{user.hashMethod, jdbcType=VARCHAR},
- updated_at = #{now, jdbcType=BIGINT},
+ updated_at = #{user.updatedAt,jdbcType=BIGINT},
homepage_type = #{user.homepageType, jdbcType=VARCHAR},
homepage_parameter = #{user.homepageParameter, jdbcType=VARCHAR}
where
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.UserDto;
-import org.sonar.db.user.UserTesting;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
import static org.sonar.db.property.PropertyTesting.newUserPropertyDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
@RunWith(DataProviderRunner.class)
public class PropertiesDaoTest {
public void shouldFindUsersForNotification() throws SQLException {
ComponentDto project1 = insertPrivateProject("uuid_45");
ComponentDto project2 = insertPrivateProject("uuid_56");
- UserDto user1 = insertUser("user1");
- UserDto user2 = insertUser("user2");
- UserDto user3 = insertUser("user3");
+ UserDto user1 = dbTester.users().insertUser(u -> u.setLogin("user1"));
+ UserDto user2 = dbTester.users().insertUser(u -> u.setLogin("user2"));
+ UserDto user3 = dbTester.users().insertUser(u -> u.setLogin("user3"));
insertProperty("notification.NewViolations.Email", "true", project1.getId(), user2.getId());
insertProperty("notification.NewViolations.Twitter", "true", null, user3.getId());
insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), user1.getId());
@Test
public void hasNotificationSubscribers() throws SQLException {
- int userId1 = insertUser("user1").getId();
- int userId2 = insertUser("user2").getId();
+ int userId1 = dbTester.users().insertUser(u -> u.setLogin("user1")).getId();
+ int userId2 = dbTester.users().insertUser(u -> u.setLogin("user2")).getId();
Long projectId = insertPrivateProject("PROJECT_A").getId();
// global subscription
insertProperty("notification.DispatcherWithGlobalSubscribers.Email", "true", null, userId2);
@Test
public void select_global_properties_by_keys() throws Exception {
insertPrivateProject("A");
- int userId = insertUser("B").getId();
+ int userId = dbTester.users().insertUser(u -> u.setLogin("B")).getId();
String key = "key";
String anotherKey = "anotherKey";
public void select_component_properties_by_ids() {
ComponentDto project = dbTester.components().insertPrivateProject();
ComponentDto project2 = dbTester.components().insertPrivateProject();
-
- UserDto user = UserTesting.newUserDto();
- dbClient.userDao().insert(session, user);
+ UserDto user = dbTester.users().insertUser();
String key = "key";
String anotherKey = "anotherKey";
public void select_properties_by_keys_and_component_ids() {
ComponentDto project = dbTester.components().insertPrivateProject();
ComponentDto project2 = dbTester.components().insertPrivateProject();
-
- UserDto user = UserTesting.newUserDto();
- dbClient.userDao().insert(session, user);
+ UserDto user = dbTester.users().insertUser();
String key = "key";
String anotherKey = "anotherKey";
return project;
}
- private UserDto insertUser(String login) {
- UserDto dto = new UserDto().setLogin(login);
- DbSession session = dbTester.getSession();
- dbClient.userDao().insert(session, dto);
- session.commit();
- return dto;
- }
-
private static PropertyDtoAssert assertThatDto(@Nullable PropertyDto dto) {
return new PropertyDtoAssert(dto);
}
.setLocal(true)
.setOnboarded(false));
- UserDto userUpdate = new UserDto()
+ UserDto userUpdate = newUserDto()
.setId(1)
.setLogin("john")
.setName("John Doo")
@Test
public void does_not_fail_to_deactivate_missing_user() {
- underTest.deactivateUser(session, UserTesting.newUserDto());
+ underTest.deactivateUser(session, newUserDto());
}
@Test
<dataset>
<users id="200"
+ uuid="user1uuid"
login="user1"
name="User1"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="201"
+ uuid="user2uuid"
login="user2"
name="User2"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="202"
+ uuid="user3uuid"
login="user3"
name="User3"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="999"
+ uuid="user999uuid"
login="disabledUser"
name="disabledUser"
active="[false]"
<dataset>
<users id="200"
+ uuid="user1uuid"
login="user1"
name="User1"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="201"
+ uuid="user2uuid"
login="user2"
name="User2"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="202"
+ uuid="user3uuid"
login="user3"
name="User3"
active="[true]"
<dataset>
<users id="200"
+ uuid="user3uuid"
login="user3"
name="User3"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="201"
+ uuid="user1uuid"
login="user1"
name="User1"
active="[true]"
is_root="[false]"
onboarded="[true]"/>
<users id="202"
+ uuid="user2uuid"
login="user2"
name="User2"
active="[true]"
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.server.platform.db.migration.version.v72;
+
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import java.sql.SQLException;
+
+public class AddUUIDtoUsers extends DdlChange {
+
+ private static final String TABLE_NAME = "users";
+ private static final String UUID_COLUMN_NAME = "uuid";
+ private static final int UUID_LENGTH = 40;
+
+ public AddUUIDtoUsers(Database db) {
+ super(db);
+ }
+
+ @Override public void execute(Context context) throws SQLException {
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName(UUID_COLUMN_NAME)
+ .setIsNullable(true)
+ .setLimit(UUID_LENGTH)
+ .build())
+ .build());
+ }
+}
.add(2104, "Create ALM_APP_INSTALLS table", CreateAlmAppInstallsTable.class)
.add(2105, "Add LINE_HASHES_VERSION to table FILE_SOURCES", AddLineHashesVersionToFileSources.class)
.add(2106, "Create PROJECT_MAPPINGS table", CreateProjectMappingsTable.class)
+ .add(2107, "Add UUID on table USERS", AddUUIDtoUsers.class)
+ .add(2108, "Populate USERS.UUID with USERS.LOGIN", PopulateUUIDOnUsers.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.server.platform.db.migration.version.v72;
+
+import java.sql.SQLException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class PopulateUUIDOnUsers extends DataChange {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public PopulateUUIDOnUsers(Database db, System2 system2, UuidFactory uuidFactory) {
+ super(db);
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("select id, login from users where uuid is null");
+ massUpdate.rowPluralName("users");
+ massUpdate.update("update users set uuid=?, updated_at=? where id=?");
+ massUpdate.execute((row, update) -> {
+ String login = row.getString(2);
+ if (login == null) {
+ login = uuidFactory.create();
+ }
+ update.setString(1, login); // login -> uuid
+ update.setLong(2, system2.now());
+ update.setLong(3, row.getLong(1));
+ return true;
+ });
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.server.platform.db.migration.version.v72;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.VARCHAR;
+import static org.junit.rules.ExpectedException.none;
+import static org.sonar.db.CoreDbTester.createForSchema;
+
+public class AddUUIDtoUsersTest {
+
+ @Rule
+ public final CoreDbTester dbTester = createForSchema(AddUUIDtoUsers.class, "users.sql");
+
+ @Rule
+ public ExpectedException expectedException = none();
+
+ private AddUUIDtoUsers underTest = new AddUUIDtoUsers(dbTester.database());
+
+ @Test
+ public void column_is_added_to_table() throws SQLException {
+ underTest.execute();
+
+ dbTester.assertColumnDefinition("users", "uuid", VARCHAR, 40, true);
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 7);
+ verifyMigrationCount(underTest, 9);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.server.platform.db.migration.version.v72;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.stream.Collectors;
+
+import org.assertj.core.groups.Tuple;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.CoreDbTester;
+
+import static java.util.stream.Collectors.toList;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.junit.rules.ExpectedException.none;
+import static org.sonar.db.CoreDbTester.createForSchema;
+
+public class PopulateUUIDOnUsersTest {
+
+ private final static long PAST = 10_000_000_000L;
+ private static final long NOW = 50_000_000_000L;
+ private System2 system2 = new TestSystem2().setNow(NOW);
+
+ private final static String NO_LOGIN = null;
+ private final static String NO_UUID = null;
+
+ @Rule
+ public ExpectedException expectedException = none();
+
+ @Rule
+ public CoreDbTester db = createForSchema(PopulateUUIDOnUsersTest.class, "users.sql");
+
+ private UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
+ private PopulateUUIDOnUsers underTest = new PopulateUUIDOnUsers(db.database(), system2, uuidFactory);
+
+ @Test
+ public void update_uuid_when_login_is_present() throws SQLException {
+
+ String login1 = insertUser(NO_UUID, randomAlphanumeric(10));
+ String login2 = insertUser(NO_UUID, randomAlphanumeric(10));
+ String login3 = insertUser(NO_UUID, randomAlphanumeric(10));
+
+ underTest.execute();
+
+ assertUser(
+ tuple(login1, login1, PAST, NOW),
+ tuple(login2, login2, PAST, NOW),
+ tuple(login3, login3, PAST, NOW)
+ );
+ }
+
+ @Test
+ public void generate_random_uuid_when_login_is_null() throws SQLException {
+ insertUser(NO_UUID, NO_LOGIN);
+ insertUser(NO_UUID, NO_LOGIN);
+ insertUser(NO_UUID, NO_LOGIN);
+
+ underTest.execute();
+
+ assertThat(new ArrayList<>(db.select("SELECT distinct UUID FROM USERS"))).hasSize(3);
+ }
+
+ @Test
+ public void _do_nothing_when_uuid_is_already_present() throws SQLException {
+ String login1 = insertUser(NO_UUID, randomAlphanumeric(10));
+ String login2 = insertUser("existing-uuid", randomAlphanumeric(10));
+
+ underTest.execute();
+
+ assertUser(
+ tuple(login1, login1, PAST, NOW),
+ tuple("existing-uuid", login2, PAST, PAST)
+ );
+ }
+
+ @Test
+ public void is_reentrant() throws SQLException {
+ String login1 = insertUser(NO_UUID, randomAlphanumeric(10));
+ String login2 = insertUser("existing-uuid", randomAlphanumeric(10));
+
+ underTest.execute();
+ underTest.execute();
+
+ assertUser(
+ tuple(login1, login1, PAST, NOW),
+ tuple("existing-uuid", login2, PAST, PAST)
+ );
+ }
+
+ private String insertUser(String uuid, String login) {
+ db.executeInsert("USERS", "UUID", uuid, "LOGIN", login, "IS_ROOT", false, "ONBOARDED", false, "CREATED_AT", PAST, "UPDATED_AT", PAST);
+ return login;
+ }
+
+ private void assertUser(Tuple... expectedTuples) {
+ assertThat(db.select("SELECT LOGIN, UUID, CREATED_AT, UPDATED_AT FROM USERS")
+ .stream()
+ .map(map -> new Tuple(map.get("UUID"), map.get("LOGIN"), map.get("CREATED_AT"), map.get("UPDATED_AT")))
+ .collect(toList()))
+ .containsExactlyInAnyOrder(expectedTuples);
+ }
+}
--- /dev/null
+CREATE TABLE "USERS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOGIN" VARCHAR(255),
+ "NAME" VARCHAR(200),
+ "EMAIL" VARCHAR(100),
+ "CRYPTED_PASSWORD" VARCHAR(100),
+ "SALT" VARCHAR(40),
+ "HASH_METHOD" VARCHAR(10),
+ "ACTIVE" BOOLEAN DEFAULT TRUE,
+ "SCM_ACCOUNTS" VARCHAR(4000),
+ "EXTERNAL_IDENTITY" VARCHAR(255),
+ "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
+ "IS_ROOT" BOOLEAN NOT NULL,
+ "USER_LOCAL" BOOLEAN,
+ "ONBOARDED" BOOLEAN NOT NULL,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT,
+ "HOMEPAGE_TYPE" VARCHAR(40),
+ "HOMEPAGE_PARAMETER" VARCHAR(40)
+);
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN");
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT");
--- /dev/null
+CREATE TABLE "USERS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "UUID" VARCHAR(40),
+ "LOGIN" VARCHAR(255),
+ "NAME" VARCHAR(200),
+ "EMAIL" VARCHAR(100),
+ "CRYPTED_PASSWORD" VARCHAR(100),
+ "SALT" VARCHAR(40),
+ "HASH_METHOD" VARCHAR(10),
+ "ACTIVE" BOOLEAN DEFAULT TRUE,
+ "SCM_ACCOUNTS" VARCHAR(4000),
+ "EXTERNAL_IDENTITY" VARCHAR(255),
+ "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
+ "IS_ROOT" BOOLEAN NOT NULL,
+ "USER_LOCAL" BOOLEAN,
+ "ONBOARDED" BOOLEAN NOT NULL,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT,
+ "HOMEPAGE_TYPE" VARCHAR(40),
+ "HOMEPAGE_PARAMETER" VARCHAR(40)
+);
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN");
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT");
import org.mindrot.jbcrypt.BCrypt;
import org.sonar.db.DbTester;
import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserTesting;
import org.sonar.server.authentication.event.AuthenticationEvent;
import org.sonar.server.authentication.event.AuthenticationException;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.authentication.LocalAuthentication.HashMethod.BCRYPT;
import static org.sonar.server.authentication.LocalAuthentication.HashMethod.SHA1;
@Test
public void incorrect_hash_should_throw_AuthenticationException() {
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setHashMethod("ALGON2");
expectedException.expect(AuthenticationException.class);
@Test
public void null_hash_should_throw_AuthenticationException() {
- UserDto user = new UserDto();
+ UserDto user = newUserDto();
expectedException.expect(AuthenticationException.class);
expectedException.expectMessage("null hash method");
public void authentication_with_bcrypt_with_correct_password_should_work() {
String password = randomAlphanumeric(60);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setHashMethod(BCRYPT.name())
.setCryptedPassword(BCrypt.hashpw(password, BCrypt.gensalt(12)));
RANDOM.nextBytes(saltRandom);
String salt = DigestUtils.sha1Hex(saltRandom);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setHashMethod(SHA1.name())
.setCryptedPassword(DigestUtils.sha1Hex("--" + salt + "--" + password + "--"))
.setSalt(salt);
RANDOM.nextBytes(saltRandom);
String salt = DigestUtils.sha1Hex(saltRandom);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setHashMethod(SHA1.name())
.setCryptedPassword(DigestUtils.sha1Hex("--" + salt + "--" + password + "--"))
.setSalt(salt);
RANDOM.nextBytes(saltRandom);
String salt = DigestUtils.sha1Hex(saltRandom);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setHashMethod(SHA1.name())
+ .setCryptedPassword(null)
.setSalt(salt);
expectedException.expect(AuthenticationException.class);
public void authentication_with_sha1_with_empty_salt_should_throw_AuthenticationException() {
String password = randomAlphanumeric(60);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
+ .setSalt(null)
.setHashMethod(SHA1.name())
.setCryptedPassword(DigestUtils.sha1Hex("--0242b0b4c0a93ddfe09dd886de50bc25ba000b51--" + password + "--"));
public void authentication_with_bcrypt_with_incorrect_password_should_throw_AuthenticationException() {
String password = randomAlphanumeric(60);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setHashMethod(BCRYPT.name())
.setCryptedPassword(BCrypt.hashpw(password, BCrypt.gensalt(12)));
RANDOM.nextBytes(saltRandom);
String salt = DigestUtils.sha1Hex(saltRandom);
- UserDto user = new UserDto()
+ UserDto user = newUserDto()
.setLogin("myself")
.setHashMethod(SHA1.name())
.setCryptedPassword(DigestUtils.sha1Hex("--" + salt + "--" + password + "--"))
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserTesting;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.es.StartupIndexer;
import static org.assertj.core.groups.Tuple.tuple;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT;
@Test
public void response_contains_all_fields_except_additional_fields() {
- dbClient.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com"));
- dbClient.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+ db.users().insertUser(u -> u.setLogin("simon").setName("Simon").setEmail("simon@email.com"));
+ db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization2, "PROJECT_ID").setDbKey("PROJECT_KEY"));
indexPermissions();
@Test
public void issue_with_comments() {
- dbClient.userDao().insert(session, new UserDto().setLogin("john").setName("John"));
- dbClient.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+ db.users().insertUser(u -> u.setLogin("john").setName("John"));
+ db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization2, "PROJECT_ID").setDbKey("PROJECT_KEY"));
indexPermissions();
@Test
public void issue_with_comment_hidden() {
- dbClient.userDao().insert(session, new UserDto().setLogin("john").setName("John").setEmail("john@email.com"));
- dbClient.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+ db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com"));
+ db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization1, "PROJECT_ID").setDbKey("PROJECT_KEY"));
indexPermissions();
@Test
public void load_additional_fields() {
- dbClient.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com"));
- dbClient.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+ db.users().insertUser(u -> u.setLogin("simon").setName("Simon").setEmail("simon@email.com"));
+ db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization2, "PROJECT_ID").setDbKey("PROJECT_KEY").setLanguage("java"));
indexPermissions();
ComponentDto file = insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY").setLanguage("js"));
@Test
public void load_additional_fields_with_issue_admin_permission() {
- dbClient.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com"));
- dbClient.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+ db.users().insertUser(u -> u.setLogin("simon").setName("Simon").setEmail("simon@email.com"));
+ db.users().insertUser(u -> u.setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization1, "PROJECT_ID").setDbKey("PROJECT_KEY").setLanguage("java"));
grantPermissionToAnyone(project, ISSUE_ADMIN);
indexPermissions();
@Test
public void filter_by_assigned_to_me() {
- dbClient.userDao().insert(session, new UserDto().setLogin("john").setName("John").setEmail("john@email.com"));
+ dbClient.userDao().insert(session, newUserDto().setLogin("john").setName("John").setEmail("john@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(defaultOrganization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
indexPermissions();
@Test
public void assigned_to_me_facet_is_sticky_relative_to_assignees() {
- dbClient.userDao().insert(session, new UserDto().setLogin("alice").setName("Alice").setEmail("alice@email.com"));
+ dbClient.userDao().insert(session, newUserDto().setLogin("alice").setName("Alice").setEmail("alice@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization2, "PROJECT_ID").setDbKey("PROJECT_KEY"));
indexPermissions();
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserTesting;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.BadRequestException;
import static org.sonar.api.measures.Metric.ValueType.LEVEL;
import static org.sonar.api.measures.Metric.ValueType.STRING;
import static org.sonar.api.measures.Metric.ValueType.WORK_DUR;
+import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations;
public class CreateActionTest {
ws = new WsTester(new CustomMeasuresWs(new CreateAction(dbClient, userSession, System2.INSTANCE, new CustomMeasureValidator(newFullTypeValidations()),
new CustomMeasureJsonWriter(new UserJsonWriter(userSession)), TestComponentFinder.from(db))));
- db.getDbClient().userDao().insert(dbSession, new UserDto()
+ db.getDbClient().userDao().insert(dbSession, newUserDto()
.setLogin("login")
.setName("Login")
.setEmail("login@login.com")
import org.sonar.db.measure.custom.CustomMeasureDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserTesting;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.measure.custom.CustomMeasureTesting.newCustomMeasureDto;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
public class SearchActionTest {
defaultProject = insertDefaultProject();
userSessionRule.logIn().addProjectPermission(UserRole.ADMIN, defaultProject);
- db.getDbClient().userDao().insert(dbSession, new UserDto()
+ db.getDbClient().userDao().insert(dbSession, newUserDto()
.setLogin("login")
.setName("Login")
.setEmail("login@login.com")
import org.sonar.db.metric.MetricTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserTesting;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.ServerException;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.db.measure.custom.CustomMeasureTesting.newCustomMeasureDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.measure.custom.ws.UpdateAction.PARAM_DESCRIPTION;
import static org.sonar.server.measure.custom.ws.UpdateAction.PARAM_ID;
import static org.sonar.server.measure.custom.ws.UpdateAction.PARAM_VALUE;
ws = new WsTester(new CustomMeasuresWs(new UpdateAction(dbClient, userSessionRule, system, validator, new CustomMeasureJsonWriter(new UserJsonWriter(userSessionRule)))));
- db.getDbClient().userDao().insert(dbSession, new UserDto()
+ db.getDbClient().userDao().insert(dbSession, newUserDto()
.setLogin("login")
.setName("Login")
.setEmail("login@login.com")
*/
package org.sonar.server.user;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.database.model.User;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
-
+import static org.sonar.db.DbTester.create;
public class DeprecatedUserFinderTest {
@Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
+ public DbTester dbTester = create(System2.INSTANCE);
private DeprecatedUserFinder underTest = new DeprecatedUserFinder(dbTester.getDbClient());
-
- @Before
- public void init() {
- dbTester.prepareDbUnit(DeprecatedUserFinderTest.class, "fixture.xml");
- }
@Test
public void shouldFindUserByLogin() {
-
- User user = underTest.findByLogin("simon");
- assertThat(user.getId(), is(1));
+
+ UserDto simon = dbTester.users().insertUser(u -> u.setLogin("simon").setName("Simon Brandhof").setEmail("simon.brandhof@sonarsource.com"));
+ UserDto evgeny = dbTester.users().insertUser(u -> u.setLogin("godin").setName("Evgeny Mandrikov").setEmail("evgeny.mandrikov@sonarsource.com"));
+
+ User user = underTest.findByLogin(simon.getLogin());
+ assertThat(user.getId(), is(simon.getId()));
assertThat(user.getLogin(), is("simon"));
assertThat(user.getName(), is("Simon Brandhof"));
assertThat(user.getEmail(), is("simon.brandhof@sonarsource.com"));
- user = underTest.findByLogin("godin");
- assertThat(user.getId(), is(2));
+ user = underTest.findByLogin(evgeny.getLogin());
+ assertThat(user.getId(), is(evgeny.getId()));
assertThat(user.getLogin(), is("godin"));
assertThat(user.getName(), is("Evgeny Mandrikov"));
assertThat(user.getEmail(), is("evgeny.mandrikov@sonarsource.com"));
@Test
public void shouldFindUserById() {
- User user = underTest.findById(1);
- assertThat(user.getId(), is(1));
+ UserDto simon = dbTester.users().insertUser(u -> u.setLogin("simon").setName("Simon Brandhof").setEmail("simon.brandhof@sonarsource.com"));
+ UserDto evgeny = dbTester.users().insertUser(u -> u.setLogin("godin").setName("Evgeny Mandrikov").setEmail("evgeny.mandrikov@sonarsource.com"));
+
+ User user = underTest.findById(simon.getId());
+ assertThat(user.getId(), is(simon.getId()));
assertThat(user.getLogin(), is("simon"));
assertThat(user.getName(), is("Simon Brandhof"));
assertThat(user.getEmail(), is("simon.brandhof@sonarsource.com"));
- user = underTest.findById(2);
- assertThat(user.getId(), is(2));
+ user = underTest.findById(evgeny.getId());
+ assertThat(user.getId(), is(evgeny.getId()));
assertThat(user.getLogin(), is("godin"));
assertThat(user.getName(), is("Evgeny Mandrikov"));
assertThat(user.getEmail(), is("evgeny.mandrikov@sonarsource.com"));
- user = underTest.findById(3);
+ user = underTest.findById(999);
assertThat(user, nullValue());
}
public void only_return_login_and_name_when_not_logged() throws Exception {
userSession.anonymous();
- dbClient.userDao().insert(dbSession, UserTesting.newUserDto("john", "John", "john@email.com"));
+ dbClient.userDao().insert(dbSession, newUserDto("john", "John", "john@email.com"));
dbSession.commit();
userIndexer.indexOnStartup(null);
String name = String.format("User %d", index);
List<String> scmAccounts = singletonList(String.format("user-%d", index));
- UserDto userDto = dbClient.userDao().insert(dbSession, new UserDto()
+ UserDto userDto = dbClient.userDao().insert(dbSession, newUserDto()
.setActive(true)
.setEmail(email)
.setLogin(login)
+++ /dev/null
-<dataset>
-
- <users id="1"
- login="simon"
- name="Simon Brandhof"
- email="simon.brandhof@sonarsource.com"
- is_root="[false]"
- onboarded="[true]"/>
- <users id="2"
- login="godin"
- name="Evgeny Mandrikov"
- email="evgeny.mandrikov@sonarsource.com"
- is_root="[false]"
- onboarded="[true]"/>
-
-</dataset>