]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8980 Index organizations when indexing a user
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 21 Mar 2017 17:02:22 +0000 (18:02 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 24 Mar 2017 16:38:53 +0000 (17:38 +0100)
18 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMemberDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMemberMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMemberMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationMemberDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/organization/ws/RemoveMemberAction.java
server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchMembersAction.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserDoc.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndex.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexDefinition.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserQuery.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserResultSetIterator.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchMembersActionTest.java
server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexDefinitionTest.java
server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexTest.java
server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/user/index/UserResultSetIteratorTest.java
server/sonar-server/src/test/resources/org/sonar/server/user/index/UserResultSetIteratorTest/shared.xml [deleted file]

index 6a10a129ab42b675d5a55f796b8e51b538848633..e19d186c323bc454e3d3346ff0ba278c701fe55f 100644 (file)
@@ -23,9 +23,12 @@ package org.sonar.db.organization;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.BiConsumer;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
 
+import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput;
+
 public class OrganizationMemberDao implements Dao {
   private static OrganizationMemberMapper mapper(DbSession dbSession) {
     return dbSession.getMapper(OrganizationMemberMapper.class);
@@ -55,4 +58,21 @@ public class OrganizationMemberDao implements Dao {
     return mapper(dbSession).selectOrganizationUuidsByUser(userId);
   }
 
+  /**
+   *
+   * @param loginOrganizationConsumer {@link BiConsumer}<String,String> (login, organization uuid)
+   */
+  public void selectForUserIndexing(DbSession dbSession, List<String> logins, BiConsumer<String, String> loginOrganizationConsumer) {
+    executeLargeInputsWithoutOutput(logins, list -> mapper(dbSession).selectForIndexing(list)
+      .forEach(row -> loginOrganizationConsumer.accept(row.get("login"), row.get("organizationUuid"))));
+  }
+
+  /**
+   *
+   * @param loginOrganizationConsumer {@link BiConsumer}<String,String> (login, organization uuid)
+   */
+  public void selectAllForUserIndexing(DbSession dbSession, BiConsumer<String, String> loginOrganizationConsumer) {
+    mapper(dbSession).selectAllForIndexing()
+      .forEach(row -> loginOrganizationConsumer.accept(row.get("login"), row.get("organizationUuid")));
+  }
 }
index 80237b276d16dc62c7c96a56e4a306e07d4d1deb..5491715a43a909ad5b51c9970bb5ec837ed5dbf4 100644 (file)
@@ -21,6 +21,7 @@
 package org.sonar.db.organization;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import org.apache.ibatis.annotations.Param;
 
@@ -31,6 +32,10 @@ public interface OrganizationMemberMapper {
 
   List<String> selectLogins(String organizationUuid);
 
+  List<Map<String, String>> selectForIndexing(@Param("logins") List<String> logins);
+
+  List<Map<String, String>> selectAllForIndexing();
+
   void insert(OrganizationMemberDto organizationMember);
 
   void delete(@Param("organizationUuid") String organizationUuid, @Param("userId") Integer userId);
index 2a63ade892fa361e3080f58e718f470d5233b9b8..951929079ea225035fd6afe9f3d4dd0eec8c5cba 100644 (file)
     where om.user_id = #{userId, jdbcType=INTEGER}
   </select>
 
+  <select id="selectForIndexing" resultType="hashmap">
+    select u.login as "login", om.organization_uuid as "organizationUuid"
+    from organization_members om
+     inner join users u on om.user_id=u.id
+    where u.login in
+    <foreach collection="logins" open="(" close=")" item="login" separator=",">
+      #{login, jdbcType=VARCHAR}
+    </foreach>
+  </select>
+
+  <select id="selectAllForIndexing" resultType="hashmap">
+    select u.login as "login", om.organization_uuid as "organizationUuid"
+    from organization_members om
+    inner join users u on om.user_id=u.id
+  </select>
+
   <insert id="insert" parameterType="OrganizationMember" useGeneratedKeys="false">
     insert into organization_members
     (
index a586f1be28b80912ebbc0380afef977f7eb57181..1bd9fc6afcb4777a00e341b72305bf992754659d 100644 (file)
 
 package org.sonar.db.organization;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.ibatis.exceptions.PersistenceException;
+import org.assertj.core.groups.Tuple;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -34,6 +37,7 @@ import org.sonar.db.user.UserDto;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
+import static org.assertj.core.api.Assertions.tuple;
 
 public class OrganizationMemberDaoTest {
   @Rule
@@ -87,6 +91,38 @@ public class OrganizationMemberDaoTest {
     assertThat(underTest.selectOrganizationUuidsByUser(dbSession, 123)).isEmpty();
   }
 
+  @Test
+  public void select_for_indexing() {
+    OrganizationDto org1 = db.organizations().insert(o -> o.setUuid("ORG_1"));
+    OrganizationDto org2 = db.organizations().insert(o -> o.setUuid("ORG_2"));
+    UserDto user1 = db.users().insertUser("L_1");
+    UserDto user2 = db.users().insertUser("L_2");
+    db.organizations().addMember(org1, user1);
+    db.organizations().addMember(org1, user2);
+    db.organizations().addMember(org2, user1);
+    List<Tuple> result = new ArrayList<>();
+
+    underTest.selectForUserIndexing(dbSession, Arrays.asList("L_1", "L_2"), (login, org) -> result.add(tuple(login, org)));
+
+    assertThat(result).containsOnly(tuple("L_1", "ORG_1"), tuple("L_1", "ORG_2"), tuple("L_2", "ORG_1"));
+  }
+
+  @Test
+  public void select_all_for_indexing() {
+    OrganizationDto org1 = db.organizations().insert(o -> o.setUuid("ORG_1"));
+    OrganizationDto org2 = db.organizations().insert(o -> o.setUuid("ORG_2"));
+    UserDto user1 = db.users().insertUser("L_1");
+    UserDto user2 = db.users().insertUser("L_2");
+    db.organizations().addMember(org1, user1);
+    db.organizations().addMember(org1, user2);
+    db.organizations().addMember(org2, user1);
+    List<Tuple> result = new ArrayList<>();
+
+    underTest.selectAllForUserIndexing(dbSession, (login, org) -> result.add(tuple(login, org)));
+
+    assertThat(result).containsOnly(tuple("L_1", "ORG_1"), tuple("L_1", "ORG_2"), tuple("L_2", "ORG_1"));
+  }
+
   @Test
   public void insert() {
     underTest.insert(dbSession, create("O_1", 256));
index 1c31b25fd6066b25191c6e1409516ab6e9090155..1fcc099a4db6a191b39a060ebd6f84370fab5091 100644 (file)
@@ -108,5 +108,4 @@ public class RemoveMemberAction implements OrganizationsWsAction {
       organizationDto.getUuid(), ADMINISTER.getKey(), user.getId());
     checkRequest(remainingAdmins > 0, "The last administrator member cannot be removed");
   }
-
 }
index 77208d0f7a28c1cab8735d8cd57b49bcca05da51..1dffd2a3e119c698a3c7582f068fccb086521256 100644 (file)
@@ -98,9 +98,8 @@ public class SearchMembersAction implements OrganizationsWsAction {
   public void handle(Request request, Response response) throws Exception {
     try (DbSession dbSession = dbClient.openSession(false)) {
       OrganizationDto organization = getOrganization(dbSession, request.param("organization"));
-      List<String> memberLogins = dbClient.organizationMemberDao().selectLoginsByOrganizationUuid(dbSession, organization.getUuid());
 
-      UserQuery.Builder userQuery = buildUserQuery(request, memberLogins);
+      UserQuery.Builder userQuery = buildUserQuery(request, organization);
       SearchOptions searchOptions = buildSearchOptions(request);
 
       SearchResult<UserDoc> searchResults = userIndex.search(userQuery.build(), searchOptions);
@@ -143,7 +142,7 @@ public class SearchMembersAction implements OrganizationsWsAction {
     return response.build();
   }
 
-  private static UserQuery.Builder buildUserQuery(Request request, List<String> memberLogins) {
+  private static UserQuery.Builder buildUserQuery(Request request, OrganizationDto organization) {
     UserQuery.Builder userQuery = UserQuery.builder();
     String textQuery = request.param(Param.TEXT_QUERY);
     checkArgument(textQuery == null || textQuery.length() >= 2, "Query length must be greater than or equal to 2");
@@ -151,9 +150,9 @@ public class SearchMembersAction implements OrganizationsWsAction {
 
     SelectionMode selectionMode = SelectionMode.fromParam(request.mandatoryParam(Param.SELECTED));
     if (SelectionMode.DESELECTED.equals(selectionMode)) {
-      userQuery.setExcludedLogins(memberLogins);
+      userQuery.setExcludedOrganizationUuid(organization.getUuid());
     } else {
-      userQuery.setLogins(memberLogins);
+      userQuery.setOrganizationUuid(organization.getUuid());
     }
     return userQuery;
   }
index c1ad19d6322855f61520b10b423b5611f773f841..1b7591d0f55d203731b9f95560b86b7c3d688d95 100644 (file)
@@ -27,6 +27,8 @@ import javax.annotation.Nullable;
 import org.sonar.api.user.User;
 import org.sonar.server.es.BaseDoc;
 
+import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ORGANIZATION_UUIDS;
+
 public class UserDoc extends BaseDoc implements User {
 
   public UserDoc(Map<String, Object> fields) {
@@ -77,6 +79,10 @@ public class UserDoc extends BaseDoc implements User {
     return getField(UserIndexDefinition.FIELD_SCM_ACCOUNTS);
   }
 
+  public List<String> organizationUuids() {
+    return getField(FIELD_ORGANIZATION_UUIDS);
+  }
+
   public long createdAt() {
     return getFieldAsDate(UserIndexDefinition.FIELD_CREATED_AT).getTime();
   }
@@ -110,6 +116,11 @@ public class UserDoc extends BaseDoc implements User {
     return this;
   }
 
+  public UserDoc setOrganizationUuids(@Nullable List<String> organizationUuids) {
+    setField(FIELD_ORGANIZATION_UUIDS, organizationUuids);
+    return this;
+  }
+
   public UserDoc setCreatedAt(long l) {
     setField(UserIndexDefinition.FIELD_CREATED_AT, new Date(l));
     return this;
index a3a17feb13d738cf02099811ffa3c01ff014ccae..6961dfffabf4766ed8635fed6d7c0b0896e42c3b 100644 (file)
@@ -57,6 +57,7 @@ import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ACTIVE;
 import static org.sonar.server.user.index.UserIndexDefinition.FIELD_EMAIL;
 import static org.sonar.server.user.index.UserIndexDefinition.FIELD_LOGIN;
 import static org.sonar.server.user.index.UserIndexDefinition.FIELD_NAME;
+import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ORGANIZATION_UUIDS;
 import static org.sonar.server.user.index.UserIndexDefinition.FIELD_SCM_ACCOUNTS;
 
 @ServerSide
@@ -140,12 +141,10 @@ public class UserIndex {
       .addSort(FIELD_NAME, SortOrder.ASC);
 
     BoolQueryBuilder filter = boolQuery().must(termQuery(FIELD_ACTIVE, true));
-
-    userQuery.getLogins().ifPresent(
-      logins -> filter.must(termsQuery(FIELD_LOGIN, userQuery.getLogins().get())));
-
-    userQuery.getExcludedLogins().ifPresent(
-      excludedLogins -> filter.mustNot(termsQuery(FIELD_LOGIN, userQuery.getExcludedLogins().get())));
+    userQuery.getOrganizationUuid()
+      .ifPresent(o -> filter.must(termQuery(FIELD_ORGANIZATION_UUIDS, o)));
+    userQuery.getExcludedOrganizationUuid()
+      .ifPresent(o -> filter.mustNot(termQuery(FIELD_ORGANIZATION_UUIDS, o)));
 
     QueryBuilder esQuery = matchAllQuery();
     Optional<String> textQuery = userQuery.getTextQuery();
index 68777d84338e97566ad68dece37ed6d4181ac408..ace94fdfac948edd509d83f2681ae8c320237257 100644 (file)
@@ -40,6 +40,7 @@ public class UserIndexDefinition implements IndexDefinition {
   public static final String FIELD_UPDATED_AT = "updatedAt";
   public static final String FIELD_ACTIVE = "active";
   public static final String FIELD_SCM_ACCOUNTS = "scmAccounts";
+  public static final String FIELD_ORGANIZATION_UUIDS = "organizationUuids";
 
   private final Settings settings;
 
@@ -62,5 +63,6 @@ public class UserIndexDefinition implements IndexDefinition {
     mapping.createDateTimeField(FIELD_UPDATED_AT);
     mapping.createBooleanField(FIELD_ACTIVE);
     mapping.stringFieldBuilder(FIELD_SCM_ACCOUNTS).disableNorms().build();
+    mapping.stringFieldBuilder(FIELD_ORGANIZATION_UUIDS).disableNorms().build();
   }
 }
index edac71f8fdcd7a89af154c4a61410df71315e163..34c906db284cffda33e1e46ecaa5ffb1b27c5e59 100644 (file)
@@ -52,12 +52,12 @@ public class UserIndexer implements StartupIndexer {
 
   @Override
   public void indexOnStartup(Set<IndexType> emptyIndexTypes) {
-    doIndex(null, Size.REGULAR);
+    doIndex(null, Size.LARGE);
   }
 
   public void index(String login) {
     requireNonNull(login);
-    doIndex(login, Size.LARGE);
+    doIndex(login, Size.REGULAR);
   }
 
   private void doIndex(@Nullable String login, Size bulkSize) {
index 9ff05e694cefaa4280aa2e56146adf042d708370..5b5ebda4dc9bb9f29e9cb0dd34d949330d6d5798 100644 (file)
@@ -20,8 +20,6 @@
 
 package org.sonar.server.user.index;
 
-import com.google.common.collect.ImmutableList;
-import java.util.List;
 import java.util.Optional;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
@@ -31,25 +29,25 @@ import static org.apache.commons.lang.StringUtils.isBlank;
 @Immutable
 public class UserQuery {
   private final String textQuery;
-  private final List<String> logins;
-  private final List<String> excludedLogins;
+  private final String organizationUuid;
+  private final String excludedOrganizationUuid;
 
   private UserQuery(Builder builder) {
     this.textQuery = builder.textQuery;
-    this.logins = builder.logins == null ? null : ImmutableList.copyOf(builder.logins);
-    this.excludedLogins = builder.excludedLogins == null ? null : ImmutableList.copyOf(builder.excludedLogins);
+    this.organizationUuid = builder.organizationUuid;
+    this.excludedOrganizationUuid = builder.excludedOrganizationUuid;
   }
 
   public Optional<String> getTextQuery() {
     return Optional.ofNullable(textQuery);
   }
 
-  public Optional<List<String>> getLogins() {
-    return Optional.ofNullable(logins);
+  public Optional<String> getOrganizationUuid() {
+    return Optional.ofNullable(organizationUuid);
   }
 
-  public Optional<List<String>> getExcludedLogins() {
-    return Optional.ofNullable(excludedLogins);
+  public Optional<String> getExcludedOrganizationUuid() {
+    return Optional.ofNullable(excludedOrganizationUuid);
   }
 
   public static Builder builder() {
@@ -58,8 +56,8 @@ public class UserQuery {
 
   public static class Builder {
     private String textQuery;
-    private List<String> logins;
-    private List<String> excludedLogins;
+    private String organizationUuid;
+    private String excludedOrganizationUuid;
 
     private Builder() {
       // enforce factory method
@@ -74,13 +72,19 @@ public class UserQuery {
       return this;
     }
 
-    public Builder setLogins(@Nullable List<String> logins) {
-      this.logins = logins;
+    /**
+     * Include only users that are members of the organizationUuid
+     */
+    public Builder setOrganizationUuid(@Nullable String organizationUuid) {
+      this.organizationUuid = organizationUuid;
       return this;
     }
 
-    public Builder setExcludedLogins(@Nullable List<String> excludedLogins) {
-      this.excludedLogins = excludedLogins;
+    /**
+     * Include only users that are not members of the excludedOrganizationUuid
+     */
+    public Builder setExcludedOrganizationUuid(@Nullable String excludedOrganizationUuid) {
+      this.excludedOrganizationUuid = excludedOrganizationUuid;
       return this;
     }
   }
index 48a0177b86783c3972840166026c1bd3af2e57af..f2876942d74cf7446b6c19b1416660eb221f8065 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.user.index;
 
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Maps;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -30,6 +32,8 @@ import org.sonar.db.DbSession;
 import org.sonar.db.ResultSetIterator;
 import org.sonar.db.user.UserDto;
 
+import static java.util.Collections.singletonList;
+
 /**
  * Scrolls over table USERS and reads documents to populate the user index
  */
@@ -47,11 +51,13 @@ class UserResultSetIterator extends ResultSetIterator<UserDoc> {
   };
 
   private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from users u ";
-
   private static final String LOGIN_FILTER = " WHERE u.login=?";
 
-  private UserResultSetIterator(PreparedStatement stmt) throws SQLException {
+  private final ListMultimap<String, String> organizationUuidsByLogins;
+
+  private UserResultSetIterator(PreparedStatement stmt, ListMultimap<String, String> organizationUuidsByLogins) throws SQLException {
     super(stmt);
+    this.organizationUuidsByLogins = organizationUuidsByLogins;
   }
 
   static UserResultSetIterator create(DbClient dbClient, DbSession session, @Nullable String login) {
@@ -59,7 +65,15 @@ class UserResultSetIterator extends ResultSetIterator<UserDoc> {
       String sql = createSql(login);
       PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql);
       setParameter(stmt, login);
-      return new UserResultSetIterator(stmt);
+
+      ListMultimap<String, String> organizationUuidsByLogin = ArrayListMultimap.create();
+      if (login == null) {
+        dbClient.organizationMemberDao().selectAllForUserIndexing(session, organizationUuidsByLogin::put);
+      } else {
+        dbClient.organizationMemberDao().selectForUserIndexing(session, singletonList(login), organizationUuidsByLogin::put);
+      }
+
+      return new UserResultSetIterator(stmt, organizationUuidsByLogin);
     } catch (SQLException e) {
       throw new IllegalStateException("Fail to prepare SQL request to select all users", e);
     }
@@ -79,7 +93,7 @@ class UserResultSetIterator extends ResultSetIterator<UserDoc> {
 
   @Override
   protected UserDoc read(ResultSet rs) throws SQLException {
-    UserDoc doc = new UserDoc(Maps.<String, Object>newHashMapWithExpectedSize(7));
+    UserDoc doc = new UserDoc(Maps.newHashMapWithExpectedSize(8));
 
     String login = rs.getString(1);
 
@@ -91,6 +105,7 @@ class UserResultSetIterator extends ResultSetIterator<UserDoc> {
     doc.setScmAccounts(UserDto.decodeScmAccounts(rs.getString(5)));
     doc.setCreatedAt(rs.getLong(6));
     doc.setUpdatedAt(rs.getLong(7));
+    doc.setOrganizationUuids(organizationUuidsByLogins.get(login));
     return doc;
   }
 
index 1e61a2718a880ceb760574f37b075f38f7c811a4..1c99f943686926485d40ba425161648c3586a089 100644 (file)
@@ -90,12 +90,13 @@ public class SearchMembersActionTest {
   public void search_members_of_default_organization() {
     OrganizationDto defaultOrganization = db.getDefaultOrganization();
     OrganizationDto anotherOrganization = db.organizations().insert();
-    UserDto user = insertUser();
-    UserDto anotherUser = insertUser();
-    UserDto userInAnotherOrganization = insertUser();
+    UserDto user = db.users().insertUser();
+    UserDto anotherUser = db.users().insertUser();
+    UserDto userInAnotherOrganization = db.users().insertUser();
     db.organizations().addMember(defaultOrganization, user);
     db.organizations().addMember(defaultOrganization, anotherUser);
     db.organizations().addMember(anotherOrganization, userInAnotherOrganization);
+    indexAllUsers();
 
     SearchMembersWsResponse result = call();
 
@@ -110,12 +111,13 @@ public class SearchMembersActionTest {
   public void search_members_of_specified_organization() {
     OrganizationDto organization = db.organizations().insert();
     OrganizationDto anotherOrganization = db.organizations().insert();
-    UserDto user = insertUser();
-    UserDto anotherUser = insertUser();
-    UserDto userInAnotherOrganization = insertUser();
+    UserDto user = db.users().insertUser();
+    UserDto anotherUser = db.users().insertUser();
+    UserDto userInAnotherOrganization = db.users().insertUser();
     db.organizations().addMember(organization, user);
     db.organizations().addMember(organization, anotherUser);
     db.organizations().addMember(anotherOrganization, userInAnotherOrganization);
+    indexAllUsers();
     request.setOrganization(organization.getKey());
 
     SearchMembersWsResponse result = call();
@@ -130,8 +132,8 @@ public class SearchMembersActionTest {
   @Test
   public void return_avatar() {
     UserDto user = db.users().insertUser(u -> u.setEmail("email@domain.com"));
-    indexer.index(user.getLogin());
     db.organizations().addMember(db.getDefaultOrganization(), user);
+    indexer.index(user.getLogin());
 
     SearchMembersWsResponse result = call();
 
@@ -140,10 +142,11 @@ public class SearchMembersActionTest {
 
   @Test
   public void do_not_return_group_count_if_no_admin_permission() {
-    UserDto user = insertUser();
+    UserDto user = db.users().insertUser();
     GroupDto group = db.users().insertGroup();
     db.users().insertMember(group, user);
     db.organizations().addMember(db.getDefaultOrganization(), user);
+    indexAllUsers();
 
     SearchMembersWsResponse result = call();
 
@@ -153,8 +156,8 @@ public class SearchMembersActionTest {
   @Test
   public void return_group_counts_if_org_admin() {
     userSession.addPermission(OrganizationPermission.ADMINISTER, db.getDefaultOrganization());
-    UserDto user = insertUser();
-    UserDto anotherUser = insertUser();
+    UserDto user = db.users().insertUser();
+    UserDto anotherUser = db.users().insertUser();
     IntStream.range(0, 10)
       .mapToObj(i -> db.users().insertGroup())
       .forEach(g -> db.users().insertMembers(g, user));
@@ -164,6 +167,7 @@ public class SearchMembersActionTest {
     db.organizations().addMember(db.getDefaultOrganization(), user);
     db.organizations().addMember(db.getDefaultOrganization(), anotherUser);
     db.organizations().addMember(anotherOrganization, user);
+    indexAllUsers();
 
     SearchMembersWsResponse result = call();
 
@@ -176,12 +180,13 @@ public class SearchMembersActionTest {
   public void search_non_members() {
     OrganizationDto defaultOrganization = db.getDefaultOrganization();
     OrganizationDto anotherOrganization = db.organizations().insert();
-    UserDto user = insertUser();
-    UserDto anotherUser = insertUser();
-    UserDto userInAnotherOrganization = insertUser();
+    UserDto user = db.users().insertUser();
+    UserDto anotherUser = db.users().insertUser();
+    UserDto userInAnotherOrganization = db.users().insertUser();
     db.organizations().addMember(anotherOrganization, user);
     db.organizations().addMember(anotherOrganization, anotherUser);
     db.organizations().addMember(defaultOrganization, userInAnotherOrganization);
+    indexAllUsers();
     request.setSelected(WebService.SelectionMode.DESELECTED.value());
 
     SearchMembersWsResponse result = call();
@@ -200,6 +205,7 @@ public class SearchMembersActionTest {
       db.organizations().addMember(db.getDefaultOrganization(), userDto);
       indexer.index(userDto.getLogin());
     });
+    indexAllUsers();
     request.setPage(2).setPageSize(3);
 
     SearchMembersWsResponse result = call();
@@ -218,6 +224,7 @@ public class SearchMembersActionTest {
       db.organizations().addMember(db.getDefaultOrganization(), userDto);
       indexer.index(userDto.getLogin());
     });
+    indexAllUsers();
     request.setQuery("_9");
 
     SearchMembersWsResponse result = call();
@@ -232,6 +239,7 @@ public class SearchMembersActionTest {
       db.organizations().addMember(db.getDefaultOrganization(), userDto);
       indexer.index(userDto.getLogin());
     });
+    indexAllUsers();
     request.setQuery("_9");
 
     SearchMembersWsResponse result = call();
@@ -248,6 +256,7 @@ public class SearchMembersActionTest {
       db.organizations().addMember(db.getDefaultOrganization(), userDto);
       indexer.index(userDto.getLogin());
     });
+    indexAllUsers();
     request.setQuery("_9");
 
     SearchMembersWsResponse result = call();
@@ -263,6 +272,7 @@ public class SearchMembersActionTest {
     indexer.index(grace.getLogin());
     db.organizations().addMember(db.getDefaultOrganization(), ada);
     db.organizations().addMember(db.getDefaultOrganization(), grace);
+    indexAllUsers();
 
     String result = ws.newRequest().execute().getInput();
 
@@ -318,11 +328,8 @@ public class SearchMembersActionTest {
     assertThat(selected.defaultValue()).isEqualTo("selected");
   }
 
-  private UserDto insertUser() {
-    UserDto userDto = db.users().insertUser();
-    indexer.index(userDto.getLogin());
-
-    return userDto;
+  private void indexAllUsers() {
+    indexer.indexOnStartup(indexer.getIndexTypes());
   }
 
   private SearchMembersWsResponse call() {
index 0687a43c4e6ef257b1c604b9ccf84f6ce6a358e6..f6e7776b053e9ceaf481d1e673cb2a6ecf74a646 100644 (file)
@@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 public class UserIndexDefinitionTest {
 
-  IndexDefinition.IndexDefinitionContext underTest = new IndexDefinition.IndexDefinitionContext();
+  private IndexDefinition.IndexDefinitionContext underTest = new IndexDefinition.IndexDefinitionContext();
 
   @Test
   public void define() {
index b3a257f6cacce63a9a2fa2292a294fe8234176e6..1159085b85108fd1fc6abe5d741864eaceb810a3 100644 (file)
@@ -28,11 +28,10 @@ import org.junit.Test;
 import org.sonar.api.config.MapSettings;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.es.SearchOptions;
-import org.sonar.server.es.SearchResult;
 
+import static com.google.common.collect.Lists.newArrayList;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.server.user.index.UserIndexDefinition.INDEX_TYPE_USER;
 
@@ -144,36 +143,27 @@ public class UserIndexTest {
   }
 
   @Test
-  public void search_users_filter_logins() throws Exception {
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER1_LOGIN, asList("user_1", "u1")).setEmail("email1"));
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER2_LOGIN, emptyList()).setEmail("email2"));
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser("user3", emptyList()).setEmail("email2"));
-
-    SearchResult<UserDoc> result = underTest.search(userQuery.setLogins(asList(USER1_LOGIN, USER2_LOGIN)).build(), new SearchOptions());
-    assertThat(result.getDocs()).hasSize(2)
-      .extracting(UserDoc::login)
-      .containsOnly(USER1_LOGIN, USER2_LOGIN);
-  }
-
-  @Test
-  public void search_users_filter_logins_that_match_exactly() {
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser("USER_1", asList("user_1", "u1")).setEmail("email1"));
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser("UsEr_1", emptyList()).setEmail("email2"));
-
-    assertThat(underTest.search(userQuery.setLogins(singletonList("USER_1")).build(), new SearchOptions()).getDocs()).hasSize(1);
-    assertThat(underTest.search(userQuery.setLogins(singletonList("USER_")).build(), new SearchOptions()).getDocs()).isEmpty();
-    assertThat(underTest.search(userQuery.setLogins(emptyList()).build(), new SearchOptions()).getDocs()).isEmpty();
+  public void search_users_filter_by_organization_uuid() {
+    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER1_LOGIN, asList("user_1", "u1")).setEmail("email1")
+      .setOrganizationUuids(newArrayList("O1", "O2")));
+    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER2_LOGIN, emptyList()).setEmail("email2")
+      .setOrganizationUuids(newArrayList("O2")));
+
+    assertThat(underTest.search(userQuery.setOrganizationUuid("O42").build(), new SearchOptions()).getDocs()).isEmpty();
+    assertThat(underTest.search(userQuery.setOrganizationUuid("O2").build(), new SearchOptions()).getDocs()).hasSize(2);
+    assertThat(underTest.search(userQuery.setOrganizationUuid("O1").build(), new SearchOptions()).getDocs()).hasSize(1);
   }
 
   @Test
-  public void search_users_exclude_logins() throws Exception {
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER1_LOGIN, asList("user_1", "u1")).setEmail("email1"));
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER2_LOGIN, emptyList()).setEmail("email2"));
-    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser("user3", emptyList()).setEmail("email2"));
-
-    assertThat(underTest.search(userQuery.setExcludedLogins(emptyList()).build(), new SearchOptions()).getDocs()).hasSize(3);
-    assertThat(underTest.search(userQuery.setExcludedLogins(asList(USER1_LOGIN, USER2_LOGIN, "user3")).build(), new SearchOptions()).getDocs()).isEmpty();
-    assertThat(underTest.search(userQuery.setExcludedLogins(asList(USER1_LOGIN, USER2_LOGIN)).build(), new SearchOptions()).getDocs()).hasSize(1);
+  public void search_users_filter_by_excluded_organization_uuid() {
+    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER1_LOGIN, asList("user_1", "u1")).setEmail("email1")
+      .setOrganizationUuids(newArrayList("O1", "O2")));
+    esTester.putDocuments(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType(), newUser(USER2_LOGIN, emptyList()).setEmail("email2")
+      .setOrganizationUuids(newArrayList("O2")));
+
+    assertThat(underTest.search(userQuery.setExcludedOrganizationUuid("O42").build(), new SearchOptions()).getDocs()).hasSize(2);
+    assertThat(underTest.search(userQuery.setExcludedOrganizationUuid("O2").build(), new SearchOptions()).getDocs()).isEmpty();
+    assertThat(underTest.search(userQuery.setExcludedOrganizationUuid("O1").build(), new SearchOptions()).getDocs()).hasSize(1);
   }
 
   private static UserDoc newUser(String login, List<String> scmAccounts) {
index a293caee01dffef628a7fc007bb50ecd018ef148..8f9230c55ee651d75630483c8e002e6eb3c74ea6 100644 (file)
@@ -35,26 +35,26 @@ public class UserIndexerTest {
   private System2 system2 = System2.INSTANCE;
 
   @Rule
-  public DbTester dbTester = DbTester.create(system2);
+  public DbTester db = DbTester.create(system2);
 
   @Rule
-  public EsTester esTester = new EsTester(new UserIndexDefinition(new MapSettings()));
+  public EsTester es = new EsTester(new UserIndexDefinition(new MapSettings()));
 
   @Test
   public void index_nothing() {
     UserIndexer indexer = createIndexer();
     indexer.indexOnStartup(null);
-    assertThat(esTester.countDocuments(UserIndexDefinition.INDEX_TYPE_USER)).isEqualTo(0L);
+    assertThat(es.countDocuments(UserIndexDefinition.INDEX_TYPE_USER)).isEqualTo(0L);
   }
 
   @Test
   public void index_everything() {
-    dbTester.prepareDbUnit(getClass(), "index.xml");
+    db.prepareDbUnit(getClass(), "index.xml");
 
     UserIndexer indexer = createIndexer();
     indexer.indexOnStartup(null);
 
-    List<UserDoc> docs = esTester.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class);
+    List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class);
     assertThat(docs).hasSize(1);
     UserDoc doc = docs.get(0);
     assertThat(doc.login()).isEqualTo("user1");
@@ -68,17 +68,17 @@ public class UserIndexerTest {
 
   @Test
   public void index_single_user() {
-    UserDto user = dbTester.users().insertUser();
+    UserDto user = db.users().insertUser();
 
     UserIndexer indexer = createIndexer();
     indexer.indexOnStartup(null);
 
-    List<UserDoc> docs = esTester.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class);
+    List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class);
     assertThat(docs).hasSize(1);
     assertThat(docs).extracting(UserDoc::login).containsExactly(user.getLogin());
   }
 
   private UserIndexer createIndexer() {
-    return new UserIndexer(dbTester.getDbClient(), esTester.client());
+    return new UserIndexer(db.getDbClient(), es.client());
   }
 }
index 10171f211ea950e7b9c633ac889513c54140f58c..c2271a768ca487059a8f1573d70686519588206a 100644 (file)
  */
 package org.sonar.server.user.index;
 
-import com.google.common.base.Function;
 import com.google.common.collect.Maps;
+import java.util.Arrays;
 import java.util.Map;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.user.UserDto;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class UserResultSetIteratorTest {
 
   @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+  public DbTester db = DbTester.create();
 
   @Test
   public void iterator_over_users() {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-    UserResultSetIterator it = UserResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), null);
-    Map<String, UserDoc> usersByLogin = Maps.uniqueIndex(it, new Function<UserDoc, String>() {
-      @Override
-      public String apply(UserDoc user) {
-        return user.login();
-      }
-    });
+    UserDto userDto1 = db.users().insertUser(u -> u
+      .setName("User1")
+      .setLogin("user1")
+      .setEmail("user1@mail.com")
+      .setScmAccounts(Arrays.asList("user_1", "u1"))
+      .setCreatedAt(1_500_000_000_000L)
+      .setUpdatedAt(1_500_000_000_000L));
+    UserDto userDto2 = db.users().insertUser(u -> u
+      .setName("User2")
+      .setLogin("user2")
+      .setEmail("user2@mail.com")
+      .setScmAccounts(Arrays.asList("user,2", "user_2"))
+      .setCreatedAt(1_500_000_000_000L)
+      .setUpdatedAt(1_500_000_000_000L));
+    UserDto userDto3 = db.users().insertUser(u -> u
+      .setName("User3")
+      .setLogin("user3")
+      .setEmail(null)
+      .setActive(false)
+      .setScmAccounts((String) null)
+      .setCreatedAt(1_500_000_000_000L)
+      .setUpdatedAt(1_550_000_000_000L));
+    OrganizationDto org1 = db.organizations().insertForUuid("ORG_1");
+    OrganizationDto org2 = db.organizations().insertForUuid("ORG_2");
+    db.organizations().addMember(org1, userDto1);
+    db.organizations().addMember(org1, userDto2);
+    db.organizations().addMember(org2, userDto1);
+
+    UserResultSetIterator it = UserResultSetIterator.create(db.getDbClient(), db.getSession(), null);
+    Map<String, UserDoc> usersByLogin = Maps.uniqueIndex(it, UserDoc::login);
     it.close();
 
     assertThat(usersByLogin).hasSize(3);
@@ -53,16 +76,18 @@ public class UserResultSetIteratorTest {
     assertThat(user1.email()).isEqualTo("user1@mail.com");
     assertThat(user1.active()).isTrue();
     assertThat(user1.scmAccounts()).containsOnly("user_1", "u1");
-    assertThat(user1.createdAt()).isEqualTo(1500000000000L);
-    assertThat(user1.updatedAt()).isEqualTo(1500000000000L);
+    assertThat(user1.createdAt()).isEqualTo(1_500_000_000_000L);
+    assertThat(user1.updatedAt()).isEqualTo(1_500_000_000_000L);
+    assertThat(user1.organizationUuids()).containsOnly("ORG_1", "ORG_2");
 
     UserDoc user2 = usersByLogin.get("user2");
     assertThat(user2.name()).isEqualTo("User2");
     assertThat(user2.email()).isEqualTo("user2@mail.com");
     assertThat(user2.active()).isTrue();
     assertThat(user2.scmAccounts()).containsOnly("user,2", "user_2");
-    assertThat(user2.createdAt()).isEqualTo(1500000000000L);
-    assertThat(user2.updatedAt()).isEqualTo(1500000000000L);
+    assertThat(user2.createdAt()).isEqualTo(1_500_000_000_000L);
+    assertThat(user2.updatedAt()).isEqualTo(1_500_000_000_000L);
+    assertThat(user2.organizationUuids()).containsOnly("ORG_1");
 
     UserDoc user3 = usersByLogin.get("user3");
     assertThat(user3.name()).isEqualTo("User3");
@@ -71,5 +96,6 @@ public class UserResultSetIteratorTest {
     assertThat(user3.scmAccounts()).isEmpty();
     assertThat(user3.createdAt()).isEqualTo(1500000000000L);
     assertThat(user3.updatedAt()).isEqualTo(1550000000000L);
+    assertThat(user3.organizationUuids()).isEmpty();
   }
 }
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/index/UserResultSetIteratorTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/user/index/UserResultSetIteratorTest/shared.xml
deleted file mode 100644 (file)
index 6af8bdf..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<dataset>
-
-  <users id="1"
-         login="user1"
-         name="User1"
-         email="user1@mail.com"
-         active="[true]"
-         scm_accounts="&#10;user_1&#10;u1&#10;"
-         created_at="1500000000000"
-         updated_at="1500000000000"
-         is_root="[false]"/>
-
-  <!-- scm accounts with comma -->
-  <users id="2"
-         login="user2"
-         name="User2"
-         email="user2@mail.com"
-         active="[true]"
-         scm_accounts="&#10;user,2&#10;user_2&#10;"
-         created_at="1500000000000"
-         updated_at="1500000000000"
-         is_root="[false]"/>
-
-  <!--no scm account, no email -->
-  <users id="3"
-         login="user3"
-         name="User3"
-         email="[null]"
-         active="[false]"
-         scm_accounts="[null]"
-         created_at="1500000000000"
-         updated_at="1550000000000"
-         is_root="[false]"/>
-
-</dataset>