summaryrefslogtreecommitdiffstats
path: root/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java')
-rw-r--r--javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java1125
1 files changed, 1125 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java b/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java
new file mode 100644
index 0000000000..78fef3932c
--- /dev/null
+++ b/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java
@@ -0,0 +1,1125 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.schema;
+
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.assertThat;
+import static com.google.gerrit.server.notedb.NoteDbTable.GROUPS;
+import static com.google.gerrit.server.notedb.NotesMigration.DISABLE_REVIEW_DB;
+import static com.google.gerrit.server.notedb.NotesMigration.SECTION_NOTE_DB;
+import static com.google.gerrit.truth.OptionalSubject.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.accounts.AccountInput;
+import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.CommitInfo;
+import com.google.gerrit.extensions.common.GroupAuditEventInfo;
+import com.google.gerrit.extensions.common.GroupAuditEventInfo.GroupMemberAuditEventInfo;
+import com.google.gerrit.extensions.common.GroupAuditEventInfo.Type;
+import com.google.gerrit.extensions.common.GroupAuditEventInfo.UserMemberAuditEventInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.common.GroupOptionsInfo;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbWrapper;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.Sequences;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.account.GroupUUID;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerId;
+import com.google.gerrit.server.config.GerritServerIdProvider;
+import com.google.gerrit.server.git.CommitUtil;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.group.db.GroupConfig;
+import com.google.gerrit.server.group.db.GroupNameNotes;
+import com.google.gerrit.server.group.db.GroupsConsistencyChecker;
+import com.google.gerrit.server.group.testing.InternalGroupSubject;
+import com.google.gerrit.server.group.testing.TestGroupBackend;
+import com.google.gerrit.server.util.time.TimeUtil;
+import com.google.gerrit.testing.InMemoryTestEnvironment;
+import com.google.gerrit.testing.TestTimeUtil;
+import com.google.gerrit.testing.TestTimeUtil.TempClockStep;
+import com.google.gerrit.testing.TestUpdateUI;
+import com.google.gerrit.truth.OptionalSubject;
+import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import java.io.IOException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class Schema_166_to_167_WithGroupsInReviewDbTest {
+ private static Config createConfig() {
+ Config config = new Config();
+ config.setString(GerritServerIdProvider.SECTION, null, GerritServerIdProvider.KEY, "1234567");
+
+ // Enable groups in ReviewDb. This means the primary storage for groups is ReviewDb.
+ config.setBoolean(SECTION_NOTE_DB, GROUPS.key(), DISABLE_REVIEW_DB, false);
+
+ return config;
+ }
+
+ @Rule
+ public InMemoryTestEnvironment testEnv =
+ new InMemoryTestEnvironment(Schema_166_to_167_WithGroupsInReviewDbTest::createConfig);
+
+ @Inject private GerritApi gApi;
+ @Inject private Schema_167 schema167;
+ @Inject private ReviewDb db;
+ @Inject private GitRepositoryManager gitRepoManager;
+ @Inject private AllUsersName allUsersName;
+ @Inject private GroupsConsistencyChecker consistencyChecker;
+ @Inject private IdentifiedUser currentUser;
+ @Inject private @GerritServerId String serverId;
+ @Inject private @GerritPersonIdent PersonIdent serverIdent;
+ @Inject private GroupBundle.Factory groupBundleFactory;
+ @Inject private GroupBackend groupBackend;
+ @Inject private DynamicSet<GroupBackend> backends;
+ @Inject private Sequences seq;
+
+ private JdbcSchema jdbcSchema;
+
+ @Before
+ public void initDb() throws Exception {
+ jdbcSchema = ReviewDbWrapper.unwrapJbdcSchema(db);
+
+ try (Statement stmt = jdbcSchema.getConnection().createStatement()) {
+ stmt.execute(
+ "CREATE TABLE account_groups ("
+ + " group_uuid varchar(255) DEFAULT '' NOT NULL,"
+ + " group_id INTEGER DEFAULT 0 NOT NULL,"
+ + " name varchar(255) DEFAULT '' NOT NULL,"
+ + " created_on TIMESTAMP,"
+ + " description CLOB,"
+ + " owner_group_uuid varchar(255) DEFAULT '' NOT NULL,"
+ + " visible_to_all CHAR(1) DEFAULT 'N' NOT NULL"
+ + ")");
+
+ stmt.execute(
+ "CREATE TABLE account_group_members ("
+ + " group_id INTEGER DEFAULT 0 NOT NULL,"
+ + " account_id INTEGER DEFAULT 0 NOT NULL"
+ + ")");
+
+ stmt.execute(
+ "CREATE TABLE account_group_members_audit ("
+ + " group_id INTEGER DEFAULT 0 NOT NULL,"
+ + " account_id INTEGER DEFAULT 0 NOT NULL,"
+ + " added_by INTEGER DEFAULT 0 NOT NULL,"
+ + " added_on TIMESTAMP,"
+ + " removed_by INTEGER,"
+ + " removed_on TIMESTAMP"
+ + ")");
+
+ stmt.execute(
+ "CREATE TABLE account_group_by_id ("
+ + " group_id INTEGER DEFAULT 0 NOT NULL,"
+ + " include_uuid VARCHAR(255) DEFAULT '' NOT NULL"
+ + ")");
+
+ stmt.execute(
+ "CREATE TABLE account_group_by_id_aud ("
+ + " group_id INTEGER DEFAULT 0 NOT NULL,"
+ + " include_uuid VARCHAR(255) DEFAULT '' NOT NULL,"
+ + " added_by INTEGER DEFAULT 0 NOT NULL,"
+ + " added_on TIMESTAMP,"
+ + " removed_by INTEGER,"
+ + " removed_on TIMESTAMP"
+ + ")");
+ }
+ }
+
+ @Before
+ public void setTimeForTesting() {
+ TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
+ }
+
+ @After
+ public void resetTime() {
+ TestTimeUtil.useSystemTime();
+ }
+
+ @Test
+ public void reviewDbOnlyGroupsAreMigratedToNoteDb() throws Exception {
+ // Create groups only in ReviewDb
+ AccountGroup group1 = newGroup().setName("verifiers").build();
+ AccountGroup group2 = newGroup().setName("contributors").build();
+ storeInReviewDb(group1, group2);
+
+ executeSchemaMigration(schema167, group1, group2);
+
+ ImmutableList<GroupReference> groups = getAllGroupsFromNoteDb();
+ ImmutableList<String> groupNames =
+ groups.stream().map(GroupReference::getName).collect(toImmutableList());
+ assertThat(groupNames).containsAllOf("verifiers", "contributors");
+ }
+
+ @Test
+ public void alreadyExistingGroupsAreMigratedToNoteDb() throws Exception {
+ // Create group in NoteDb and ReviewDb
+ GroupInput groupInput = new GroupInput();
+ groupInput.name = "verifiers";
+ groupInput.description = "old";
+ GroupInfo group1 = gApi.groups().create(groupInput).get();
+ storeInReviewDb(group1);
+
+ // Update group only in ReviewDb
+ AccountGroup group1InReviewDb = getFromReviewDb(new AccountGroup.Id(group1.groupId));
+ group1InReviewDb.setDescription("new");
+ updateInReviewDb(group1InReviewDb);
+
+ // Create a second group in NoteDb and ReviewDb
+ GroupInfo group2 = gApi.groups().create("contributors").get();
+ storeInReviewDb(group2);
+
+ executeSchemaMigration(schema167, group1, group2);
+
+ // Verify that both groups are present in NoteDb
+ ImmutableList<GroupReference> groups = getAllGroupsFromNoteDb();
+ ImmutableList<String> groupNames =
+ groups.stream().map(GroupReference::getName).collect(toImmutableList());
+ assertThat(groupNames).containsAllOf("verifiers", "contributors");
+
+ // Verify that group1 has the description from ReviewDb
+ Optional<InternalGroup> group1InNoteDb = getGroupFromNoteDb(new AccountGroup.UUID(group1.id));
+ assertThatGroup(group1InNoteDb).value().description().isEqualTo("new");
+ }
+
+ @Test
+ public void adminGroupIsMigratedToNoteDb() throws Exception {
+ // Administrators group is automatically created for all Gerrit servers (NoteDb only).
+ GroupInfo adminGroup = gApi.groups().id("Administrators").get();
+ storeInReviewDb(adminGroup);
+
+ executeSchemaMigration(schema167, adminGroup);
+
+ ImmutableList<GroupReference> groups = getAllGroupsFromNoteDb();
+ ImmutableList<String> groupNames =
+ groups.stream().map(GroupReference::getName).collect(toImmutableList());
+ assertThat(groupNames).contains("Administrators");
+ }
+
+ @Test
+ public void nonInteractiveUsersGroupIsMigratedToNoteDb() throws Exception {
+ // 'Non-Interactive Users' group is automatically created for all Gerrit servers (NoteDb only).
+ GroupInfo nonInteractiveUsersGroup = gApi.groups().id("Non-Interactive Users").get();
+ storeInReviewDb(nonInteractiveUsersGroup);
+
+ executeSchemaMigration(schema167, nonInteractiveUsersGroup);
+
+ ImmutableList<GroupReference> groups = getAllGroupsFromNoteDb();
+ ImmutableList<String> groupNames =
+ groups.stream().map(GroupReference::getName).collect(toImmutableList());
+ assertThat(groupNames).contains("Non-Interactive Users");
+ }
+
+ @Test
+ public void groupsAreConsistentAfterMigrationToNoteDb() throws Exception {
+ // Administrators group are automatically created for all Gerrit servers (NoteDb only).
+ GroupInfo adminGroup = gApi.groups().id("Administrators").get();
+ GroupInfo nonInteractiveUsersGroup = gApi.groups().id("Non-Interactive Users").get();
+ storeInReviewDb(adminGroup, nonInteractiveUsersGroup);
+
+ AccountGroup group1 = newGroup().setName("verifiers").build();
+ AccountGroup group2 = newGroup().setName("contributors").build();
+ storeInReviewDb(group1, group2);
+
+ executeSchemaMigration(schema167, group1, group2);
+
+ List<ConsistencyCheckInfo.ConsistencyProblemInfo> consistencyProblems =
+ consistencyChecker.check();
+ assertThat(consistencyProblems).isEmpty();
+ }
+
+ @Test
+ public void nameIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().setName("verifiers").build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().name().isEqualTo("verifiers");
+ }
+
+ @Test
+ public void emptyNameIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().setName("").build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().name().isEqualTo("");
+ }
+
+ @Test
+ public void uuidIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup.UUID groupUuid = new AccountGroup.UUID("ABCDEF");
+ AccountGroup group = newGroup().setGroupUuid(groupUuid).build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(groupUuid);
+ assertThatGroup(groupInNoteDb).value().groupUuid().isEqualTo(groupUuid);
+ }
+
+ @Test
+ public void idIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup.Id id = new AccountGroup.Id(12345);
+ AccountGroup group = newGroup().setId(id).build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().id().isEqualTo(id);
+ }
+
+ @Test
+ public void createdOnIsKeptDuringMigrationToNoteDb() throws Exception {
+ Timestamp createdOn =
+ Timestamp.from(
+ LocalDate.of(2018, Month.FEBRUARY, 20)
+ .atTime(18, 2, 56)
+ .atZone(ZoneOffset.UTC)
+ .toInstant());
+ AccountGroup group = newGroup().setCreatedOn(createdOn).build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().createdOn().isEqualTo(createdOn);
+ }
+
+ @Test
+ public void ownerUuidIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup.UUID ownerGroupUuid = new AccountGroup.UUID("UVWXYZ");
+ AccountGroup group = newGroup().setOwnerGroupUuid(ownerGroupUuid).build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().ownerGroupUuid().isEqualTo(ownerGroupUuid);
+ }
+
+ @Test
+ public void descriptionIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().setDescription("A test group").build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().description().isEqualTo("A test group");
+ }
+
+ @Test
+ public void absentDescriptionIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().description().isNull();
+ }
+
+ @Test
+ public void visibleToAllIsKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().setVisibleToAll(true).build();
+ storeInReviewDb(group);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().visibleToAll().isTrue();
+ }
+
+ @Test
+ public void membersAreKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().build();
+ storeInReviewDb(group);
+ Account.Id member1 = new Account.Id(23456);
+ Account.Id member2 = new Account.Id(93483);
+ addMembersInReviewDb(group.getId(), member1, member2);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().members().containsExactly(member1, member2);
+ }
+
+ @Test
+ public void subgroupsAreKeptDuringMigrationToNoteDb() throws Exception {
+ AccountGroup group = newGroup().build();
+ storeInReviewDb(group);
+ AccountGroup.UUID subgroup1 = new AccountGroup.UUID("FGHIKL");
+ AccountGroup.UUID subgroup2 = new AccountGroup.UUID("MNOPQR");
+ addSubgroupsInReviewDb(group.getId(), subgroup1, subgroup2);
+
+ executeSchemaMigration(schema167, group);
+
+ Optional<InternalGroup> groupInNoteDb = getGroupFromNoteDb(group.getGroupUUID());
+ assertThatGroup(groupInNoteDb).value().subgroups().containsExactly(subgroup1, subgroup2);
+ }
+
+ @Test
+ public void logFormatWithAccountsAndGerritGroups() throws Exception {
+ AccountInfo user1 = createAccount("user1");
+ AccountInfo user2 = createAccount("user2");
+
+ AccountGroup group1 = createInReviewDb("group1");
+ AccountGroup group2 = createInReviewDb("group2");
+ AccountGroup group3 = createInReviewDb("group3");
+
+ // Add some accounts
+ try (TempClockStep step = TestTimeUtil.freezeClock()) {
+ addMembersInReviewDb(
+ group1.getId(), new Account.Id(user1._accountId), new Account.Id(user2._accountId));
+ }
+ TimeUtil.nowTs();
+
+ // Add some Gerrit groups
+ try (TempClockStep step = TestTimeUtil.freezeClock()) {
+ addSubgroupsInReviewDb(group1.getId(), group2.getGroupUUID(), group3.getGroupUUID());
+ }
+
+ executeSchemaMigration(schema167, group1, group2, group3);
+
+ GroupBundle noteDbBundle = readGroupBundleFromNoteDb(group1.getGroupUUID());
+
+ ImmutableList<CommitInfo> log = log(group1);
+ assertThat(log).hasSize(4);
+
+ // Verify commit that created the group
+ assertThat(log.get(0)).message().isEqualTo("Create group");
+ assertThat(log.get(0)).author().name().isEqualTo(serverIdent.getName());
+ assertThat(log.get(0)).author().email().isEqualTo(serverIdent.getEmailAddress());
+ assertThat(log.get(0)).author().date().isEqualTo(noteDbBundle.group().getCreatedOn());
+ assertThat(log.get(0)).author().tz().isEqualTo(serverIdent.getTimeZoneOffset());
+ assertThat(log.get(0)).committer().isEqualTo(log.get(0).author);
+
+ // Verify commit that the group creator as member
+ assertThat(log.get(1))
+ .message()
+ .isEqualTo(
+ "Update group\n\nAdd: "
+ + currentUser.getName()
+ + " <"
+ + currentUser.getAccountId()
+ + "@"
+ + serverId
+ + ">");
+ assertThat(log.get(1)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(1)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(1)).committer().hasSameDateAs(log.get(1).author);
+
+ // Verify commit that added members
+ assertThat(log.get(2))
+ .message()
+ .isEqualTo(
+ "Update group\n"
+ + "\n"
+ + ("Add: user1 <" + user1._accountId + "@" + serverId + ">\n")
+ + ("Add: user2 <" + user2._accountId + "@" + serverId + ">"));
+ assertThat(log.get(2)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(2)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
+
+ // Verify commit that added Gerrit groups
+ assertThat(log.get(3))
+ .message()
+ .isEqualTo(
+ "Update group\n"
+ + "\n"
+ + ("Add-group: " + group2.getName() + " <" + group2.getGroupUUID().get() + ">\n")
+ + ("Add-group: " + group3.getName() + " <" + group3.getGroupUUID().get() + ">"));
+ assertThat(log.get(3)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(3)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(3)).committer().hasSameDateAs(log.get(3).author);
+
+ // Verify that audit log is correctly read by Gerrit
+ List<? extends GroupAuditEventInfo> auditEvents =
+ gApi.groups().id(group1.getGroupUUID().get()).auditLog();
+ assertThat(auditEvents).hasSize(5);
+ AccountInfo currentUserInfo = gApi.accounts().id(currentUser.getAccountId().get()).get();
+ assertMemberAuditEvent(
+ auditEvents.get(4), Type.ADD_USER, currentUser.getAccountId(), currentUserInfo);
+ assertMemberAuditEvents(
+ auditEvents.get(3),
+ auditEvents.get(2),
+ Type.ADD_USER,
+ currentUser.getAccountId(),
+ user1,
+ user2);
+ assertSubgroupAuditEvents(
+ auditEvents.get(1),
+ auditEvents.get(0),
+ Type.ADD_GROUP,
+ currentUser.getAccountId(),
+ toGroupInfo(group2),
+ toGroupInfo(group3));
+ }
+
+ @Test
+ public void logFormatWithSystemGroups() throws Exception {
+ AccountGroup group = createInReviewDb("group");
+
+ try (TempClockStep step = TestTimeUtil.freezeClock()) {
+ addSubgroupsInReviewDb(
+ group.getId(), SystemGroupBackend.ANONYMOUS_USERS, SystemGroupBackend.REGISTERED_USERS);
+ }
+
+ executeSchemaMigration(schema167, group);
+
+ GroupBundle noteDbBundle = readGroupBundleFromNoteDb(group.getGroupUUID());
+
+ ImmutableList<CommitInfo> log = log(group);
+ assertThat(log).hasSize(3);
+
+ // Verify commit that created the group
+ assertThat(log.get(0)).message().isEqualTo("Create group");
+ assertThat(log.get(0)).author().name().isEqualTo(serverIdent.getName());
+ assertThat(log.get(0)).author().email().isEqualTo(serverIdent.getEmailAddress());
+ assertThat(log.get(0)).author().date().isEqualTo(noteDbBundle.group().getCreatedOn());
+ assertThat(log.get(0)).author().tz().isEqualTo(serverIdent.getTimeZoneOffset());
+ assertThat(log.get(0)).committer().isEqualTo(log.get(0).author);
+
+ // Verify commit that the group creator as member
+ assertThat(log.get(1))
+ .message()
+ .isEqualTo(
+ "Update group\n\nAdd: "
+ + currentUser.getName()
+ + " <"
+ + currentUser.getAccountId()
+ + "@"
+ + serverId
+ + ">");
+ assertThat(log.get(1)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(1)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(1)).committer().hasSameDateAs(log.get(1).author);
+
+ // Verify commit that added system groups
+ assertThat(log.get(2))
+ .message()
+ .isEqualTo(
+ "Update group\n"
+ + "\n"
+ + "Add-group: Anonymous Users <global:Anonymous-Users>\n"
+ + "Add-group: Registered Users <global:Registered-Users>");
+ assertThat(log.get(2)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(2)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
+
+ // Verify that audit log is correctly read by Gerrit
+ List<? extends GroupAuditEventInfo> auditEvents =
+ gApi.groups().id(group.getGroupUUID().get()).auditLog();
+ assertThat(auditEvents).hasSize(3);
+ AccountInfo currentUserInfo = gApi.accounts().id(currentUser.getAccountId().get()).get();
+ assertMemberAuditEvent(
+ auditEvents.get(2), Type.ADD_USER, currentUser.getAccountId(), currentUserInfo);
+ assertSubgroupAuditEvents(
+ auditEvents.get(1),
+ auditEvents.get(0),
+ Type.ADD_GROUP,
+ currentUser.getAccountId(),
+ groupInfoForExternalGroup(SystemGroupBackend.ANONYMOUS_USERS),
+ groupInfoForExternalGroup(SystemGroupBackend.REGISTERED_USERS));
+ }
+
+ @Test
+ public void logFormatWithExternalGroup() throws Exception {
+ AccountGroup group = createInReviewDb("group");
+
+ TestGroupBackend testGroupBackend = new TestGroupBackend();
+ backends.add("gerrit", testGroupBackend);
+ AccountGroup.UUID subgroupUuid = testGroupBackend.create("test").getGroupUUID();
+ assertThat(groupBackend.handles(subgroupUuid)).isTrue();
+ addSubgroupsInReviewDb(group.getId(), subgroupUuid);
+
+ executeSchemaMigration(schema167, group);
+
+ GroupBundle noteDbBundle = readGroupBundleFromNoteDb(group.getGroupUUID());
+
+ ImmutableList<CommitInfo> log = log(group);
+ assertThat(log).hasSize(3);
+
+ // Verify commit that created the group
+ assertThat(log.get(0)).message().isEqualTo("Create group");
+ assertThat(log.get(0)).author().name().isEqualTo(serverIdent.getName());
+ assertThat(log.get(0)).author().email().isEqualTo(serverIdent.getEmailAddress());
+ assertThat(log.get(0)).author().date().isEqualTo(noteDbBundle.group().getCreatedOn());
+ assertThat(log.get(0)).author().tz().isEqualTo(serverIdent.getTimeZoneOffset());
+ assertThat(log.get(0)).committer().isEqualTo(log.get(0).author);
+
+ // Verify commit that the group creator as member
+ assertThat(log.get(1))
+ .message()
+ .isEqualTo(
+ "Update group\n\nAdd: "
+ + currentUser.getName()
+ + " <"
+ + currentUser.getAccountId()
+ + "@"
+ + serverId
+ + ">");
+ assertThat(log.get(1)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(1)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(1)).committer().hasSameDateAs(log.get(1).author);
+
+ // Verify commit that added system groups
+ // Note: The schema migration can only resolve names of Gerrit groups, not of external groups
+ // and system groups, hence the UUID shows up in commit messages where we would otherwise
+ // expect the group name.
+ assertThat(log.get(2))
+ .message()
+ .isEqualTo(
+ "Update group\n"
+ + "\n"
+ + "Add-group: "
+ + subgroupUuid.get()
+ + " <"
+ + subgroupUuid.get()
+ + ">");
+ assertThat(log.get(2)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(2)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
+
+ // Verify that audit log is correctly read by Gerrit
+ List<? extends GroupAuditEventInfo> auditEvents =
+ gApi.groups().id(group.getGroupUUID().get()).auditLog();
+ assertThat(auditEvents).hasSize(2);
+ AccountInfo currentUserInfo = gApi.accounts().id(currentUser.getAccountId().get()).get();
+ assertMemberAuditEvent(
+ auditEvents.get(1), Type.ADD_USER, currentUser.getAccountId(), currentUserInfo);
+ assertSubgroupAuditEvent(
+ auditEvents.get(0),
+ Type.ADD_GROUP,
+ currentUser.getAccountId(),
+ groupInfoForExternalGroup(subgroupUuid));
+ }
+
+ @Test
+ public void logFormatWithNonExistingExternalGroup() throws Exception {
+ AccountGroup group = createInReviewDb("group");
+
+ AccountGroup.UUID subgroupUuid = new AccountGroup.UUID("notExisting:foo");
+
+ assertThat(groupBackend.handles(subgroupUuid)).isFalse();
+ addSubgroupsInReviewDb(group.getId(), subgroupUuid);
+
+ executeSchemaMigration(schema167, group);
+
+ GroupBundle noteDbBundle = readGroupBundleFromNoteDb(group.getGroupUUID());
+
+ ImmutableList<CommitInfo> log = log(group);
+ assertThat(log).hasSize(3);
+
+ // Verify commit that created the group
+ assertThat(log.get(0)).message().isEqualTo("Create group");
+ assertThat(log.get(0)).author().name().isEqualTo(serverIdent.getName());
+ assertThat(log.get(0)).author().email().isEqualTo(serverIdent.getEmailAddress());
+ assertThat(log.get(0)).author().date().isEqualTo(noteDbBundle.group().getCreatedOn());
+ assertThat(log.get(0)).author().tz().isEqualTo(serverIdent.getTimeZoneOffset());
+ assertThat(log.get(0)).committer().isEqualTo(log.get(0).author);
+
+ // Verify commit that the group creator as member
+ assertThat(log.get(1))
+ .message()
+ .isEqualTo(
+ "Update group\n\nAdd: "
+ + currentUser.getName()
+ + " <"
+ + currentUser.getAccountId()
+ + "@"
+ + serverId
+ + ">");
+ assertThat(log.get(1)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(1)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(1)).committer().hasSameDateAs(log.get(1).author);
+
+ // Verify commit that added system groups
+ // Note: The schema migration can only resolve names of Gerrit groups, not of external groups
+ // and system groups, hence the UUID shows up in commit messages where we would otherwise
+ // expect the group name.
+ assertThat(log.get(2))
+ .message()
+ .isEqualTo("Update group\n" + "\n" + "Add-group: notExisting:foo <notExisting:foo>");
+ assertThat(log.get(2)).author().name().isEqualTo(currentUser.getName());
+ assertThat(log.get(2)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+ assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
+
+ // Verify that audit log is correctly read by Gerrit
+ List<? extends GroupAuditEventInfo> auditEvents =
+ gApi.groups().id(group.getGroupUUID().get()).auditLog();
+ assertThat(auditEvents).hasSize(2);
+ AccountInfo currentUserInfo = gApi.accounts().id(currentUser.getAccountId().get()).get();
+ assertMemberAuditEvent(
+ auditEvents.get(1), Type.ADD_USER, currentUser.getAccountId(), currentUserInfo);
+ assertSubgroupAuditEvent(
+ auditEvents.get(0),
+ Type.ADD_GROUP,
+ currentUser.getAccountId(),
+ groupInfoForExternalGroup(subgroupUuid));
+ }
+
+ private static TestGroup.Builder newGroup() {
+ return TestGroup.builder();
+ }
+
+ private AccountGroup createInReviewDb(String groupName) throws Exception {
+ AccountGroup group =
+ new AccountGroup(
+ new AccountGroup.NameKey(groupName),
+ new AccountGroup.Id(seq.nextGroupId()),
+ GroupUUID.make(groupName, serverIdent),
+ TimeUtil.nowTs());
+ storeInReviewDb(group);
+ addMembersInReviewDb(group.getId(), currentUser.getAccountId());
+ return group;
+ }
+
+ private void storeInReviewDb(GroupInfo... groups) throws Exception {
+ storeInReviewDb(
+ Arrays.stream(groups)
+ .map(Schema_166_to_167_WithGroupsInReviewDbTest::toAccountGroup)
+ .toArray(AccountGroup[]::new));
+ }
+
+ private void storeInReviewDb(AccountGroup... groups) throws Exception {
+ try (PreparedStatement stmt =
+ jdbcSchema
+ .getConnection()
+ .prepareStatement(
+ "INSERT INTO account_groups"
+ + " (group_uuid,"
+ + " group_id,"
+ + " name,"
+ + " description,"
+ + " created_on,"
+ + " owner_group_uuid,"
+ + " visible_to_all) VALUES (?, ?, ?, ?, ?, ?, ?)")) {
+ for (AccountGroup group : groups) {
+ stmt.setString(1, group.getGroupUUID().get());
+ stmt.setInt(2, group.getId().get());
+ stmt.setString(3, group.getName());
+ stmt.setString(4, group.getDescription());
+ stmt.setTimestamp(5, group.getCreatedOn());
+ stmt.setString(6, group.getOwnerGroupUUID().get());
+ stmt.setString(7, group.isVisibleToAll() ? "Y" : "N");
+ stmt.addBatch();
+ }
+ stmt.executeBatch();
+ }
+ }
+
+ private void updateInReviewDb(AccountGroup... groups) throws Exception {
+ try (PreparedStatement stmt =
+ jdbcSchema
+ .getConnection()
+ .prepareStatement(
+ "UPDATE account_groups SET"
+ + " group_uuid = ?,"
+ + " name = ?,"
+ + " description = ?,"
+ + " created_on = ?,"
+ + " owner_group_uuid = ?,"
+ + " visible_to_all = ?"
+ + " WHERE group_id = ?")) {
+ for (AccountGroup group : groups) {
+ stmt.setString(1, group.getGroupUUID().get());
+ stmt.setString(2, group.getName());
+ stmt.setString(3, group.getDescription());
+ stmt.setTimestamp(4, group.getCreatedOn());
+ stmt.setString(5, group.getOwnerGroupUUID().get());
+ stmt.setString(6, group.isVisibleToAll() ? "Y" : "N");
+ stmt.setInt(7, group.getId().get());
+ stmt.addBatch();
+ }
+ stmt.executeBatch();
+ }
+ }
+
+ private AccountGroup getFromReviewDb(AccountGroup.Id groupId) throws Exception {
+ try (Statement stmt = jdbcSchema.getConnection().createStatement();
+ ResultSet rs =
+ stmt.executeQuery(
+ "SELECT group_uuid,"
+ + " name,"
+ + " description,"
+ + " created_on,"
+ + " owner_group_uuid,"
+ + " visible_to_all"
+ + " FROM account_groups"
+ + " WHERE group_id = "
+ + groupId.get())) {
+ if (!rs.next()) {
+ throw new OrmException(String.format("Group %s not found", groupId.get()));
+ }
+
+ AccountGroup.UUID groupUuid = new AccountGroup.UUID(rs.getString(1));
+ AccountGroup.NameKey groupName = new AccountGroup.NameKey(rs.getString(2));
+ String description = rs.getString(3);
+ Timestamp createdOn = rs.getTimestamp(4);
+ AccountGroup.UUID ownerGroupUuid = new AccountGroup.UUID(rs.getString(5));
+ boolean visibleToAll = "Y".equals(rs.getString(6));
+
+ AccountGroup group = new AccountGroup(groupName, groupId, groupUuid, createdOn);
+ group.setDescription(description);
+ group.setOwnerGroupUUID(ownerGroupUuid);
+ group.setVisibleToAll(visibleToAll);
+
+ if (rs.next()) {
+ throw new OrmException(String.format("Group ID %s is ambiguous", groupId.get()));
+ }
+
+ return group;
+ }
+ }
+
+ private void addMembersInReviewDb(AccountGroup.Id groupId, Account.Id... memberIds)
+ throws Exception {
+ try (PreparedStatement addMemberStmt =
+ jdbcSchema
+ .getConnection()
+ .prepareStatement(
+ "INSERT INTO account_group_members"
+ + " (group_id,"
+ + " account_id) VALUES ("
+ + groupId.get()
+ + ", ?)");
+ PreparedStatement addMemberAuditStmt =
+ jdbcSchema
+ .getConnection()
+ .prepareStatement(
+ "INSERT INTO account_group_members_audit"
+ + " (group_id,"
+ + " account_id,"
+ + " added_by,"
+ + " added_on) VALUES ("
+ + groupId.get()
+ + ", ?, "
+ + currentUser.getAccountId().get()
+ + ", ?)")) {
+ Timestamp addedOn = TimeUtil.nowTs();
+ for (Account.Id memberId : memberIds) {
+ addMemberStmt.setInt(1, memberId.get());
+ addMemberStmt.addBatch();
+
+ addMemberAuditStmt.setInt(1, memberId.get());
+ addMemberAuditStmt.setTimestamp(2, addedOn);
+ addMemberAuditStmt.addBatch();
+ }
+ addMemberStmt.executeBatch();
+ addMemberAuditStmt.executeBatch();
+ }
+ }
+
+ private void addSubgroupsInReviewDb(AccountGroup.Id groupId, AccountGroup.UUID... subgroupUuids)
+ throws Exception {
+ try (PreparedStatement addSubGroupStmt =
+ jdbcSchema
+ .getConnection()
+ .prepareStatement(
+ "INSERT INTO account_group_by_id"
+ + " (group_id,"
+ + " include_uuid) VALUES ("
+ + groupId.get()
+ + ", ?)");
+ PreparedStatement addSubGroupAuditStmt =
+ jdbcSchema
+ .getConnection()
+ .prepareStatement(
+ "INSERT INTO account_group_by_id_aud"
+ + " (group_id,"
+ + " include_uuid,"
+ + " added_by,"
+ + " added_on) VALUES ("
+ + groupId.get()
+ + ", ?, "
+ + currentUser.getAccountId().get()
+ + ", ?)")) {
+ Timestamp addedOn = TimeUtil.nowTs();
+ for (AccountGroup.UUID subgroupUuid : subgroupUuids) {
+ addSubGroupStmt.setString(1, subgroupUuid.get());
+ addSubGroupStmt.addBatch();
+
+ addSubGroupAuditStmt.setString(1, subgroupUuid.get());
+ addSubGroupAuditStmt.setTimestamp(2, addedOn);
+ addSubGroupAuditStmt.addBatch();
+ }
+ addSubGroupStmt.executeBatch();
+ addSubGroupAuditStmt.executeBatch();
+ }
+ }
+
+ private AccountInfo createAccount(String name) throws RestApiException {
+ AccountInput accountInput = new AccountInput();
+ accountInput.username = name;
+ accountInput.name = name;
+ return gApi.accounts().create(accountInput).get();
+ }
+
+ private GroupBundle readGroupBundleFromNoteDb(AccountGroup.UUID groupUuid) throws Exception {
+ try (Repository allUsersRepo = gitRepoManager.openRepository(allUsersName)) {
+ return groupBundleFactory.fromNoteDb(allUsersName, allUsersRepo, groupUuid);
+ }
+ }
+
+ private void executeSchemaMigration(SchemaVersion schema, AccountGroup... groupsToVerify)
+ throws Exception {
+ executeSchemaMigration(
+ schema,
+ Arrays.stream(groupsToVerify)
+ .map(AccountGroup::getGroupUUID)
+ .toArray(AccountGroup.UUID[]::new));
+ }
+
+ private void executeSchemaMigration(SchemaVersion schema, GroupInfo... groupsToVerify)
+ throws Exception {
+ executeSchemaMigration(
+ schema,
+ Arrays.stream(groupsToVerify)
+ .map(i -> new AccountGroup.UUID(i.id))
+ .toArray(AccountGroup.UUID[]::new));
+ }
+
+ private void executeSchemaMigration(SchemaVersion schema, AccountGroup.UUID... groupsToVerify)
+ throws Exception {
+ List<GroupBundle> reviewDbBundles = new ArrayList<>();
+ for (AccountGroup.UUID groupUuid : groupsToVerify) {
+ reviewDbBundles.add(GroupBundle.Factory.fromReviewDb(db, groupUuid));
+ }
+
+ schema.migrateData(db, new TestUpdateUI());
+
+ for (GroupBundle reviewDbBundle : reviewDbBundles) {
+ assertMigratedCleanly(readGroupBundleFromNoteDb(reviewDbBundle.uuid()), reviewDbBundle);
+ }
+ }
+
+ private void assertMigratedCleanly(GroupBundle noteDbBundle, GroupBundle expectedReviewDbBundle) {
+ assertThat(GroupBundle.compareWithAudits(expectedReviewDbBundle, noteDbBundle)).isEmpty();
+ }
+
+ private ImmutableList<CommitInfo> log(AccountGroup group) throws Exception {
+ ImmutableList.Builder<CommitInfo> result = ImmutableList.builder();
+ List<Date> commitDates = new ArrayList<>();
+ try (Repository allUsersRepo = gitRepoManager.openRepository(allUsersName);
+ RevWalk rw = new RevWalk(allUsersRepo)) {
+ Ref ref = allUsersRepo.exactRef(RefNames.refsGroups(group.getGroupUUID()));
+ if (ref != null) {
+ rw.sort(RevSort.REVERSE);
+ rw.setRetainBody(true);
+ rw.markStart(rw.parseCommit(ref.getObjectId()));
+ for (RevCommit c : rw) {
+ result.add(CommitUtil.toCommitInfo(c));
+ commitDates.add(c.getCommitterIdent().getWhen());
+ }
+ }
+ }
+ assertThat(commitDates).named("commit timestamps for %s", result).isOrdered();
+ return result.build();
+ }
+
+ private ImmutableList<GroupReference> getAllGroupsFromNoteDb()
+ throws IOException, ConfigInvalidException {
+ try (Repository allUsersRepo = gitRepoManager.openRepository(allUsersName)) {
+ return GroupNameNotes.loadAllGroups(allUsersRepo);
+ }
+ }
+
+ private Optional<InternalGroup> getGroupFromNoteDb(AccountGroup.UUID groupUuid) throws Exception {
+ try (Repository allUsersRepo = gitRepoManager.openRepository(allUsersName)) {
+ return GroupConfig.loadForGroup(allUsersName, allUsersRepo, groupUuid).getLoadedGroup();
+ }
+ }
+
+ private static OptionalSubject<InternalGroupSubject, InternalGroup> assertThatGroup(
+ Optional<InternalGroup> group) {
+ return assertThat(group, InternalGroupSubject::assertThat).named("group");
+ }
+
+ private void assertMemberAuditEvent(
+ GroupAuditEventInfo info,
+ Type expectedType,
+ Account.Id expectedUser,
+ AccountInfo expectedMember) {
+ assertThat(info.user._accountId).isEqualTo(expectedUser.get());
+ assertThat(info.type).isEqualTo(expectedType);
+ assertThat(info).isInstanceOf(UserMemberAuditEventInfo.class);
+ assertAccount(((UserMemberAuditEventInfo) info).member, expectedMember);
+ }
+
+ private void assertMemberAuditEvents(
+ GroupAuditEventInfo info1,
+ GroupAuditEventInfo info2,
+ Type expectedType,
+ Account.Id expectedUser,
+ AccountInfo expectedMember1,
+ AccountInfo expectedMember2) {
+ assertThat(info1).isInstanceOf(UserMemberAuditEventInfo.class);
+ assertThat(info2).isInstanceOf(UserMemberAuditEventInfo.class);
+
+ UserMemberAuditEventInfo event1 = (UserMemberAuditEventInfo) info1;
+ UserMemberAuditEventInfo event2 = (UserMemberAuditEventInfo) info2;
+
+ assertThat(event1.member._accountId)
+ .isAnyOf(expectedMember1._accountId, expectedMember2._accountId);
+ assertThat(event2.member._accountId)
+ .isAnyOf(expectedMember1._accountId, expectedMember2._accountId);
+ assertThat(event1.member._accountId).isNotEqualTo(event2.member._accountId);
+
+ if (event1.member._accountId == expectedMember1._accountId) {
+ assertMemberAuditEvent(info1, expectedType, expectedUser, expectedMember1);
+ assertMemberAuditEvent(info2, expectedType, expectedUser, expectedMember2);
+ } else {
+ assertMemberAuditEvent(info1, expectedType, expectedUser, expectedMember2);
+ assertMemberAuditEvent(info2, expectedType, expectedUser, expectedMember1);
+ }
+ }
+
+ private void assertSubgroupAuditEvent(
+ GroupAuditEventInfo info,
+ Type expectedType,
+ Account.Id expectedUser,
+ GroupInfo expectedSubGroup) {
+ assertThat(info.user._accountId).isEqualTo(expectedUser.get());
+ assertThat(info.type).isEqualTo(expectedType);
+ assertThat(info).isInstanceOf(GroupMemberAuditEventInfo.class);
+ assertGroup(((GroupMemberAuditEventInfo) info).member, expectedSubGroup);
+ }
+
+ private void assertSubgroupAuditEvents(
+ GroupAuditEventInfo info1,
+ GroupAuditEventInfo info2,
+ Type expectedType,
+ Account.Id expectedUser,
+ GroupInfo expectedSubGroup1,
+ GroupInfo expectedSubGroup2) {
+ assertThat(info1).isInstanceOf(GroupMemberAuditEventInfo.class);
+ assertThat(info2).isInstanceOf(GroupMemberAuditEventInfo.class);
+
+ GroupMemberAuditEventInfo event1 = (GroupMemberAuditEventInfo) info1;
+ GroupMemberAuditEventInfo event2 = (GroupMemberAuditEventInfo) info2;
+
+ assertThat(event1.member.id).isAnyOf(expectedSubGroup1.id, expectedSubGroup2.id);
+ assertThat(event2.member.id).isAnyOf(expectedSubGroup1.id, expectedSubGroup2.id);
+ assertThat(event1.member.id).isNotEqualTo(event2.member.id);
+
+ if (event1.member.id.equals(expectedSubGroup1.id)) {
+ assertSubgroupAuditEvent(info1, expectedType, expectedUser, expectedSubGroup1);
+ assertSubgroupAuditEvent(info2, expectedType, expectedUser, expectedSubGroup2);
+ } else {
+ assertSubgroupAuditEvent(info1, expectedType, expectedUser, expectedSubGroup2);
+ assertSubgroupAuditEvent(info2, expectedType, expectedUser, expectedSubGroup1);
+ }
+ }
+
+ private void assertAccount(AccountInfo actual, AccountInfo expected) {
+ assertThat(actual._accountId).isEqualTo(expected._accountId);
+ assertThat(actual.name).isEqualTo(expected.name);
+ assertThat(actual.email).isEqualTo(expected.email);
+ assertThat(actual.username).isEqualTo(expected.username);
+ }
+
+ private void assertGroup(GroupInfo actual, GroupInfo expected) {
+ assertThat(actual.id).isEqualTo(expected.id);
+ assertThat(actual.name).isEqualTo(expected.name);
+ assertThat(actual.groupId).isEqualTo(expected.groupId);
+ }
+
+ private GroupInfo groupInfoForExternalGroup(AccountGroup.UUID groupUuid) {
+ GroupInfo groupInfo = new GroupInfo();
+ groupInfo.id = IdString.fromDecoded(groupUuid.get()).encoded();
+
+ if (groupBackend.handles(groupUuid)) {
+ groupInfo.name = groupBackend.get(groupUuid).getName();
+ }
+
+ return groupInfo;
+ }
+
+ private static AccountGroup toAccountGroup(GroupInfo info) {
+ AccountGroup group =
+ new AccountGroup(
+ new AccountGroup.NameKey(info.name),
+ new AccountGroup.Id(info.groupId),
+ new AccountGroup.UUID(info.id),
+ info.createdOn);
+ group.setDescription(info.description);
+ if (info.ownerId != null) {
+ group.setOwnerGroupUUID(new AccountGroup.UUID(info.ownerId));
+ }
+ group.setVisibleToAll(
+ info.options != null && info.options.visibleToAll != null && info.options.visibleToAll);
+ return group;
+ }
+
+ private static GroupInfo toGroupInfo(AccountGroup group) {
+ GroupInfo groupInfo = new GroupInfo();
+ groupInfo.id = group.getGroupUUID().get();
+ groupInfo.groupId = group.getId().get();
+ groupInfo.name = group.getName();
+ groupInfo.createdOn = group.getCreatedOn();
+ groupInfo.description = group.getDescription();
+ groupInfo.owner = group.getOwnerGroupUUID().get();
+ groupInfo.options = new GroupOptionsInfo();
+ groupInfo.options.visibleToAll = group.isVisibleToAll() ? true : null;
+ return groupInfo;
+ }
+}