blob: bf6953afcd0dc7f1c487362843a888316f0bd3f0 [file] [log] [blame]
// Copyright (C) 2017 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.common.truth.Truth.assert_;
import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.assertThat;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_GROUPNAMES;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.group.db.AuditLogFormatter;
import com.google.gerrit.server.group.db.AuditLogReader;
import com.google.gerrit.server.group.db.GroupNameNotes;
import com.google.gerrit.server.update.RefUpdateUtil;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.testing.GerritBaseTests;
import com.google.gerrit.testing.GitTestUtil;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import com.google.gerrit.testing.TestTimeUtil;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import java.sql.Timestamp;
import java.util.Optional;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class GroupRebuilderTest extends GerritBaseTests {
private static final TimeZone TZ = TimeZone.getTimeZone("America/Los_Angeles");
private static final String SERVER_ID = "server-id";
private static final String SERVER_NAME = "Gerrit Server";
private static final String SERVER_EMAIL = "noreply@gerritcodereview.com";
private AtomicInteger idCounter;
private AllUsersName allUsersName;
private Repository repo;
private GroupRebuilder rebuilder;
private GroupBundle.Factory bundleFactory;
@Before
public void setUp() throws Exception {
TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
idCounter = new AtomicInteger();
allUsersName = new AllUsersName(AllUsersNameProvider.DEFAULT);
repo = new InMemoryRepositoryManager().createRepository(allUsersName);
rebuilder =
new GroupRebuilder(
GroupRebuilderTest.newPersonIdent(),
allUsersName,
// Note that the expected name/email values in tests are not necessarily realistic,
// since they use these trivial name/email functions.
getAuditLogFormatter());
bundleFactory = new GroupBundle.Factory(new AuditLogReader(SERVER_ID, allUsersName));
}
@After
public void tearDown() {
TestTimeUtil.useSystemTime();
}
@Test
public void minimalGroupFields() throws Exception {
AccountGroup g = newGroup("a");
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(1);
assertCommit(log.get(0), "Create group", SERVER_NAME, SERVER_EMAIL);
assertThat(logGroupNames()).isEmpty();
}
@Test
public void allGroupFields() throws Exception {
AccountGroup g = newGroup("a");
g.setDescription("Description");
g.setOwnerGroupUUID(new AccountGroup.UUID("owner"));
g.setVisibleToAll(true);
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(1);
assertServerCommit(log.get(0), "Create group");
}
@Test
public void emptyGroupName() throws Exception {
AccountGroup g = newGroup("");
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
GroupBundle noteDbBundle = reload(g);
assertMigratedCleanly(noteDbBundle, b);
assertThat(noteDbBundle.group().getName()).isEmpty();
}
@Test
public void nullGroupDescription() throws Exception {
AccountGroup g = newGroup("a");
g.setDescription(null);
assertThat(g.getDescription()).isNull();
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
GroupBundle noteDbBundle = reload(g);
assertMigratedCleanly(noteDbBundle, b);
assertThat(noteDbBundle.group().getDescription()).isNull();
}
@Test
public void emptyGroupDescription() throws Exception {
AccountGroup g = newGroup("a");
g.setDescription("");
assertThat(g.getDescription()).isEmpty();
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
GroupBundle noteDbBundle = reload(g);
assertMigratedCleanly(noteDbBundle, b);
assertThat(noteDbBundle.group().getDescription()).isNull();
}
@Test
public void membersAndSubgroups() throws Exception {
AccountGroup g = newGroup("a");
GroupBundle b =
builder()
.group(g)
.members(member(g, 1), member(g, 2))
.byId(byId(g, "x"), byId(g, "y"))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(2);
assertServerCommit(log.get(0), "Create group");
assertServerCommit(
log.get(1),
"Update group\n"
+ "\n"
+ "Add-group: Group x <x>\n"
+ "Add-group: Group y <y>\n"
+ "Add: Account 1 <1@server-id>\n"
+ "Add: Account 2 <2@server-id>");
}
@Test
public void memberAudit() throws Exception {
AccountGroup g = newGroup("a");
Timestamp t1 = TimeUtil.nowTs();
Timestamp t2 = TimeUtil.nowTs();
Timestamp t3 = TimeUtil.nowTs();
GroupBundle b =
builder()
.group(g)
.members(member(g, 1))
.memberAudit(addMember(g, 1, 8, t2), addAndRemoveMember(g, 2, 8, t1, 9, t3))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(4);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1), "Update group\n\nAdd: Account 2 <2@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(2), "Update group\n\nAdd: Account 1 <1@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(3), "Update group\n\nRemove: Account 2 <2@server-id>", "Account 9", "9@server-id");
}
@Test
public void memberAuditLegacyRemoved() throws Exception {
AccountGroup g = newGroup("a");
GroupBundle b =
builder()
.group(g)
.members(member(g, 2))
.memberAudit(
addAndLegacyRemoveMember(g, 1, 8, TimeUtil.nowTs()),
addMember(g, 2, 8, TimeUtil.nowTs()))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(4);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1), "Update group\n\nAdd: Account 1 <1@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(2), "Update group\n\nRemove: Account 1 <1@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(3), "Update group\n\nAdd: Account 2 <2@server-id>", "Account 8", "8@server-id");
}
@Test
public void unauditedMembershipsAddedAtEnd() throws Exception {
AccountGroup g = newGroup("a");
GroupBundle b =
builder()
.group(g)
.members(member(g, 1), member(g, 2), member(g, 3))
.memberAudit(addMember(g, 1, 8, TimeUtil.nowTs()))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(3);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1), "Update group\n\nAdd: Account 1 <1@server-id>", "Account 8", "8@server-id");
assertServerCommit(
log.get(2), "Update group\n\nAdd: Account 2 <2@server-id>\nAdd: Account 3 <3@server-id>");
}
@Test
public void byIdAudit() throws Exception {
AccountGroup g = newGroup("a");
Timestamp t1 = TimeUtil.nowTs();
Timestamp t2 = TimeUtil.nowTs();
Timestamp t3 = TimeUtil.nowTs();
GroupBundle b =
builder()
.group(g)
.byId(byId(g, "x"))
.byIdAudit(addById(g, "x", 8, t2), addAndRemoveById(g, "y", 8, t1, 9, t3))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(4);
assertServerCommit(log.get(0), "Create group");
assertCommit(log.get(1), "Update group\n\nAdd-group: Group y <y>", "Account 8", "8@server-id");
assertCommit(log.get(2), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
assertCommit(
log.get(3), "Update group\n\nRemove-group: Group y <y>", "Account 9", "9@server-id");
}
@Test
public void unauditedByIdAddedAtEnd() throws Exception {
AccountGroup g = newGroup("a");
GroupBundle b =
builder()
.group(g)
.byId(byId(g, "x"), byId(g, "y"), byId(g, "z"))
.byIdAudit(addById(g, "x", 8, TimeUtil.nowTs()))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(3);
assertServerCommit(log.get(0), "Create group");
assertCommit(log.get(1), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
assertServerCommit(
log.get(2), "Update group\n\nAdd-group: Group y <y>\nAdd-group: Group z <z>");
}
@Test
public void auditsAtSameTimestampBrokenDownByType() throws Exception {
AccountGroup g = newGroup("a");
Timestamp ts = TimeUtil.nowTs();
int user = 8;
GroupBundle b =
builder()
.group(g)
.members(member(g, 1), member(g, 2))
.memberAudit(
addMember(g, 1, user, ts),
addMember(g, 2, user, ts),
addAndRemoveMember(g, 3, user, ts, user, ts))
.byId(byId(g, "x"), byId(g, "y"))
.byIdAudit(
addById(g, "x", user, ts),
addById(g, "y", user, ts),
addAndRemoveById(g, "z", user, ts, user, ts))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(5);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1),
"Update group\n"
+ "\n"
+ "Add: Account 1 <1@server-id>\n"
+ "Add: Account 2 <2@server-id>\n"
+ "Add: Account 3 <3@server-id>",
"Account 8",
"8@server-id");
assertCommit(
log.get(2), "Update group\n\nRemove: Account 3 <3@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(3),
"Update group\n"
+ "\n"
+ "Add-group: Group x <x>\n"
+ "Add-group: Group y <y>\n"
+ "Add-group: Group z <z>",
"Account 8",
"8@server-id");
assertCommit(
log.get(4), "Update group\n\nRemove-group: Group z <z>", "Account 8", "8@server-id");
}
@Test
public void auditsAtSameTimestampBrokenDownByUserAndType() throws Exception {
AccountGroup g = newGroup("a");
Timestamp ts = TimeUtil.nowTs();
int user1 = 8;
int user2 = 9;
GroupBundle b =
builder()
.group(g)
.members(member(g, 1), member(g, 2), member(g, 3))
.memberAudit(
addMember(g, 1, user1, ts), addMember(g, 2, user2, ts), addMember(g, 3, user1, ts))
.byId(byId(g, "x"), byId(g, "y"), byId(g, "z"))
.byIdAudit(
addById(g, "x", user1, ts), addById(g, "y", user2, ts), addById(g, "z", user1, ts))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(5);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1),
"Update group\n" + "\n" + "Add: Account 1 <1@server-id>\n" + "Add: Account 3 <3@server-id>",
"Account 8",
"8@server-id");
assertCommit(
log.get(2),
"Update group\n\nAdd-group: Group x <x>\nAdd-group: Group z <z>",
"Account 8",
"8@server-id");
assertCommit(
log.get(3), "Update group\n\nAdd: Account 2 <2@server-id>", "Account 9", "9@server-id");
assertCommit(log.get(4), "Update group\n\nAdd-group: Group y <y>", "Account 9", "9@server-id");
}
@Test
public void fixupCommitPostDatesAllAuditEventsEvenIfAuditEventsAreInTheFuture() throws Exception {
AccountGroup g = newGroup("a");
IntStream.range(0, 20).forEach(i -> TimeUtil.nowTs());
Timestamp future = TimeUtil.nowTs();
TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
GroupBundle b =
builder()
.group(g)
.byId(byId(g, "x"), byId(g, "y"), byId(g, "z"))
.byIdAudit(addById(g, "x", 8, future))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(3);
assertServerCommit(log.get(0), "Create group");
assertCommit(log.get(1), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
assertServerCommit(
log.get(2), "Update group\n\nAdd-group: Group y <y>\nAdd-group: Group z <z>");
assertThat(log.stream().map(c -> c.committer.date).collect(toImmutableList()))
.named("%s", log)
.isOrdered();
assertThat(TimeUtil.nowTs()).isLessThan(future);
}
@Test
public void redundantMemberAuditsAreIgnored() throws Exception {
AccountGroup g = newGroup("a");
Timestamp t1 = TimeUtil.nowTs();
Timestamp t2 = TimeUtil.nowTs();
Timestamp t3 = TimeUtil.nowTs();
Timestamp t4 = TimeUtil.nowTs();
Timestamp t5 = TimeUtil.nowTs();
GroupBundle b =
builder()
.group(g)
.members(member(g, 2))
.memberAudit(
addMember(g, 1, 8, t1),
addMember(g, 1, 8, t1),
addMember(g, 1, 8, t3),
addMember(g, 1, 9, t4),
addAndRemoveMember(g, 1, 8, t2, 9, t5),
addAndLegacyRemoveMember(g, 2, 9, t3),
addMember(g, 2, 8, t1),
addMember(g, 2, 9, t4),
addMember(g, 1, 8, t5))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(5);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1),
"Update group\n\nAdd: Account 1 <1@server-id>\nAdd: Account 2 <2@server-id>",
"Account 8",
"8@server-id");
assertCommit(
log.get(2), "Update group\n\nRemove: Account 2 <2@server-id>", "Account 9", "9@server-id");
assertCommit(
log.get(3), "Update group\n\nAdd: Account 2 <2@server-id>", "Account 9", "9@server-id");
assertCommit(
log.get(4), "Update group\n\nRemove: Account 1 <1@server-id>", "Account 9", "9@server-id");
}
@Test
public void additionsAndRemovalsWithinSameSecondCanBeMigrated() throws Exception {
TestTimeUtil.resetWithClockStep(1, TimeUnit.MILLISECONDS);
AccountGroup g = newGroup("a");
Timestamp t1 = TimeUtil.nowTs();
Timestamp t2 = TimeUtil.nowTs();
Timestamp t3 = TimeUtil.nowTs();
Timestamp t4 = TimeUtil.nowTs();
Timestamp t5 = TimeUtil.nowTs();
GroupBundle b =
builder()
.group(g)
.members(member(g, 1))
.memberAudit(
addAndLegacyRemoveMember(g, 1, 8, t1),
addMember(g, 1, 10, t2),
addAndRemoveMember(g, 1, 8, t3, 9, t4),
addMember(g, 1, 8, t5))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(6);
assertServerCommit(log.get(0), "Create group");
assertCommit(
log.get(1), "Update group\n\nAdd: Account 1 <1@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(2), "Update group\n\nRemove: Account 1 <1@server-id>", "Account 8", "8@server-id");
assertCommit(
log.get(3), "Update group\n\nAdd: Account 1 <1@server-id>", "Account 10", "10@server-id");
assertCommit(
log.get(4), "Update group\n\nRemove: Account 1 <1@server-id>", "Account 9", "9@server-id");
assertCommit(
log.get(5), "Update group\n\nAdd: Account 1 <1@server-id>", "Account 8", "8@server-id");
}
@Test
public void redundantByIdAuditsAreIgnored() throws Exception {
AccountGroup g = newGroup("a");
Timestamp t1 = TimeUtil.nowTs();
Timestamp t2 = TimeUtil.nowTs();
Timestamp t3 = TimeUtil.nowTs();
Timestamp t4 = TimeUtil.nowTs();
Timestamp t5 = TimeUtil.nowTs();
GroupBundle b =
builder()
.group(g)
.byId()
.byIdAudit(
addById(g, "x", 8, t1),
addById(g, "x", 8, t3),
addById(g, "x", 9, t4),
addAndRemoveById(g, "x", 8, t2, 9, t5))
.build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
ImmutableList<CommitInfo> log = log(g);
assertThat(log).hasSize(3);
assertServerCommit(log.get(0), "Create group");
assertCommit(log.get(1), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
assertCommit(
log.get(2), "Update group\n\nRemove-group: Group x <x>", "Account 9", "9@server-id");
}
@Test
public void combineWithBatchGroupNameNotes() throws Exception {
AccountGroup g1 = newGroup("a");
AccountGroup g2 = newGroup("b");
GroupReference gr1 = new GroupReference(g1.getGroupUUID(), g1.getName());
GroupReference gr2 = new GroupReference(g2.getGroupUUID(), g2.getName());
GroupBundle b1 = builder().group(g1).build();
GroupBundle b2 = builder().group(g2).build();
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
rebuilder.rebuild(repo, b1, bru);
rebuilder.rebuild(repo, b2, bru);
try (ObjectInserter inserter = repo.newObjectInserter()) {
ImmutableList<GroupReference> refs = ImmutableList.of(gr1, gr2);
GroupNameNotes.updateAllGroups(repo, inserter, bru, refs, newPersonIdent());
inserter.flush();
}
assertThat(log(g1)).isEmpty();
assertThat(log(g2)).isEmpty();
assertThat(logGroupNames()).isEmpty();
RefUpdateUtil.executeChecked(bru, repo);
assertThat(log(g1)).hasSize(1);
assertThat(log(g2)).hasSize(1);
assertThat(logGroupNames()).hasSize(1);
assertMigratedCleanly(reload(g1), b1);
assertMigratedCleanly(reload(g2), b2);
assertThat(GroupNameNotes.loadAllGroups(repo)).containsExactly(gr1, gr2);
}
@Test
public void groupNamesWithLeadingAndTrailingWhitespace() throws Exception {
for (String leading : ImmutableList.of("", " ", " ")) {
for (String trailing : ImmutableList.of("", " ", " ")) {
AccountGroup g = newGroup(leading + "a" + trailing);
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
}
}
}
@Test
public void disallowExisting() throws Exception {
AccountGroup g = newGroup("a");
GroupBundle b = builder().group(g).build();
rebuilder.rebuild(repo, b, null);
assertMigratedCleanly(reload(g), b);
String refName = RefNames.refsGroups(g.getGroupUUID());
ObjectId oldId = repo.exactRef(refName).getObjectId();
try {
rebuilder.rebuild(repo, b, null);
assert_().fail("expected OrmDuplicateKeyException");
} catch (OrmDuplicateKeyException e) {
// Expected.
}
assertThat(repo.exactRef(refName).getObjectId()).isEqualTo(oldId);
}
private GroupBundle reload(AccountGroup g) throws Exception {
return bundleFactory.fromNoteDb(allUsersName, repo, g.getGroupUUID());
}
private void assertMigratedCleanly(GroupBundle noteDbBundle, GroupBundle expectedReviewDbBundle) {
assertThat(GroupBundle.compareWithAudits(expectedReviewDbBundle, noteDbBundle)).isEmpty();
}
private AccountGroup newGroup(String name) {
int id = idCounter.incrementAndGet();
return new AccountGroup(
new AccountGroup.NameKey(name),
new AccountGroup.Id(id),
new AccountGroup.UUID(name.trim() + "-" + id),
TimeUtil.nowTs());
}
private AccountGroupMember member(AccountGroup g, int accountId) {
return new AccountGroupMember(new AccountGroupMember.Key(new Account.Id(accountId), g.getId()));
}
private AccountGroupMemberAudit addMember(
AccountGroup g, int accountId, int adder, Timestamp addedOn) {
return new AccountGroupMemberAudit(member(g, accountId), new Account.Id(adder), addedOn);
}
private AccountGroupMemberAudit addAndLegacyRemoveMember(
AccountGroup g, int accountId, int adder, Timestamp addedOn) {
AccountGroupMemberAudit a = addMember(g, accountId, adder, addedOn);
a.removedLegacy();
return a;
}
private AccountGroupMemberAudit addAndRemoveMember(
AccountGroup g,
int accountId,
int adder,
Timestamp addedOn,
int removedBy,
Timestamp removedOn) {
AccountGroupMemberAudit a = addMember(g, accountId, adder, addedOn);
a.removed(new Account.Id(removedBy), removedOn);
return a;
}
private AccountGroupByIdAud addById(
AccountGroup g, String subgroupUuid, int adder, Timestamp addedOn) {
return new AccountGroupByIdAud(byId(g, subgroupUuid), new Account.Id(adder), addedOn);
}
private AccountGroupByIdAud addAndRemoveById(
AccountGroup g,
String subgroupUuid,
int adder,
Timestamp addedOn,
int removedBy,
Timestamp removedOn) {
AccountGroupByIdAud a = addById(g, subgroupUuid, adder, addedOn);
a.removed(new Account.Id(removedBy), removedOn);
return a;
}
private AccountGroupById byId(AccountGroup g, String subgroupUuid) {
return new AccountGroupById(
new AccountGroupById.Key(g.getId(), new AccountGroup.UUID(subgroupUuid)));
}
private ImmutableList<CommitInfo> log(AccountGroup g) throws Exception {
return GitTestUtil.log(repo, RefNames.refsGroups(g.getGroupUUID()));
}
private ImmutableList<CommitInfo> logGroupNames() throws Exception {
return GitTestUtil.log(repo, REFS_GROUPNAMES);
}
private static GroupBundle.Builder builder() {
return GroupBundle.builder().source(GroupBundle.Source.REVIEW_DB);
}
private static PersonIdent newPersonIdent() {
return new PersonIdent(SERVER_NAME, SERVER_EMAIL, TimeUtil.nowTs(), TZ);
}
private static void assertServerCommit(CommitInfo commitInfo, String expectedMessage) {
assertCommit(commitInfo, expectedMessage, SERVER_NAME, SERVER_EMAIL);
}
private static void assertCommit(
CommitInfo commitInfo, String expectedMessage, String expectedName, String expectedEmail) {
assertThat(commitInfo).message().isEqualTo(expectedMessage);
assertThat(commitInfo).author().name().isEqualTo(expectedName);
assertThat(commitInfo).author().email().isEqualTo(expectedEmail);
// Committer should always be the server, regardless of author.
assertThat(commitInfo).committer().name().isEqualTo(SERVER_NAME);
assertThat(commitInfo).committer().email().isEqualTo(SERVER_EMAIL);
assertThat(commitInfo).committer().date().isEqualTo(commitInfo.author.date);
assertThat(commitInfo).committer().tz().isEqualTo(commitInfo.author.tz);
}
private static AuditLogFormatter getAuditLogFormatter() {
return AuditLogFormatter.create(
GroupRebuilderTest::getAccount, GroupRebuilderTest::getGroup, SERVER_ID);
}
private static Optional<Account> getAccount(Account.Id id) {
Account account = new Account(id, TimeUtil.nowTs());
account.setFullName("Account " + id);
return Optional.of(account);
}
private static Optional<GroupDescription.Basic> getGroup(AccountGroup.UUID uuid) {
GroupDescription.Basic group =
new GroupDescription.Basic() {
@Override
public AccountGroup.UUID getGroupUUID() {
return uuid;
}
@Override
public String getName() {
return "Group " + uuid;
}
@Nullable
@Override
public String getEmailAddress() {
return null;
}
@Nullable
@Override
public String getUrl() {
return null;
}
};
return Optional.of(group);
}
}