ChangeBundle: Be more lenient about reviewers
The computation in ReviewerSet#fromApprovals doesn't really do the
right thing when there are multiple zero and non-zero labels and the
input list isn't sorted. This is a different thing from what
ChangeNotesParser does, which always takes the latest state for a user
regardless of whether there are other states earlier in the series.
We don't distinguish REVIEWER/CC in the UI, so being slightly lossy is
not likely to be noticeable.
Change-Id: I8b8409742a01f53f4d10a363e36bd4d5bb724ed2
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
index f5202f4..0a24269 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
@@ -42,7 +42,6 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
-import com.google.common.collect.Table;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
@@ -63,7 +62,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -710,37 +708,10 @@
}
}
- @AutoValue
- static abstract class ReviewerKey {
- private static Map<ReviewerKey, Timestamp> toMap(ReviewerSet reviewers) {
- Map<ReviewerKey, Timestamp> result = new HashMap<>();
- for (Table.Cell<ReviewerStateInternal, Account.Id, Timestamp> c :
- reviewers.asTable().cellSet()) {
- result.put(new AutoValue_ChangeBundle_ReviewerKey(
- c.getRowKey(), c.getColumnKey()), c.getValue());
- }
- return result;
- }
-
- abstract ReviewerStateInternal state();
- abstract Account.Id account();
-
- @Override
- public String toString() {
- return state() + "," + account();
- }
- }
-
private static void diffReviewers(List<String> diffs,
ChangeBundle bundleA, ChangeBundle bundleB) {
- Map<ReviewerKey, Timestamp> as = ReviewerKey.toMap(bundleA.reviewers);
- Map<ReviewerKey, Timestamp> bs = ReviewerKey.toMap(bundleB.reviewers);
- for (ReviewerKey k : diffKeySets(diffs, as, bs)) {
- Timestamp a = as.get(k);
- Timestamp b = bs.get(k);
- String desc = describe(k);
- diffTimestamps(diffs, desc, bundleA, a, bundleB, b, "timestamp");
- }
+ diffSets(
+ diffs, bundleA.reviewers.all(), bundleB.reviewers.all(), "reviewer");
}
private static void diffPatchLineComments(List<String> diffs,
@@ -759,19 +730,26 @@
private static <T> Set<T> diffKeySets(List<String> diffs, Map<T, ?> a,
Map<T, ?> b) {
- Set<T> as = a.keySet();
- Set<T> bs = b.keySet();
+ if (a.isEmpty() && b.isEmpty()) {
+ return a.keySet();
+ }
+ String clazz =
+ keyClass((!a.isEmpty() ? a.keySet() : b.keySet()).iterator().next());
+ return diffSets(diffs, a.keySet(), b.keySet(), clazz);
+ }
+
+ private static <T> Set<T> diffSets(List<String> diffs, Set<T> as,
+ Set<T> bs, String desc) {
if (as.isEmpty() && bs.isEmpty()) {
return as;
}
- String clazz = keyClass((!as.isEmpty() ? as : bs).iterator().next());
Set<T> aNotB = Sets.difference(as, bs);
Set<T> bNotA = Sets.difference(bs, as);
if (aNotB.isEmpty() && bNotA.isEmpty()) {
return as;
}
- diffs.add(clazz + " sets differ: " + aNotB + " only in A; "
+ diffs.add(desc + " sets differ: " + aNotB + " only in A; "
+ bNotA + " only in B");
return Sets.intersection(as, bs);
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
index 978682b..a6ab96d 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
@@ -19,6 +19,7 @@
import static com.google.gerrit.common.TimeUtil.roundToSecond;
import static com.google.gerrit.server.notedb.ChangeBundle.Source.NOTE_DB;
import static com.google.gerrit.server.notedb.ChangeBundle.Source.REVIEW_DB;
+import static com.google.gerrit.server.notedb.ReviewerStateInternal.CC;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -1055,7 +1056,7 @@
}
@Test
- public void diffReviewerKeySets() throws Exception {
+ public void diffReviewers() throws Exception {
Change c = TestChanges.newChange(project, accountId);
Timestamp now = TimeUtil.nowTs();
ReviewerSet r1 = reviewers(REVIEWER, new Account.Id(1), now);
@@ -1068,67 +1069,23 @@
assertNoDiffs(b1, b1);
assertNoDiffs(b2, b2);
assertDiffs(b1, b2,
- "ReviewerKey sets differ:"
- + " [REVIEWER,1] only in A;"
- + " [REVIEWER,2] only in B");
+ "reviewer sets differ:"
+ + " [1] only in A;"
+ + " [2] only in B");
}
@Test
- public void diffReviewerTimestamps() throws Exception {
+ public void diffReviewersIgnoresStateAndTimestamp() throws Exception {
Change c = TestChanges.newChange(project, accountId);
ReviewerSet r1 = reviewers(REVIEWER, new Account.Id(1), TimeUtil.nowTs());
- ReviewerSet r2 = reviewers(REVIEWER, new Account.Id(1), TimeUtil.nowTs());
+ ReviewerSet r2 = reviewers(CC, new Account.Id(1), TimeUtil.nowTs());
ChangeBundle b1 = new ChangeBundle(c, messages(), latest(c), approvals(),
comments(), r1, REVIEW_DB);
ChangeBundle b2 = new ChangeBundle(c, messages(), latest(c), approvals(),
comments(), r2, REVIEW_DB);
- assertDiffs(b1, b2,
- "timestamp differs for ReviewerKey REVIEWER,1:"
- + " {2009-09-30 17:00:06.0} != {2009-09-30 17:00:12.0}");
-
- b1 = new ChangeBundle(c, messages(), latest(c), approvals(), comments(), r1,
- REVIEW_DB);
- b2 = new ChangeBundle(c, messages(), latest(c), approvals(), comments(), r2,
- NOTE_DB);
- assertDiffs(b1, b2,
- "timestamp differs for ReviewerKey REVIEWER,1 in NoteDb vs. ReviewDb:"
- + " {2009-09-30 17:00:12.0} != {2009-09-30 17:00:06.0}");
- }
-
- @Test
- public void diffReviewerTimestampsAllowsSlop() throws Exception {
- subWindowResolution();
- Change c = TestChanges.newChange(project, accountId);
- ReviewerSet r1 = reviewers(REVIEWER, new Account.Id(1), TimeUtil.nowTs());
- ReviewerSet r2 = reviewers(REVIEWER, new Account.Id(1), TimeUtil.nowTs());
-
- // Both are ReviewDb, exact timestamp match is required.
- ChangeBundle b1 = new ChangeBundle(c, messages(), latest(c), approvals(),
- comments(), r1, REVIEW_DB);
- ChangeBundle b2 = new ChangeBundle(c, messages(), latest(c), approvals(),
- comments(), r2, REVIEW_DB);
- assertDiffs(b1, b2,
- "timestamp differs for ReviewerKey REVIEWER,1:"
- + " {2009-09-30 17:00:02.0} != {2009-09-30 17:00:03.0}");
-
- // One NoteDb, slop is allowed
- b1 = new ChangeBundle(c, messages(), latest(c), approvals(), comments(), r1,
- NOTE_DB);
- b2 = new ChangeBundle(c, messages(), latest(c), approvals(), comments(), r2,
- REVIEW_DB);
- assertNoDiffs(b1, b2);
-
- // But not too much slop.
- superWindowResolution();
- ReviewerSet r3 = reviewers(REVIEWER, new Account.Id(1), TimeUtil.nowTs());
- b1 = new ChangeBundle(c, messages(), latest(c), approvals(), comments(), r1,
- NOTE_DB);
- ChangeBundle b3 = new ChangeBundle(c, messages(), latest(c), approvals(),
- comments(), r3, REVIEW_DB);
- assertDiffs(b1, b3,
- "timestamp differs for ReviewerKey REVIEWER,1 in NoteDb vs. ReviewDb:"
- + " {2009-09-30 17:00:02.0} != {2009-09-30 17:00:10.0}");
+ assertNoDiffs(b1, b1);
+ assertNoDiffs(b2, b2);
}
@Test