Merge "Remove project state check from ChangeControl#addPatchSet"
diff --git a/java/com/google/gerrit/common/data/testing/BUILD b/java/com/google/gerrit/common/data/testing/BUILD
new file mode 100644
index 0000000..83f1c06
--- /dev/null
+++ b/java/com/google/gerrit/common/data/testing/BUILD
@@ -0,0 +1,11 @@
+java_library(
+ name = "common-data-test-util",
+ testonly = 1,
+ srcs = glob(["**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//java/com/google/gerrit/common:server",
+ "//java/com/google/gerrit/reviewdb:server",
+ "//lib:truth",
+ ],
+)
diff --git a/java/com/google/gerrit/common/data/testing/GroupReferenceSubject.java b/java/com/google/gerrit/common/data/testing/GroupReferenceSubject.java
new file mode 100644
index 0000000..1988d66
--- /dev/null
+++ b/java/com/google/gerrit/common/data/testing/GroupReferenceSubject.java
@@ -0,0 +1,48 @@
+// 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.common.data.testing;
+
+import static com.google.common.truth.Truth.assertAbout;
+
+import com.google.common.truth.ComparableSubject;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.StringSubject;
+import com.google.common.truth.Subject;
+import com.google.common.truth.Truth;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+
+public class GroupReferenceSubject extends Subject<GroupReferenceSubject, GroupReference> {
+
+ public static GroupReferenceSubject assertThat(GroupReference group) {
+ return assertAbout(GroupReferenceSubject::new).that(group);
+ }
+
+ private GroupReferenceSubject(FailureMetadata metadata, GroupReference group) {
+ super(metadata, group);
+ }
+
+ public ComparableSubject<?, AccountGroup.UUID> groupUuid() {
+ isNotNull();
+ GroupReference group = actual();
+ return Truth.assertThat(group.getUUID()).named("groupUuid");
+ }
+
+ public StringSubject name() {
+ isNotNull();
+ GroupReference group = actual();
+ return Truth.assertThat(group.getName()).named("name");
+ }
+}
diff --git a/java/com/google/gerrit/pgm/init/GroupsOnInit.java b/java/com/google/gerrit/pgm/init/GroupsOnInit.java
index 3385244..7fe227d 100644
--- a/java/com/google/gerrit/pgm/init/GroupsOnInit.java
+++ b/java/com/google/gerrit/pgm/init/GroupsOnInit.java
@@ -150,7 +150,7 @@
File allUsersRepoPath = getPathToAllUsersRepository();
if (allUsersRepoPath != null) {
try (Repository allUsersRepo = new FileRepository(allUsersRepoPath)) {
- return GroupNameNotes.loadAllGroupReferences(allUsersRepo).stream();
+ return GroupNameNotes.loadAllGroups(allUsersRepo).stream();
}
}
return Stream.empty();
diff --git a/java/com/google/gerrit/server/change/ChangeInserter.java b/java/com/google/gerrit/server/change/ChangeInserter.java
index 8ed1ef0..5e60906 100644
--- a/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -569,7 +569,8 @@
new Branch.NameKey(ctx.getProject(), refName),
ctx.getIdentifiedUser(),
new NoSshInfo(),
- ctx.getRevWalk())
+ ctx.getRevWalk(),
+ change)
.validate(event);
}
} catch (CommitValidationException e) {
diff --git a/java/com/google/gerrit/server/change/PatchSetInserter.java b/java/com/google/gerrit/server/change/PatchSetInserter.java
index 3cf0dc5..3a32f8f 100644
--- a/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -345,7 +345,8 @@
origNotes.getChange().getDest(),
ctx.getIdentifiedUser(),
new NoSshInfo(),
- ctx.getRevWalk())
+ ctx.getRevWalk(),
+ origNotes.getChange())
.validate(event);
} catch (CommitValidationException e) {
throw new ResourceConflictException(e.getFullMessage());
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 10b761f..292fa7a 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1856,7 +1856,8 @@
logDebug("Creating new change for {} even though it is already tracked", name);
}
- if (!validCommit(rp.getRevWalk(), magicBranch.perm, magicBranch.dest, magicBranch.cmd, c)) {
+ if (!validCommit(
+ rp.getRevWalk(), magicBranch.perm, magicBranch.dest, magicBranch.cmd, c, null)) {
// Not a change the user can propose? Abort as early as possible.
newChanges = Collections.emptyList();
logDebug("Aborting early due to invalid commit");
@@ -2434,7 +2435,7 @@
}
PermissionBackend.ForRef perm = permissions.ref(change.getDest().get());
- if (!validCommit(rp.getRevWalk(), perm, change.getDest(), inputCommand, newCommit)) {
+ if (!validCommit(rp.getRevWalk(), perm, change.getDest(), inputCommand, newCommit, change)) {
return false;
}
rp.getRevWalk().parseBody(priorCommit);
@@ -2798,7 +2799,7 @@
}
if (existing.keySet().contains(c)) {
continue;
- } else if (!validCommit(walk, perm, branch, cmd, c)) {
+ } else if (!validCommit(walk, perm, branch, cmd, c, null)) {
break;
}
@@ -2820,7 +2821,8 @@
PermissionBackend.ForRef perm,
Branch.NameKey branch,
ReceiveCommand cmd,
- ObjectId id)
+ ObjectId id,
+ @Nullable Change change)
throws IOException {
if (validCommits.contains(id)) {
@@ -2841,7 +2843,7 @@
? commitValidatorsFactory.forMergedCommits(
project.getNameKey(), perm, user.asIdentifiedUser())
: commitValidatorsFactory.forReceiveCommits(
- perm, branch, user.asIdentifiedUser(), sshInfo, repo, rw);
+ perm, branch, user.asIdentifiedUser(), sshInfo, repo, rw, change);
messages.addAll(validators.validate(receiveEvent));
} catch (CommitValidationException e) {
logDebug("Commit validation failed on {}", c.name());
diff --git a/java/com/google/gerrit/server/git/validators/CommitValidators.java b/java/com/google/gerrit/server/git/validators/CommitValidators.java
index a80ff73..05ca98b 100644
--- a/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -19,6 +19,7 @@
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
import static java.util.stream.Collectors.toList;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.FooterConstants;
@@ -30,6 +31,8 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Branch.NameKey;
+import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.client.RevId;
@@ -46,6 +49,7 @@
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackend.ForRef;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.RefPermission;
import com.google.gerrit.server.project.ProjectCache;
@@ -125,7 +129,8 @@
IdentifiedUser user,
SshInfo sshInfo,
Repository repo,
- RevWalk rw)
+ RevWalk rw,
+ @Nullable Change change)
throws IOException {
NoteMap rejectCommits = BanCommit.loadRejectCommitsMap(repo, rw);
ProjectState projectState = projectCache.checkedGet(branch.getParentKey());
@@ -138,7 +143,12 @@
new CommitterUploaderValidator(user, perm, canonicalWebUrl),
new SignedOffByValidator(user, perm, projectState),
new ChangeIdValidator(
- projectState, user, canonicalWebUrl, installCommitMsgHookCommand, sshInfo),
+ projectState,
+ user,
+ canonicalWebUrl,
+ installCommitMsgHookCommand,
+ sshInfo,
+ change),
new ConfigValidator(branch, user, rw, allUsers, allProjects),
new BannedCommitsValidator(rejectCommits),
new PluginCommitValidationListener(pluginValidators),
@@ -148,11 +158,12 @@
}
public CommitValidators forGerritCommits(
- PermissionBackend.ForRef perm,
- Branch.NameKey branch,
+ ForRef perm,
+ NameKey branch,
IdentifiedUser user,
SshInfo sshInfo,
- RevWalk rw)
+ RevWalk rw,
+ @Nullable Change change)
throws IOException {
ProjectState projectState = projectCache.checkedGet(branch.getParentKey());
return new CommitValidators(
@@ -163,7 +174,12 @@
new AuthorUploaderValidator(user, perm, canonicalWebUrl),
new SignedOffByValidator(user, perm, projectCache.checkedGet(branch.getParentKey())),
new ChangeIdValidator(
- projectState, user, canonicalWebUrl, installCommitMsgHookCommand, sshInfo),
+ projectState,
+ user,
+ canonicalWebUrl,
+ installCommitMsgHookCommand,
+ sshInfo,
+ change),
new ConfigValidator(branch, user, rw, allUsers, allProjects),
new PluginCommitValidationListener(pluginValidators),
new ExternalIdUpdateListener(allUsers, externalIdsConsistencyChecker),
@@ -231,6 +247,15 @@
"[%s] invalid "
+ FooterConstants.CHANGE_ID.getName()
+ " line format in commit message footer";
+
+ @VisibleForTesting
+ public static final String CHANGE_ID_MISMATCH_MSG =
+ "[%s] "
+ + FooterConstants.CHANGE_ID.getName()
+ + " in commit message footer does not match"
+ + FooterConstants.CHANGE_ID.getName()
+ + " of target change";
+
private static final Pattern CHANGE_ID = Pattern.compile(CHANGE_ID_PATTERN);
private final ProjectState projectState;
@@ -238,18 +263,21 @@
private final String installCommitMsgHookCommand;
private final SshInfo sshInfo;
private final IdentifiedUser user;
+ private final Change change;
public ChangeIdValidator(
ProjectState projectState,
IdentifiedUser user,
String canonicalWebUrl,
String installCommitMsgHookCommand,
- SshInfo sshInfo) {
+ SshInfo sshInfo,
+ Change change) {
this.projectState = projectState;
this.canonicalWebUrl = canonicalWebUrl;
this.installCommitMsgHookCommand = installCommitMsgHookCommand;
this.sshInfo = sshInfo;
this.user = user;
+ this.change = change;
}
@Override
@@ -289,7 +317,12 @@
messages.add(getMissingChangeIdErrorMsg(errMsg, receiveEvent.commit));
throw new CommitValidationException(errMsg, messages);
}
+ if (change != null && !v.equals(change.getKey().get())) {
+ String errMsg = String.format(CHANGE_ID_MISMATCH_MSG, sha1);
+ throw new CommitValidationException(errMsg);
+ }
}
+
return Collections.emptyList();
}
diff --git a/java/com/google/gerrit/server/group/db/GroupNameNotes.java b/java/com/google/gerrit/server/group/db/GroupNameNotes.java
index 775ebd6..87aee8e 100644
--- a/java/com/google/gerrit/server/group/db/GroupNameNotes.java
+++ b/java/com/google/gerrit/server/group/db/GroupNameNotes.java
@@ -21,8 +21,10 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
+import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multiset;
import com.google.common.hash.Hashing;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GroupReference;
@@ -32,11 +34,9 @@
import com.google.gwtorm.server.OrmDuplicateKeyException;
import java.io.IOException;
import java.util.Collection;
-import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.CommitBuilder;
@@ -68,7 +68,7 @@
@VisibleForTesting
static final String UNIQUE_REF_ERROR = "GroupReference collection must contain unique references";
- public static GroupNameNotes loadForRename(
+ public static GroupNameNotes forRename(
Repository repository,
AccountGroup.UUID groupUuid,
AccountGroup.NameKey oldName,
@@ -83,7 +83,7 @@
return groupNameNotes;
}
- public static GroupNameNotes loadForNewGroup(
+ public static GroupNameNotes forNewGroup(
Repository repository, AccountGroup.UUID groupUuid, AccountGroup.NameKey groupName)
throws IOException, ConfigInvalidException, OrmDuplicateKeyException {
checkNotNull(groupName);
@@ -94,18 +94,19 @@
return groupNameNotes;
}
- public static Optional<GroupReference> loadOneGroupReference(
- Repository allUsersRepo, String groupName) throws IOException, ConfigInvalidException {
- Ref ref = allUsersRepo.exactRef(RefNames.REFS_GROUPNAMES);
+ public static Optional<GroupReference> loadGroup(
+ Repository repository, AccountGroup.NameKey groupName)
+ throws IOException, ConfigInvalidException {
+ Ref ref = repository.exactRef(RefNames.REFS_GROUPNAMES);
if (ref == null) {
return Optional.empty();
}
- try (RevWalk revWalk = new RevWalk(allUsersRepo);
+ try (RevWalk revWalk = new RevWalk(repository);
ObjectReader reader = revWalk.getObjectReader()) {
RevCommit notesCommit = revWalk.parseCommit(ref.getObjectId());
NoteMap noteMap = NoteMap.read(reader, notesCommit);
- ObjectId noteDataBlobId = noteMap.get(getNoteKey(new AccountGroup.NameKey(groupName)));
+ ObjectId noteDataBlobId = noteMap.get(getNoteKey(groupName));
if (noteDataBlobId == null) {
return Optional.empty();
}
@@ -113,34 +114,34 @@
}
}
- public static ImmutableSet<GroupReference> loadAllGroupReferences(Repository repository)
+ public static ImmutableList<GroupReference> loadAllGroups(Repository repository)
throws IOException, ConfigInvalidException {
Ref ref = repository.exactRef(RefNames.REFS_GROUPNAMES);
if (ref == null) {
- return ImmutableSet.of();
+ return ImmutableList.of();
}
try (RevWalk revWalk = new RevWalk(repository);
ObjectReader reader = revWalk.getObjectReader()) {
RevCommit notesCommit = revWalk.parseCommit(ref.getObjectId());
NoteMap noteMap = NoteMap.read(reader, notesCommit);
- Set<GroupReference> groupReferences = new LinkedHashSet<>();
+ Multiset<GroupReference> groupReferences = HashMultiset.create();
for (Note note : noteMap) {
GroupReference groupReference = getGroupReference(reader, note.getData());
- boolean result = groupReferences.add(groupReference);
- if (!result) {
+ int numOfOccurrences = groupReferences.add(groupReference, 1);
+ if (numOfOccurrences > 1) {
GroupsNoteDbConsistencyChecker.logConsistencyProblemAsWarning(
"The UUID of group %s (%s) is duplicate in group name notes",
groupReference.getName(), groupReference.getUUID());
}
}
- return ImmutableSet.copyOf(groupReferences);
+ return ImmutableList.copyOf(groupReferences);
}
}
- public static void updateGroupNames(
- Repository allUsersRepo,
+ public static void updateAllGroups(
+ Repository repository,
ObjectInserter inserter,
BatchRefUpdate bru,
Collection<GroupReference> groupReferences,
@@ -153,7 +154,7 @@
RevWalk rw = new RevWalk(reader)) {
// Always start from an empty map, discarding old notes.
NoteMap noteMap = NoteMap.newEmptyMap();
- Ref ref = allUsersRepo.exactRef(RefNames.REFS_GROUPNAMES);
+ Ref ref = repository.exactRef(RefNames.REFS_GROUPNAMES);
RevCommit oldCommit = ref != null ? rw.parseCommit(ref.getObjectId()) : null;
for (Map.Entry<AccountGroup.UUID, String> e : biMap.entrySet()) {
@@ -195,8 +196,8 @@
}
private final AccountGroup.UUID groupUuid;
- private final Optional<AccountGroup.NameKey> oldGroupName;
- private final Optional<AccountGroup.NameKey> newGroupName;
+ private Optional<AccountGroup.NameKey> oldGroupName;
+ private Optional<AccountGroup.NameKey> newGroupName;
private boolean nameConflicting;
@@ -278,6 +279,9 @@
commit.setTreeId(noteMap.writeTree(inserter));
commit.setMessage(getCommitMessage());
+ oldGroupName = Optional.empty();
+ newGroupName = Optional.empty();
+
return true;
}
@@ -311,8 +315,7 @@
return config.toText();
}
- @VisibleForTesting
- public static GroupReference getGroupReference(ObjectReader reader, ObjectId noteDataBlobId)
+ private static GroupReference getGroupReference(ObjectReader reader, ObjectId noteDataBlobId)
throws IOException, ConfigInvalidException {
byte[] noteData = reader.open(noteDataBlobId, OBJ_BLOB).getCachedBytes();
return getFromNoteData(noteData);
diff --git a/java/com/google/gerrit/server/group/db/Groups.java b/java/com/google/gerrit/server/group/db/Groups.java
index f3232be..d0ea9ca 100644
--- a/java/com/google/gerrit/server/group/db/Groups.java
+++ b/java/com/google/gerrit/server/group/db/Groups.java
@@ -192,7 +192,7 @@
throws OrmException, IOException, ConfigInvalidException {
if (groupsMigration.readFromNoteDb()) {
try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
- return GroupNameNotes.loadAllGroupReferences(allUsersRepo).stream();
+ return GroupNameNotes.loadAllGroups(allUsersRepo).stream();
}
}
@@ -298,10 +298,9 @@
.filter(groupUuid -> !AccountGroup.isInternalGroup(groupUuid));
}
- private Stream<AccountGroup.UUID> getExternalGroupsFromNoteDb(Repository allUsersRepo)
+ private static Stream<AccountGroup.UUID> getExternalGroupsFromNoteDb(Repository allUsersRepo)
throws IOException, ConfigInvalidException {
- ImmutableSet<GroupReference> allInternalGroups =
- GroupNameNotes.loadAllGroupReferences(allUsersRepo);
+ ImmutableList<GroupReference> allInternalGroups = GroupNameNotes.loadAllGroups(allUsersRepo);
ImmutableSet.Builder<AccountGroup.UUID> allSubgroups = ImmutableSet.builder();
for (GroupReference internalGroup : allInternalGroups) {
Optional<InternalGroup> group = getGroupFromNoteDb(allUsersRepo, internalGroup.getUUID());
diff --git a/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java b/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
index 65ac12b..9f0cb3a 100644
--- a/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
+++ b/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
@@ -218,7 +218,7 @@
Repository allUsersRepo, InternalGroup group) throws IOException {
List<ConsistencyCheckInfo.ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, group.getName(), group.getGroupUUID());
+ allUsersRepo, group.getNameKey(), group.getGroupUUID());
problems.forEach(GroupsNoteDbConsistencyChecker::logConsistencyProblem);
}
@@ -232,10 +232,10 @@
*/
@VisibleForTesting
static List<ConsistencyProblemInfo> checkWithGroupNameNotes(
- Repository allUsersRepo, String groupName, AccountGroup.UUID groupUUID) throws IOException {
+ Repository allUsersRepo, AccountGroup.NameKey groupName, AccountGroup.UUID groupUUID)
+ throws IOException {
try {
- Optional<GroupReference> groupRef =
- GroupNameNotes.loadOneGroupReference(allUsersRepo, groupName);
+ Optional<GroupReference> groupRef = GroupNameNotes.loadGroup(allUsersRepo, groupName);
if (!groupRef.isPresent()) {
return ImmutableList.of(
@@ -243,7 +243,6 @@
}
AccountGroup.UUID uuid = groupRef.get().getUUID();
- String name = groupRef.get().getName();
List<ConsistencyProblemInfo> problems = new ArrayList<>();
if (!Objects.equals(groupUUID, uuid)) {
@@ -253,9 +252,11 @@
groupName, groupUUID, uuid));
}
- if (!Objects.equals(groupName, name)) {
+ String name = groupName.get();
+ String actualName = groupRef.get().getName();
+ if (!Objects.equals(name, actualName)) {
problems.add(
- warning("group note of name '%s' claims to represent name of '%s'", groupName, name));
+ warning("group note of name '%s' claims to represent name of '%s'", name, actualName));
}
return problems;
} catch (ConfigInvalidException e) {
diff --git a/java/com/google/gerrit/server/group/db/GroupsUpdate.java b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
index d93c8bd..fd5c453 100644
--- a/java/com/google/gerrit/server/group/db/GroupsUpdate.java
+++ b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
@@ -482,7 +482,7 @@
try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
AccountGroup.NameKey groupName = groupUpdate.getName().orElseGet(groupCreation::getNameKey);
GroupNameNotes groupNameNotes =
- GroupNameNotes.loadForNewGroup(allUsersRepo, groupCreation.getGroupUUID(), groupName);
+ GroupNameNotes.forNewGroup(allUsersRepo, groupCreation.getGroupUUID(), groupName);
GroupConfig groupConfig = GroupConfig.createForNewGroup(allUsersRepo, groupCreation);
groupConfig.setGroupUpdate(groupUpdate, this::getAccountNameEmail, this::getGroupName);
@@ -515,7 +515,7 @@
if (groupUpdate.getName().isPresent()) {
AccountGroup.NameKey oldName = originalGroup.getNameKey();
AccountGroup.NameKey newName = groupUpdate.getName().get();
- groupNameNotes = GroupNameNotes.loadForRename(allUsersRepo, groupUuid, oldName, newName);
+ groupNameNotes = GroupNameNotes.forRename(allUsersRepo, groupUuid, oldName, newName);
}
commit(allUsersRepo, groupConfig, groupNameNotes);
diff --git a/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java b/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java
index 46fd666..9197a01 100644
--- a/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java
+++ b/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java
@@ -15,14 +15,10 @@
package com.google.gerrit.server.group.db.testing;
import static com.google.common.collect.ImmutableList.toImmutableList;
-import static com.google.gerrit.server.group.db.GroupNameNotes.getGroupReference;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;
-import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.extensions.common.CommitInfo;
-import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.CommitUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -31,29 +27,12 @@
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.notes.Note;
-import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevWalk;
/** Test utilities for low-level NoteDb groups. */
public class GroupTestUtil {
- public static ImmutableMap<String, String> readNameToUuidMap(Repository repo) throws Exception {
- ImmutableMap.Builder<String, String> result = ImmutableMap.builder();
- try (RevWalk rw = new RevWalk(repo)) {
- Ref ref = repo.exactRef(RefNames.REFS_GROUPNAMES);
- if (ref != null) {
- NoteMap noteMap = NoteMap.read(rw.getObjectReader(), rw.parseCommit(ref.getObjectId()));
- for (Note note : noteMap) {
- GroupReference gr = getGroupReference(rw.getObjectReader(), note.getData());
- result.put(gr.getName(), gr.getUUID().get());
- }
- }
- }
- return result.build();
- }
-
// TODO(dborowitz): Move somewhere even more common.
public static ImmutableList<CommitInfo> log(Repository repo, String refName) throws Exception {
try (RevWalk rw = new RevWalk(repo)) {
diff --git a/java/com/google/gerrit/server/restapi/account/SetPreferences.java b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
index 8584240..9b2b231 100644
--- a/java/com/google/gerrit/server/restapi/account/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
@@ -14,18 +14,8 @@
package com.google.gerrit.server.restapi.account;
-import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE_COLUMN;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_ID;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_MATCH;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_TARGET;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_TOKEN;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
-import static com.google.gerrit.server.git.UserConfigSections.URL_ALIAS;
-
import com.google.common.base.Strings;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
-import com.google.gerrit.extensions.client.MenuItem;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -37,8 +27,6 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.PreferencesConfig;
-import com.google.gerrit.server.account.VersionedAccountPreferences;
-import com.google.gerrit.server.git.UserConfigSections;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -47,11 +35,7 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.Config;
@Singleton
public class SetPreferences implements RestModifyView<AccountResource, GeneralPreferencesInfo> {
@@ -93,70 +77,6 @@
return cache.get(id).getGeneralPreferences();
}
- public static void storeMyMenus(VersionedAccountPreferences prefs, List<MenuItem> my)
- throws BadRequestException {
- Config cfg = prefs.getConfig();
- if (my != null) {
- unsetSection(cfg, UserConfigSections.MY);
- for (MenuItem item : my) {
- checkRequiredMenuItemField(item.name, "name");
- checkRequiredMenuItemField(item.url, "URL");
-
- set(cfg, item.name, KEY_URL, item.url);
- set(cfg, item.name, KEY_TARGET, item.target);
- set(cfg, item.name, KEY_ID, item.id);
- }
- }
- }
-
- public static void storeMyChangeTableColumns(
- VersionedAccountPreferences prefs, List<String> changeTable) {
- Config cfg = prefs.getConfig();
- if (changeTable != null) {
- unsetSection(cfg, UserConfigSections.CHANGE_TABLE);
- cfg.setStringList(UserConfigSections.CHANGE_TABLE, null, CHANGE_TABLE_COLUMN, changeTable);
- }
- }
-
- private static void set(Config cfg, String section, String key, @Nullable String val) {
- if (val == null || val.trim().isEmpty()) {
- cfg.unset(UserConfigSections.MY, section.trim(), key);
- } else {
- cfg.setString(UserConfigSections.MY, section.trim(), key, val.trim());
- }
- }
-
- private static void unsetSection(Config cfg, String section) {
- cfg.unsetSection(section, null);
- for (String subsection : cfg.getSubsections(section)) {
- cfg.unsetSection(section, subsection);
- }
- }
-
- public static void storeUrlAliases(
- VersionedAccountPreferences prefs, Map<String, String> urlAliases) {
- if (urlAliases != null) {
- Config cfg = prefs.getConfig();
- for (String subsection : cfg.getSubsections(URL_ALIAS)) {
- cfg.unsetSection(URL_ALIAS, subsection);
- }
-
- int i = 1;
- for (Entry<String, String> e : urlAliases.entrySet()) {
- cfg.setString(URL_ALIAS, URL_ALIAS + i, KEY_MATCH, e.getKey());
- cfg.setString(URL_ALIAS, URL_ALIAS + i, KEY_TOKEN, e.getValue());
- i++;
- }
- }
- }
-
- private static void checkRequiredMenuItemField(String value, String name)
- throws BadRequestException {
- if (value == null || value.trim().isEmpty()) {
- throw new BadRequestException(name + " for menu item is required");
- }
- }
-
private void checkDownloadScheme(String downloadScheme) throws BadRequestException {
if (Strings.isNullOrEmpty(downloadScheme)) {
return;
diff --git a/java/com/google/gerrit/server/schema/SchemaCreator.java b/java/com/google/gerrit/server/schema/SchemaCreator.java
index 2004c98..895e75c 100644
--- a/java/com/google/gerrit/server/schema/SchemaCreator.java
+++ b/java/com/google/gerrit/server/schema/SchemaCreator.java
@@ -240,7 +240,7 @@
AccountGroup.NameKey groupName = groupUpdate.getName().orElseGet(groupCreation::getNameKey);
GroupNameNotes groupNameNotes =
- GroupNameNotes.loadForNewGroup(allUsersRepo, groupCreation.getGroupUUID(), groupName);
+ GroupNameNotes.forNewGroup(allUsersRepo, groupCreation.getGroupUUID(), groupName);
commit(allUsersRepo, groupConfig, groupNameNotes);
diff --git a/java/com/google/gerrit/truth/ListSubject.java b/java/com/google/gerrit/truth/ListSubject.java
index bcd8dcf..cccf51b 100644
--- a/java/com/google/gerrit/truth/ListSubject.java
+++ b/java/com/google/gerrit/truth/ListSubject.java
@@ -30,8 +30,7 @@
@SuppressWarnings("unchecked")
public static <S extends Subject<S, E>, E> ListSubject<S, E> assertThat(
List<E> list, Function<E, S> elementAssertThatFunction) {
- // The ListSubjectFactory always returns ListSubjects.
- // -> Casting is appropriate.
+ // The ListSubjectFactory always returns ListSubjects. -> Casting is appropriate.
return (ListSubject<S, E>)
assertAbout(new ListSubjectFactory<>(elementAssertThatFunction)).that(list);
}
@@ -44,11 +43,8 @@
public S element(int index) {
checkArgument(index >= 0, "index(%s) must be >= 0", index);
- // The constructor only accepts lists.
- // -> Casting is appropriate.
- @SuppressWarnings("unchecked")
- List<E> list = (List<E>) actual();
isNotNull();
+ List<E> list = getActualList();
if (index >= list.size()) {
fail("has an element at index " + index);
}
@@ -61,11 +57,23 @@
return element(0);
}
+ public S lastElement() {
+ isNotNull();
+ isNotEmpty();
+ List<E> list = getActualList();
+ return element(list.size() - 1);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<E> getActualList() {
+ // The constructor only accepts lists. -> Casting is appropriate.
+ return (List<E>) actual();
+ }
+
@SuppressWarnings("unchecked")
@Override
public ListSubject<S, E> named(String s, Object... objects) {
- // This object is returned which is of type ListSubject.
- // -> Casting is appropriate.
+ // This object is returned which is of type ListSubject. -> Casting is appropriate.
return (ListSubject<S, E>) super.named(s, objects);
}
@@ -81,8 +89,7 @@
@SuppressWarnings("unchecked")
@Override
public ListSubject<S, T> createSubject(FailureMetadata failureMetadata, Iterable<?> objects) {
- // The constructor of ListSubject only accepts lists.
- // -> Casting is appropriate.
+ // The constructor of ListSubject only accepts lists. -> Casting is appropriate.
return new ListSubject<>(failureMetadata, (List<T>) objects, elementAssertThatFunction);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 38a9489..f7ca2f2 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -75,9 +75,11 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.receive.ReceiveConstants;
+import com.google.gerrit.server.git.validators.CommitValidators.ChangeIdValidator;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.mail.Address;
import com.google.gerrit.server.project.testing.Util;
@@ -1321,6 +1323,28 @@
}
@Test
+ public void testPushWithChangedChangeId() throws Exception {
+ PushOneCommit.Result r = pushTo("refs/for/master");
+ r.assertOkStatus();
+ PushOneCommit push =
+ pushFactory.create(
+ db,
+ admin.getIdent(),
+ testRepo,
+ PushOneCommit.SUBJECT
+ + "\n\n"
+ + "Change-Id: I55eab7c7a76e95005fa9cc469aa8f9fc16da9eba\n",
+ "b.txt",
+ "anotherContent",
+ r.getChangeId());
+ r = push.to("refs/changes/" + r.getChange().change().getId().get());
+ r.assertErrorStatus(
+ String.format(
+ ChangeIdValidator.CHANGE_ID_MISMATCH_MSG,
+ r.getCommit().abbreviate(RevId.ABBREV_LEN).name()));
+ }
+
+ @Test
public void pushWithMultipleChangeIds() throws Exception {
testPushWithMultipleChangeIds();
}
diff --git a/javatests/com/google/gerrit/server/group/db/BUILD b/javatests/com/google/gerrit/server/group/db/BUILD
index 1ba0ce9..9816603 100644
--- a/javatests/com/google/gerrit/server/group/db/BUILD
+++ b/javatests/com/google/gerrit/server/group/db/BUILD
@@ -6,12 +6,14 @@
srcs = glob(["*.java"]),
deps = [
"//java/com/google/gerrit/common:server",
+ "//java/com/google/gerrit/common/data/testing:common-data-test-util",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/extensions/common/testing:common-test-util",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/group/db/testing",
"//java/com/google/gerrit/testing:gerrit-test-util",
+ "//java/com/google/gerrit/truth",
"//lib:gwtorm",
"//lib:truth",
"//lib/jgit/org.eclipse.jgit:jgit",
diff --git a/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java b/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
index d4ddbcf..c059da9 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
@@ -18,24 +18,38 @@
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 static com.google.gerrit.truth.OptionalSubject.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.common.data.testing.GroupReferenceSubject;
import com.google.gerrit.extensions.common.CommitInfo;
+import com.google.gerrit.extensions.common.testing.CommitInfoSubject;
import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllUsersNameProvider;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.group.db.testing.GroupTestUtil;
import com.google.gerrit.server.update.RefUpdateUtil;
-import com.google.gerrit.testing.GerritBaseTests;
import com.google.gerrit.testing.TestTimeUtil;
+import com.google.gerrit.truth.ListSubject;
+import com.google.gerrit.truth.OptionalSubject;
+import com.google.gwtorm.client.KeyUtil;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.StandardKeyEncoder;
+import java.io.IOException;
import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
@@ -47,16 +61,28 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.notes.NoteMap;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
-public class GroupNameNotesTest extends GerritBaseTests {
+public class GroupNameNotesTest {
+ static {
+ KeyUtil.setEncoderImpl(new StandardKeyEncoder());
+ }
+
private static final String SERVER_NAME = "Gerrit Server";
private static final String SERVER_EMAIL = "noreply@gerritcodereview.com";
private static final TimeZone TZ = TimeZone.getTimeZone("America/Los_Angeles");
+ @Rule public ExpectedException expectedException = ExpectedException.none();
+
+ private final AccountGroup.UUID groupUuid = new AccountGroup.UUID("users-XYZ");
+ private final AccountGroup.NameKey groupName = new AccountGroup.NameKey("users");
+
private AtomicInteger idCounter;
private Repository repo;
@@ -73,12 +99,311 @@
}
@Test
+ public void newGroupCanBeCreated() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ Optional<GroupReference> groupReference = loadGroup(groupName);
+ assertThatGroup(groupReference).value().groupUuid().isEqualTo(groupUuid);
+ assertThatGroup(groupReference).value().name().isEqualTo(groupName.get());
+ }
+
+ @Test
+ public void uuidOfNewGroupMustNotBeNull() throws Exception {
+ expectedException.expect(NullPointerException.class);
+ GroupNameNotes.forNewGroup(repo, null, groupName);
+ }
+
+ @Test
+ public void nameOfNewGroupMustNotBeNull() throws Exception {
+ expectedException.expect(NullPointerException.class);
+ GroupNameNotes.forNewGroup(repo, groupUuid, null);
+ }
+
+ @Test
+ public void nameOfNewGroupMayBeEmpty() throws Exception {
+ AccountGroup.NameKey emptyName = new AccountGroup.NameKey("");
+ createGroup(groupUuid, emptyName);
+
+ Optional<GroupReference> groupReference = loadGroup(emptyName);
+ assertThatGroup(groupReference).value().name().isEqualTo("");
+ }
+
+ @Test
+ public void newGroupMustNotReuseNameOfAnotherGroup() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.UUID anotherGroupUuid = new AccountGroup.UUID("AnotherGroup");
+ expectedException.expect(OrmDuplicateKeyException.class);
+ expectedException.expectMessage(groupName.get());
+ GroupNameNotes.forNewGroup(repo, anotherGroupUuid, groupName);
+ }
+
+ @Test
+ public void newGroupMayReuseUuidOfAnotherGroup() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ createGroup(groupUuid, anotherName);
+
+ Optional<GroupReference> group1 = loadGroup(groupName);
+ assertThatGroup(group1).value().groupUuid().isEqualTo(groupUuid);
+ Optional<GroupReference> group2 = loadGroup(anotherName);
+ assertThatGroup(group2).value().groupUuid().isEqualTo(groupUuid);
+ }
+
+ @Test
+ public void groupCanBeRenamed() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ renameGroup(groupUuid, groupName, anotherName);
+
+ Optional<GroupReference> groupReference = loadGroup(anotherName);
+ assertThatGroup(groupReference).value().groupUuid().isEqualTo(groupUuid);
+ assertThatGroup(groupReference).value().name().isEqualTo(anotherName.get());
+ }
+
+ @Test
+ public void previousNameOfGroupCannotBeUsedAfterRename() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ renameGroup(groupUuid, groupName, anotherName);
+
+ Optional<GroupReference> group = loadGroup(groupName);
+ assertThatGroup(group).isAbsent();
+ }
+
+ @Test
+ public void groupCannotBeRenamedToNull() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ expectedException.expect(NullPointerException.class);
+ GroupNameNotes.forRename(repo, groupUuid, groupName, null);
+ }
+
+ @Test
+ public void oldNameOfGroupMustBeSpecifiedForRename() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ expectedException.expect(NullPointerException.class);
+ GroupNameNotes.forRename(repo, groupUuid, null, anotherName);
+ }
+
+ @Test
+ public void groupCannotBeRenamedWhenOldNameIsWrong() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherOldName = new AccountGroup.NameKey("contributors");
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ expectedException.expect(ConfigInvalidException.class);
+ expectedException.expectMessage(anotherOldName.get());
+ GroupNameNotes.forRename(repo, groupUuid, anotherOldName, anotherName);
+ }
+
+ @Test
+ public void groupCannotBeRenamedToNameOfAnotherGroup() throws Exception {
+ createGroup(groupUuid, groupName);
+ AccountGroup.UUID anotherGroupUuid = new AccountGroup.UUID("admins-ABC");
+ AccountGroup.NameKey anotherGroupName = new AccountGroup.NameKey("admins");
+ createGroup(anotherGroupUuid, anotherGroupName);
+
+ expectedException.expect(OrmDuplicateKeyException.class);
+ expectedException.expectMessage(anotherGroupName.get());
+ GroupNameNotes.forRename(repo, groupUuid, groupName, anotherGroupName);
+ }
+
+ @Test
+ public void groupCannotBeRenamedWithoutSpecifiedUuid() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ expectedException.expect(NullPointerException.class);
+ GroupNameNotes.forRename(repo, null, groupName, anotherName);
+ }
+
+ @Test
+ public void groupCannotBeRenamedWhenUuidIsWrong() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.UUID anotherGroupUuid = new AccountGroup.UUID("admins-ABC");
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ expectedException.expect(ConfigInvalidException.class);
+ expectedException.expectMessage(groupUuid.get());
+ GroupNameNotes.forRename(repo, anotherGroupUuid, groupName, anotherName);
+ }
+
+ @Test
+ public void firstGroupCreationCreatesARootCommit() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ Ref ref = repo.exactRef(RefNames.REFS_GROUPNAMES);
+ assertThat(ref.getObjectId()).isNotNull();
+
+ try (RevWalk revWalk = new RevWalk(repo)) {
+ RevCommit revCommit = revWalk.parseCommit(ref.getObjectId());
+ assertThat(revCommit.getParentCount()).isEqualTo(0);
+ }
+ }
+
+ @Test
+ public void furtherGroupCreationAppendsACommit() throws Exception {
+ createGroup(groupUuid, groupName);
+ ImmutableList<CommitInfo> commitsAfterCreation = log();
+
+ AccountGroup.UUID anotherGroupUuid = new AccountGroup.UUID("admins-ABC");
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ createGroup(anotherGroupUuid, anotherName);
+
+ ImmutableList<CommitInfo> commitsAfterFurtherGroup = log();
+ assertThatCommits(commitsAfterFurtherGroup).containsAllIn(commitsAfterCreation);
+ assertThatCommits(commitsAfterFurtherGroup).lastElement().isNotIn(commitsAfterCreation);
+ }
+
+ @Test
+ public void groupRenamingAppendsACommit() throws Exception {
+ createGroup(groupUuid, groupName);
+ ImmutableList<CommitInfo> commitsAfterCreation = log();
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ renameGroup(groupUuid, groupName, anotherName);
+
+ ImmutableList<CommitInfo> commitsAfterRename = log();
+ assertThatCommits(commitsAfterRename).containsAllIn(commitsAfterCreation);
+ assertThatCommits(commitsAfterRename).lastElement().isNotIn(commitsAfterCreation);
+ }
+
+ @Test
+ public void newCommitIsNotCreatedForRedundantNameUpdate() throws Exception {
+ createGroup(groupUuid, groupName);
+ ImmutableList<CommitInfo> commitsAfterCreation = log();
+
+ renameGroup(groupUuid, groupName, groupName);
+
+ ImmutableList<CommitInfo> commitsAfterRename = log();
+ assertThatCommits(commitsAfterRename).isEqualTo(commitsAfterCreation);
+ }
+
+ @Test
+ public void newCommitIsNotCreatedWhenCommittingGroupCreationTwice() throws Exception {
+ GroupNameNotes groupNameNotes = GroupNameNotes.forNewGroup(repo, groupUuid, groupName);
+
+ commit(groupNameNotes);
+ ImmutableList<CommitInfo> commitsAfterFirstCommit = log();
+ commit(groupNameNotes);
+ ImmutableList<CommitInfo> commitsAfterSecondCommit = log();
+
+ assertThatCommits(commitsAfterSecondCommit).isEqualTo(commitsAfterFirstCommit);
+ }
+
+ @Test
+ public void newCommitIsNotCreatedWhenCommittingGroupRenamingTwice() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ GroupNameNotes groupNameNotes =
+ GroupNameNotes.forRename(repo, groupUuid, groupName, anotherName);
+
+ commit(groupNameNotes);
+ ImmutableList<CommitInfo> commitsAfterFirstCommit = log();
+ commit(groupNameNotes);
+ ImmutableList<CommitInfo> commitsAfterSecondCommit = log();
+
+ assertThatCommits(commitsAfterSecondCommit).isEqualTo(commitsAfterFirstCommit);
+ }
+
+ @Test
+ public void commitMessageMentionsGroupCreation() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ ImmutableList<CommitInfo> commits = log();
+ assertThatCommits(commits).lastElement().message().contains("Create");
+ assertThatCommits(commits).lastElement().message().contains(groupName.get());
+ }
+
+ @Test
+ public void commitMessageMentionsGroupRenaming() throws Exception {
+ createGroup(groupUuid, groupName);
+
+ AccountGroup.NameKey anotherName = new AccountGroup.NameKey("admins");
+ renameGroup(groupUuid, groupName, anotherName);
+
+ ImmutableList<CommitInfo> commits = log();
+ assertThatCommits(commits).lastElement().message().contains("Rename");
+ assertThatCommits(commits).lastElement().message().contains(groupName.get());
+ assertThatCommits(commits).lastElement().message().contains(anotherName.get());
+ }
+
+ @Test
+ public void nonExistentNotesRefIsEquivalentToNonExistentGroup() throws Exception {
+ Optional<GroupReference> group = loadGroup(groupName);
+
+ assertThatGroup(group).isAbsent();
+ }
+
+ @Test
+ public void nonExistentGroupCannotBeLoaded() throws Exception {
+ createGroup(new AccountGroup.UUID("contributors-MN"), new AccountGroup.NameKey("contributors"));
+ createGroup(groupUuid, groupName);
+
+ Optional<GroupReference> group = loadGroup(new AccountGroup.NameKey("admins"));
+ assertThatGroup(group).isAbsent();
+ }
+
+ @Test
+ public void specificGroupCanBeLoaded() throws Exception {
+ createGroup(new AccountGroup.UUID("contributors-MN"), new AccountGroup.NameKey("contributors"));
+ createGroup(groupUuid, groupName);
+ createGroup(new AccountGroup.UUID("admins-ABC"), new AccountGroup.NameKey("admins"));
+
+ Optional<GroupReference> group = loadGroup(groupName);
+ assertThatGroup(group).value().groupUuid().isEqualTo(groupUuid);
+ }
+
+ @Test
+ public void nonExistentNotesRefIsEquivalentToNotAnyExistingGroups() throws Exception {
+ ImmutableList<GroupReference> allGroups = GroupNameNotes.loadAllGroups(repo);
+
+ assertThat(allGroups).isEmpty();
+ }
+
+ @Test
+ public void allGroupsCanBeLoaded() throws Exception {
+ AccountGroup.UUID groupUuid1 = new AccountGroup.UUID("contributors-MN");
+ AccountGroup.NameKey groupName1 = new AccountGroup.NameKey("contributors");
+ createGroup(groupUuid1, groupName1);
+ AccountGroup.UUID groupUuid2 = new AccountGroup.UUID("admins-ABC");
+ AccountGroup.NameKey groupName2 = new AccountGroup.NameKey("admins");
+ createGroup(groupUuid2, groupName2);
+
+ ImmutableList<GroupReference> allGroups = GroupNameNotes.loadAllGroups(repo);
+
+ GroupReference group1 = new GroupReference(groupUuid1, groupName1.get());
+ GroupReference group2 = new GroupReference(groupUuid2, groupName2.get());
+ assertThat(allGroups).containsExactly(group1, group2);
+ }
+
+ @Test
+ public void loadedGroupsContainGroupsWithDuplicateGroupUuids() throws Exception {
+ createGroup(groupUuid, groupName);
+ AccountGroup.NameKey anotherGroupName = new AccountGroup.NameKey("admins");
+ createGroup(groupUuid, anotherGroupName);
+
+ ImmutableList<GroupReference> allGroups = GroupNameNotes.loadAllGroups(repo);
+
+ GroupReference group1 = new GroupReference(groupUuid, groupName.get());
+ GroupReference group2 = new GroupReference(groupUuid, anotherGroupName.get());
+ assertThat(allGroups).containsExactly(group1, group2);
+ }
+
+ @Test
public void updateGroupNames() throws Exception {
GroupReference g1 = newGroup("a");
GroupReference g2 = newGroup("b");
PersonIdent ident = newPersonIdent();
- updateGroupNames(ident, g1, g2);
+ updateAllGroups(ident, g1, g2);
ImmutableList<CommitInfo> log = log();
assertThat(log).hasSize(1);
@@ -87,11 +412,11 @@
assertThat(log.get(0)).author().matches(ident);
assertThat(log.get(0)).committer().matches(ident);
- assertThat(GroupTestUtil.readNameToUuidMap(repo)).containsExactly("a", "a-1", "b", "b-2");
+ assertThat(GroupNameNotes.loadAllGroups(repo)).containsExactly(g1, g2);
// Updating the same set of names is a no-op.
String commit = log.get(0).commit;
- updateGroupNames(newPersonIdent(), g1, g2);
+ updateAllGroups(newPersonIdent(), g1, g2);
log = log();
assertThat(log).hasSize(1);
assertThat(log.get(0)).commit().isEqualTo(commit);
@@ -120,9 +445,9 @@
.copy();
ident = newPersonIdent();
- updateGroupNames(ident, g1, g2);
+ updateAllGroups(ident, g1, g2);
- assertThat(GroupTestUtil.readNameToUuidMap(repo)).containsExactly("a", "a-1", "b", "b-2");
+ assertThat(GroupNameNotes.loadAllGroups(repo)).containsExactly(g1, g2);
ImmutableList<CommitInfo> log = log();
assertThat(log).hasSize(2);
@@ -142,13 +467,13 @@
GroupReference g2 = newGroup("b");
PersonIdent ident = newPersonIdent();
- updateGroupNames(ident, g1, g2);
+ updateAllGroups(ident, g1, g2);
- assertThat(GroupTestUtil.readNameToUuidMap(repo)).containsExactly("a", "a-1", "b", "b-2");
+ assertThat(GroupNameNotes.loadAllGroups(repo)).containsExactly(g1, g2);
- updateGroupNames(ident);
+ updateAllGroups(ident);
- assertThat(GroupTestUtil.readNameToUuidMap(repo)).isEmpty();
+ assertThat(GroupNameNotes.loadAllGroups(repo)).isEmpty();
ImmutableList<CommitInfo> log = log();
assertThat(log).hasSize(2);
@@ -171,12 +496,46 @@
@Test
public void emptyGroupName() throws Exception {
GroupReference g = newGroup("");
- updateGroupNames(newPersonIdent(), g);
+ updateAllGroups(newPersonIdent(), g);
- assertThat(GroupTestUtil.readNameToUuidMap(repo)).containsExactly("", "-1");
+ assertThat(GroupNameNotes.loadAllGroups(repo)).containsExactly(g);
assertThat(readNameNote(g)).isEqualTo("[group]\n\tuuid = -1\n\tname = \n");
}
+ private void createGroup(AccountGroup.UUID groupUuid, AccountGroup.NameKey groupName)
+ throws Exception {
+ GroupNameNotes groupNameNotes = GroupNameNotes.forNewGroup(repo, groupUuid, groupName);
+ commit(groupNameNotes);
+ }
+
+ private void renameGroup(
+ AccountGroup.UUID groupUuid, AccountGroup.NameKey oldName, AccountGroup.NameKey newName)
+ throws Exception {
+ GroupNameNotes groupNameNotes = GroupNameNotes.forRename(repo, groupUuid, oldName, newName);
+ commit(groupNameNotes);
+ }
+
+ private Optional<GroupReference> loadGroup(AccountGroup.NameKey groupName) throws Exception {
+ return GroupNameNotes.loadGroup(repo, groupName);
+ }
+
+ private void commit(GroupNameNotes groupNameNotes) throws IOException {
+ try (MetaDataUpdate metaDataUpdate = createMetaDataUpdate()) {
+ groupNameNotes.commit(metaDataUpdate);
+ }
+ }
+
+ private MetaDataUpdate createMetaDataUpdate() {
+ PersonIdent serverIdent = newPersonIdent();
+
+ MetaDataUpdate metaDataUpdate =
+ new MetaDataUpdate(
+ GitReferenceUpdated.DISABLED, new Project.NameKey("Test Repository"), repo);
+ metaDataUpdate.getCommitBuilder().setCommitter(serverIdent);
+ metaDataUpdate.getCommitBuilder().setAuthor(serverIdent);
+ return metaDataUpdate;
+ }
+
private GroupReference newGroup(String name) {
int id = idCounter.incrementAndGet();
return new GroupReference(new AccountGroup.UUID(name + "-" + id), name);
@@ -190,10 +549,10 @@
return GroupNameNotes.getNoteKey(new AccountGroup.NameKey(g.getName()));
}
- private void updateGroupNames(PersonIdent ident, GroupReference... groupRefs) throws Exception {
+ private void updateAllGroups(PersonIdent ident, GroupReference... groupRefs) throws Exception {
try (ObjectInserter inserter = repo.newObjectInserter()) {
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
- GroupNameNotes.updateGroupNames(repo, inserter, bru, Arrays.asList(groupRefs), ident);
+ GroupNameNotes.updateAllGroups(repo, inserter, bru, Arrays.asList(groupRefs), ident);
inserter.flush();
RefUpdateUtil.executeChecked(bru, repo);
}
@@ -204,7 +563,7 @@
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
PersonIdent ident = newPersonIdent();
try {
- GroupNameNotes.updateGroupNames(repo, inserter, bru, Arrays.asList(groupRefs), ident);
+ GroupNameNotes.updateAllGroups(repo, inserter, bru, Arrays.asList(groupRefs), ident);
assert_().fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().isEqualTo(GroupNameNotes.UNIQUE_REF_ERROR);
@@ -225,4 +584,14 @@
return new String(reader.open(noteMap.get(k), OBJ_BLOB).getCachedBytes(), UTF_8);
}
}
+
+ private static OptionalSubject<GroupReferenceSubject, GroupReference> assertThatGroup(
+ Optional<GroupReference> group) {
+ return assertThat(group, GroupReferenceSubject::assertThat);
+ }
+
+ private static ListSubject<CommitInfoSubject, CommitInfo> assertThatCommits(
+ List<CommitInfo> commits) {
+ return ListSubject.assertThat(commits, CommitInfoSubject::assertThat);
+ }
}
diff --git a/javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java b/javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java
index 51cf987..048eaba 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java
@@ -536,7 +536,7 @@
try (ObjectInserter inserter = repo.newObjectInserter()) {
ImmutableList<GroupReference> refs =
ImmutableList.of(GroupReference.forGroup(g1), GroupReference.forGroup(g2));
- GroupNameNotes.updateGroupNames(repo, inserter, bru, refs, newPersonIdent());
+ GroupNameNotes.updateAllGroups(repo, inserter, bru, refs, newPersonIdent());
inserter.flush();
}
@@ -552,7 +552,9 @@
assertMigratedCleanly(reload(g1), b1);
assertMigratedCleanly(reload(g2), b2);
- assertThat(GroupTestUtil.readNameToUuidMap(repo)).containsExactly("a", "a-1", "b", "b-2");
+ GroupReference group1 = GroupReference.forGroup(g1);
+ GroupReference group2 = GroupReference.forGroup(g2);
+ assertThat(GroupNameNotes.loadAllGroups(repo)).containsExactly(group1, group2);
}
@Test
diff --git a/javatests/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyCheckerTest.java b/javatests/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyCheckerTest.java
index eff755f..a5b04ee 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyCheckerTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyCheckerTest.java
@@ -30,7 +30,7 @@
public void groupNamesRefIsMissing() throws Exception {
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems)
.containsExactly(warning("Group with name 'g-1' doesn't exist in the list of all names"));
}
@@ -40,7 +40,7 @@
updateGroupNamesRef("g-2", "[group]\n\tuuid = uuid-2\n\tname = g-2\n");
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems)
.containsExactly(warning("Group with name 'g-1' doesn't exist in the list of all names"));
}
@@ -50,7 +50,7 @@
updateGroupNamesRef("g-1", "[group]\n\tuuid = uuid-1\n\tname = g-1\n");
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems).isEmpty();
}
@@ -59,7 +59,7 @@
updateGroupNamesRef("g-1", "[group]\n\tuuid = uuid-2\n\tname = g-1\n");
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems)
.containsExactly(
warning(
@@ -72,7 +72,7 @@
updateGroupNamesRef("g-1", "[group]\n\tuuid = uuid-1\n\tname = g-2\n");
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems)
.containsExactly(warning("group note of name 'g-1' claims to represent name of 'g-2'"));
}
@@ -82,7 +82,7 @@
updateGroupNamesRef("g-1", "[group]\n\tuuid = uuid-2\n\tname = g-2\n");
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems)
.containsExactly(
warning(
@@ -97,7 +97,7 @@
updateGroupNamesRef("g-1", "[invalid");
List<ConsistencyProblemInfo> problems =
GroupsNoteDbConsistencyChecker.checkWithGroupNameNotes(
- allUsersRepo, "g-1", new AccountGroup.UUID("uuid-1"));
+ allUsersRepo, new AccountGroup.NameKey("g-1"), new AccountGroup.UUID("uuid-1"));
assertThat(problems)
.containsExactly(
warning(