Files
gerrit/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
Gal Paikin dd31db99c3 Change the structure of Submission Id
Currently Submission Id is constructed by the change-id of the change
that triggered the submission, the timestamp, and a random alphanumeric
string. This is not pretty. Since we recently revealed the submission id
via ChangeInfo in Ic557e0c94 and via queries in I337f7f8ae, it's a good
idea to change the submission id to be more user friendly.

Submission Id is now constructed of "<numeric-id>-<topic>" or
"<numeric-id>" if topic doesn't exist for that change.

The change id is used because it makes the submission id unique (a
change can only be submitted once). The topic is used mostly since this
is currently one of the main use cases for Revert Submission.

Change-Id: Iec8b0db66adf9a7ff2809994acaedef09e4e885c
2019-12-10 15:05:08 +01:00

3144 lines
104 KiB
Java

// Copyright (C) 2013 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.notedb;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.gerrit.entities.RefNames.changeMetaRef;
import static com.google.gerrit.entities.RefNames.refsDraftComments;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.CC;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REMOVED;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.comparing;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
import com.google.gerrit.entities.Comment;
import com.google.gerrit.entities.CommentRange;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.SubmissionId;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.mail.Address;
import com.google.gerrit.server.AssigneeStatusUpdate;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.notedb.ChangeNotesCommit.ChangeNotesRevWalk;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.testing.TestChanges;
import com.google.inject.Inject;
import java.sql.Timestamp;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
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.Test;
public class ChangeNotesTest extends AbstractChangeNotesTest {
@Inject private DraftCommentNotes.Factory draftNotesFactory;
@Inject private ChangeNoteJson changeNoteJson;
@Inject private @GerritServerId String serverId;
@Test
public void tagChangeMessage() throws Exception {
String tag = "jenkins";
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setChangeMessage("verification from jenkins");
update.setTag(tag);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChangeMessages()).hasSize(1);
assertThat(notes.getChangeMessages().get(0).getTag()).isEqualTo(tag);
}
@Test
public void patchSetDescription() throws Exception {
String description = "descriptive";
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPsDescription(description);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getCurrentPatchSet().description()).hasValue(description);
description = "new, now more descriptive!";
update = newUpdate(c, changeOwner);
update.setPsDescription(description);
update.commit();
notes = newNotes(c);
assertThat(notes.getCurrentPatchSet().description()).hasValue(description);
}
@Test
public void tagInlineComments() throws Exception {
String tag = "jenkins";
Change c = newChange();
RevCommit commit = tr.commit().message("PS2").create();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putComment(
Comment.Status.PUBLISHED,
newComment(
c.currentPatchSetId(),
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
TimeUtil.nowTs(),
"Comment",
(short) 1,
commit,
false));
update.setTag(tag);
update.commit();
ChangeNotes notes = newNotes(c);
ImmutableListMultimap<ObjectId, Comment> comments = notes.getComments();
assertThat(comments).hasSize(1);
assertThat(comments.entries().asList().get(0).getValue().tag).isEqualTo(tag);
}
@Test
public void tagApprovals() throws Exception {
String tag1 = "jenkins";
String tag2 = "ip";
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Verified", (short) -1);
update.setTag(tag1);
update.commit();
update = newUpdate(c, changeOwner);
update.putApproval("Verified", (short) 1);
update.setTag(tag2);
update.commit();
ChangeNotes notes = newNotes(c);
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals = notes.getApprovals();
assertThat(approvals).hasSize(1);
assertThat(approvals.entries().asList().get(0).getValue().tag()).hasValue(tag2);
}
@Test
public void multipleTags() throws Exception {
String ipTag = "ip";
String coverageTag = "coverage";
String integrationTag = "integration";
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Verified", (short) -1);
update.setChangeMessage("integration verification");
update.setTag(integrationTag);
update.commit();
RevCommit commit = tr.commit().message("PS2").create();
update = newUpdate(c, changeOwner);
update.putComment(
Comment.Status.PUBLISHED,
newComment(
c.currentPatchSetId(),
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
TimeUtil.nowTs(),
"Comment",
(short) 1,
commit,
false));
update.setChangeMessage("coverage verification");
update.setTag(coverageTag);
update.commit();
update = newUpdate(c, changeOwner);
update.setChangeMessage("ip clear");
update.setTag(ipTag);
update.commit();
ChangeNotes notes = newNotes(c);
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals = notes.getApprovals();
assertThat(approvals).hasSize(1);
PatchSetApproval approval = approvals.entries().asList().get(0).getValue();
assertThat(approval.tag()).hasValue(integrationTag);
assertThat(approval.value()).isEqualTo(-1);
ImmutableListMultimap<ObjectId, Comment> comments = notes.getComments();
assertThat(comments).hasSize(1);
assertThat(comments.entries().asList().get(0).getValue().tag).isEqualTo(coverageTag);
ImmutableList<ChangeMessage> messages = notes.getChangeMessages();
assertThat(messages).hasSize(3);
assertThat(messages.get(0).getTag()).isEqualTo(integrationTag);
assertThat(messages.get(1).getTag()).isEqualTo(coverageTag);
assertThat(messages.get(2).getTag()).isEqualTo(ipTag);
}
@Test
public void approvalsOnePatchSet() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Verified", (short) 1);
update.putApproval("Code-Review", (short) -1);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getApprovals().keySet()).containsExactly(c.currentPatchSetId());
List<PatchSetApproval> psas = notes.getApprovals().get(c.currentPatchSetId());
assertThat(psas).hasSize(2);
assertThat(psas.get(0).patchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(0).accountId().get()).isEqualTo(1);
assertThat(psas.get(0).label()).isEqualTo("Code-Review");
assertThat(psas.get(0).value()).isEqualTo((short) -1);
assertThat(psas.get(0).granted()).isEqualTo(truncate(after(c, 2000)));
assertThat(psas.get(1).patchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(1).accountId().get()).isEqualTo(1);
assertThat(psas.get(1).label()).isEqualTo("Verified");
assertThat(psas.get(1).value()).isEqualTo((short) 1);
assertThat(psas.get(1).granted()).isEqualTo(psas.get(0).granted());
}
@Test
public void approvalsMultiplePatchSets() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
PatchSet.Id ps1 = c.currentPatchSetId();
incrementPatchSet(c);
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
PatchSet.Id ps2 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, PatchSetApproval> psas = notes.getApprovals();
assertThat(psas).hasSize(2);
PatchSetApproval psa1 = Iterables.getOnlyElement(psas.get(ps1));
assertThat(psa1.patchSetId()).isEqualTo(ps1);
assertThat(psa1.accountId().get()).isEqualTo(1);
assertThat(psa1.label()).isEqualTo("Code-Review");
assertThat(psa1.value()).isEqualTo((short) -1);
assertThat(psa1.granted()).isEqualTo(truncate(after(c, 2000)));
PatchSetApproval psa2 = Iterables.getOnlyElement(psas.get(ps2));
assertThat(psa2.patchSetId()).isEqualTo(ps2);
assertThat(psa2.accountId().get()).isEqualTo(1);
assertThat(psa2.label()).isEqualTo("Code-Review");
assertThat(psa2.value()).isEqualTo((short) +1);
assertThat(psa2.granted()).isEqualTo(truncate(after(c, 4000)));
}
@Test
public void approvalsMultipleApprovals() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
ChangeNotes notes = newNotes(c);
PatchSetApproval psa =
Iterables.getOnlyElement(notes.getApprovals().get(c.currentPatchSetId()));
assertThat(psa.label()).isEqualTo("Code-Review");
assertThat(psa.value()).isEqualTo((short) -1);
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
notes = newNotes(c);
psa = Iterables.getOnlyElement(notes.getApprovals().get(c.currentPatchSetId()));
assertThat(psa.label()).isEqualTo("Code-Review");
assertThat(psa.value()).isEqualTo((short) 1);
}
@Test
public void approvalsMultipleUsers() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
update = newUpdate(c, otherUser);
update.putApproval("Code-Review", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getApprovals().keySet()).containsExactly(c.currentPatchSetId());
List<PatchSetApproval> psas = notes.getApprovals().get(c.currentPatchSetId());
assertThat(psas).hasSize(2);
assertThat(psas.get(0).patchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(0).accountId().get()).isEqualTo(1);
assertThat(psas.get(0).label()).isEqualTo("Code-Review");
assertThat(psas.get(0).value()).isEqualTo((short) -1);
assertThat(psas.get(0).granted()).isEqualTo(truncate(after(c, 2000)));
assertThat(psas.get(1).patchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(1).accountId().get()).isEqualTo(2);
assertThat(psas.get(1).label()).isEqualTo("Code-Review");
assertThat(psas.get(1).value()).isEqualTo((short) 1);
assertThat(psas.get(1).granted()).isEqualTo(truncate(after(c, 3000)));
}
@Test
public void approvalsTombstone() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Not-For-Long", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
PatchSetApproval psa =
Iterables.getOnlyElement(notes.getApprovals().get(c.currentPatchSetId()));
assertThat(psa.accountId().get()).isEqualTo(1);
assertThat(psa.label()).isEqualTo("Not-For-Long");
assertThat(psa.value()).isEqualTo((short) 1);
update = newUpdate(c, changeOwner);
update.removeApproval("Not-For-Long");
update.commit();
notes = newNotes(c);
assertThat(notes.getApprovals())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
psa.patchSetId(),
PatchSetApproval.builder()
.key(psa.key())
.value(0)
.granted(update.getWhen())
.build()));
}
@Test
public void removeOtherUsersApprovals() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
update.putApproval("Not-For-Long", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
PatchSetApproval psa =
Iterables.getOnlyElement(notes.getApprovals().get(c.currentPatchSetId()));
assertThat(psa.accountId()).isEqualTo(otherUserId);
assertThat(psa.label()).isEqualTo("Not-For-Long");
assertThat(psa.value()).isEqualTo((short) 1);
update = newUpdate(c, changeOwner);
update.removeApprovalFor(otherUserId, "Not-For-Long");
update.commit();
notes = newNotes(c);
assertThat(notes.getApprovals())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
psa.patchSetId(),
PatchSetApproval.builder()
.key(psa.key())
.value(0)
.granted(update.getWhen())
.build()));
// Add back approval on same label.
update = newUpdate(c, otherUser);
update.putApproval("Not-For-Long", (short) 2);
update.commit();
notes = newNotes(c);
psa = Iterables.getOnlyElement(notes.getApprovals().get(c.currentPatchSetId()));
assertThat(psa.accountId()).isEqualTo(otherUserId);
assertThat(psa.label()).isEqualTo("Not-For-Long");
assertThat(psa.value()).isEqualTo((short) 2);
}
@Test
public void putOtherUsersApprovals() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.putApprovalFor(otherUser.getAccountId(), "Code-Review", (short) -1);
update.commit();
ChangeNotes notes = newNotes(c);
ImmutableList<PatchSetApproval> approvals =
notes.getApprovals().get(c.currentPatchSetId()).stream()
.sorted(comparing(a -> a.accountId().get()))
.collect(toImmutableList());
assertThat(approvals).hasSize(2);
assertThat(approvals.get(0).accountId()).isEqualTo(changeOwner.getAccountId());
assertThat(approvals.get(0).label()).isEqualTo("Code-Review");
assertThat(approvals.get(0).value()).isEqualTo((short) 1);
assertThat(approvals.get(1).accountId()).isEqualTo(otherUser.getAccountId());
assertThat(approvals.get(1).label()).isEqualTo("Code-Review");
assertThat(approvals.get(1).value()).isEqualTo((short) -1);
}
@Test
public void approvalsPostSubmit() throws Exception {
Change c = newChange();
SubmissionId submissionId = new SubmissionId(c);
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.putApproval("Verified", (short) 1);
update.commit();
update = newUpdate(c, changeOwner);
update.merge(
submissionId,
ImmutableList.of(
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Code-Review", "NEED", null))));
update.commit();
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 2);
update.commit();
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> approvals = Lists.newArrayList(notes.getApprovals().values());
assertThat(approvals).hasSize(2);
assertThat(approvals.get(0).label()).isEqualTo("Verified");
assertThat(approvals.get(0).value()).isEqualTo((short) 1);
assertThat(approvals.get(0).postSubmit()).isFalse();
assertThat(approvals.get(1).label()).isEqualTo("Code-Review");
assertThat(approvals.get(1).value()).isEqualTo((short) 2);
assertThat(approvals.get(1).postSubmit()).isTrue();
}
@Test
public void approvalsDuringSubmit() throws Exception {
Change c = newChange();
SubmissionId submissionId = new SubmissionId(c);
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.putApproval("Verified", (short) 1);
update.commit();
Account.Id ownerId = changeOwner.getAccountId();
Account.Id otherId = otherUser.getAccountId();
update = newUpdate(c, otherUser);
update.merge(
submissionId,
ImmutableList.of(
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", ownerId),
submitLabel("Code-Review", "NEED", null))));
update.putApproval("Other-Label", (short) 1);
update.putApprovalFor(ownerId, "Code-Review", (short) 2);
update.commit();
update = newUpdate(c, otherUser);
update.putApproval("Other-Label", (short) 2);
update.commit();
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> approvals = Lists.newArrayList(notes.getApprovals().values());
assertThat(approvals).hasSize(3);
assertThat(approvals.get(0).accountId()).isEqualTo(ownerId);
assertThat(approvals.get(0).label()).isEqualTo("Verified");
assertThat(approvals.get(0).value()).isEqualTo(1);
assertThat(approvals.get(0).postSubmit()).isFalse();
assertThat(approvals.get(1).accountId()).isEqualTo(ownerId);
assertThat(approvals.get(1).label()).isEqualTo("Code-Review");
assertThat(approvals.get(1).value()).isEqualTo(2);
assertThat(approvals.get(1).postSubmit()).isFalse(); // During submit.
assertThat(approvals.get(2).accountId()).isEqualTo(otherId);
assertThat(approvals.get(2).label()).isEqualTo("Other-Label");
assertThat(approvals.get(2).value()).isEqualTo(2);
assertThat(approvals.get(2).postSubmit()).isTrue();
}
@Test
public void multipleReviewers() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.putReviewer(otherUser.getAccount().id(), REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
Timestamp ts = new Timestamp(update.getWhen().getTime());
assertThat(notes.getReviewers())
.isEqualTo(
ReviewerSet.fromTable(
ImmutableTable.<ReviewerStateInternal, Account.Id, Timestamp>builder()
.put(REVIEWER, Account.id(1), ts)
.put(REVIEWER, Account.id(2), ts)
.build()));
}
@Test
public void reviewerTypes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.putReviewer(otherUser.getAccount().id(), CC);
update.commit();
ChangeNotes notes = newNotes(c);
Timestamp ts = new Timestamp(update.getWhen().getTime());
assertThat(notes.getReviewers())
.isEqualTo(
ReviewerSet.fromTable(
ImmutableTable.<ReviewerStateInternal, Account.Id, Timestamp>builder()
.put(REVIEWER, Account.id(1), ts)
.put(CC, Account.id(2), ts)
.build()));
}
@Test
public void oneReviewerMultipleTypes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccount().id(), REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
Timestamp ts = new Timestamp(update.getWhen().getTime());
assertThat(notes.getReviewers())
.isEqualTo(ReviewerSet.fromTable(ImmutableTable.of(REVIEWER, Account.id(2), ts)));
update = newUpdate(c, otherUser);
update.putReviewer(otherUser.getAccount().id(), CC);
update.commit();
notes = newNotes(c);
ts = new Timestamp(update.getWhen().getTime());
assertThat(notes.getReviewers())
.isEqualTo(ReviewerSet.fromTable(ImmutableTable.of(CC, Account.id(2), ts)));
}
@Test
public void removeReviewer() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccount().id(), REVIEWER);
update.commit();
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
update = newUpdate(c, otherUser);
update.putApproval("Code-Review", (short) 1);
update.commit();
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> psas = notes.getApprovals().get(c.currentPatchSetId());
assertThat(psas).hasSize(2);
assertThat(psas.get(0).accountId()).isEqualTo(changeOwner.getAccount().id());
assertThat(psas.get(1).accountId()).isEqualTo(otherUser.getAccount().id());
update = newUpdate(c, changeOwner);
update.removeReviewer(otherUser.getAccount().id());
update.commit();
notes = newNotes(c);
psas = notes.getApprovals().get(c.currentPatchSetId());
assertThat(psas).hasSize(1);
assertThat(psas.get(0).accountId()).isEqualTo(changeOwner.getAccount().id());
}
@Test
public void submitRecords() throws Exception {
Change c = newChange();
SubmissionId submissionId = new SubmissionId(c);
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubjectForCommit("Submit patch set 1");
update.merge(
submissionId,
ImmutableList.of(
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Code-Review", "NEED", null)),
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Alternative-Code-Review", "NEED", null))));
update.commit();
ChangeNotes notes = newNotes(c);
List<SubmitRecord> recs = notes.getSubmitRecords();
assertThat(recs).hasSize(2);
assertThat(recs.get(0))
.isEqualTo(
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Code-Review", "NEED", null)));
assertThat(recs.get(1))
.isEqualTo(
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Alternative-Code-Review", "NEED", null)));
assertThat(notes.getChange().getSubmissionId()).isEqualTo(submissionId.toString());
}
@Test
public void latestSubmitRecordsOnly() throws Exception {
Change c = newChange();
SubmissionId submissionId = new SubmissionId(c);
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubjectForCommit("Submit patch set 1");
update.merge(
submissionId,
ImmutableList.of(
submitRecord("OK", null, submitLabel("Code-Review", "OK", otherUser.getAccountId()))));
update.commit();
incrementPatchSet(c);
update = newUpdate(c, changeOwner);
update.setSubjectForCommit("Submit patch set 2");
update.merge(
submissionId,
ImmutableList.of(
submitRecord(
"OK", null, submitLabel("Code-Review", "OK", changeOwner.getAccountId()))));
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getSubmitRecords())
.containsExactly(
submitRecord("OK", null, submitLabel("Code-Review", "OK", changeOwner.getAccountId())));
assertThat(notes.getChange().getSubmissionId()).isEqualTo(submissionId.toString());
}
@Test
public void emptyChangeUpdate() throws Exception {
Change c = newChange();
Ref initial = repo.exactRef(changeMetaRef(c.getId()));
assertThat(initial).isNotNull();
// Empty update doesn't create a new commit.
ChangeUpdate update = newUpdate(c, changeOwner);
update.commit();
assertThat(update.getResult()).isNull();
Ref updated = repo.exactRef(changeMetaRef(c.getId()));
assertThat(updated.getObjectId()).isEqualTo(initial.getObjectId());
}
@Test
public void assigneeCommit() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setAssignee(otherUserId);
ObjectId result = update.commit();
assertThat(result).isNotNull();
try (RevWalk rw = new RevWalk(repo)) {
RevCommit commit = rw.parseCommit(update.getResult());
rw.parseBody(commit);
String strIdent = "Gerrit User " + otherUserId + " <" + otherUserId + "@" + serverId + ">";
assertThat(commit.getFullMessage()).contains("Assignee: " + strIdent);
}
}
@Test
public void assigneeChangeNotes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setAssignee(otherUserId);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getAssignee()).isEqualTo(otherUserId);
update = newUpdate(c, changeOwner);
update.setAssignee(changeOwner.getAccountId());
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getAssignee()).isEqualTo(changeOwner.getAccountId());
}
@Test
public void pastAssigneesChangeNotes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setAssignee(otherUserId);
update.commit();
update = newUpdate(c, changeOwner);
update.setAssignee(changeOwner.getAccountId());
update.commit();
update = newUpdate(c, changeOwner);
update.setAssignee(otherUserId);
update.commit();
update = newUpdate(c, changeOwner);
update.removeAssignee();
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getPastAssignees()).hasSize(2);
}
@Test
public void assigneeStatusUpdateChangeNotes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
update.setAssignee(otherUserId);
update.commit();
update = newUpdate(c, changeOwner);
update.removeAssignee();
update.commit();
update = newUpdate(c, changeOwner);
update.setAssignee(changeOwner.getAccountId());
update.commit();
update = newUpdate(c, changeOwner);
update.setAssignee(otherUserId);
update.commit();
ChangeNotes notes = newNotes(c);
ImmutableList<AssigneeStatusUpdate> statusUpdates = notes.getAssigneeUpdates();
assertThat(statusUpdates).hasSize(4);
assertThat(statusUpdates.get(3).updatedBy()).isEqualTo(otherUserId);
assertThat(statusUpdates.get(3).currentAssignee()).hasValue(otherUserId);
assertThat(statusUpdates.get(2).currentAssignee()).isEmpty();
assertThat(statusUpdates.get(1).currentAssignee()).hasValue(changeOwner.getAccountId());
assertThat(statusUpdates.get(0).currentAssignee()).hasValue(otherUserId);
}
@Test
public void hashtagCommit() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
LinkedHashSet<String> hashtags = new LinkedHashSet<>();
hashtags.add("tag1");
hashtags.add("tag2");
update.setHashtags(hashtags);
update.commit();
try (RevWalk walk = new RevWalk(repo)) {
RevCommit commit = walk.parseCommit(update.getResult());
walk.parseBody(commit);
assertThat(commit.getFullMessage()).contains("Hashtags: tag1,tag2\n");
}
}
@Test
public void hashtagChangeNotes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
LinkedHashSet<String> hashtags = new LinkedHashSet<>();
hashtags.add("tag1");
hashtags.add("tag2");
update.setHashtags(hashtags);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getHashtags()).isEqualTo(hashtags);
}
@Test
public void topicChangeNotes() throws Exception {
Change c = newChange();
// initially topic is not set
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isNull();
// set topic
String topic = "myTopic";
ChangeUpdate update = newUpdate(c, changeOwner);
update.setTopic(topic);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isEqualTo(topic);
// clear topic by setting empty string
update = newUpdate(c, changeOwner);
update.setTopic("");
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isNull();
// set other topic
topic = "otherTopic";
update = newUpdate(c, changeOwner);
update.setTopic(topic);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isEqualTo(topic);
// clear topic by setting null
update = newUpdate(c, changeOwner);
update.setTopic(null);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isNull();
}
@Test
public void changeIdChangeNotes() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getKey()).isEqualTo(c.getKey());
// An update doesn't affect the Change-Id
ChangeUpdate update = newUpdate(c, changeOwner);
update.setTopic("topic"); // Change something to get a new commit.
update.commit();
assertThat(notes.getChange().getKey()).isEqualTo(c.getKey());
// Trying to set another Change-Id fails
String otherChangeId = "I577fb248e474018276351785930358ec0450e9f7";
ChangeUpdate failingUpdate = newUpdate(c, changeOwner);
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class, () -> failingUpdate.setChangeId(otherChangeId));
assertThat(thrown)
.hasMessageThat()
.contains(
"The Change-Id was already set to "
+ c.getKey()
+ ", so we cannot set this Change-Id: "
+ otherChangeId);
}
@Test
public void branchChangeNotes() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
BranchNameKey expectedBranch = BranchNameKey.create(project, "refs/heads/master");
assertThat(notes.getChange().getDest()).isEqualTo(expectedBranch);
// An update doesn't affect the branch
ChangeUpdate update = newUpdate(c, changeOwner);
update.setTopic("topic"); // Change something to get a new commit.
update.commit();
assertThat(newNotes(c).getChange().getDest()).isEqualTo(expectedBranch);
// Set another branch
String otherBranch = "refs/heads/stable";
update = newUpdate(c, changeOwner);
update.setBranch(otherBranch);
update.commit();
assertThat(newNotes(c).getChange().getDest())
.isEqualTo(BranchNameKey.create(project, otherBranch));
}
@Test
public void ownerChangeNotes() throws Exception {
Change c = newChange();
assertThat(newNotes(c).getChange().getOwner()).isEqualTo(changeOwner.getAccountId());
// An update doesn't affect the owner
ChangeUpdate update = newUpdate(c, otherUser);
update.setTopic("topic"); // Change something to get a new commit.
update.commit();
assertThat(newNotes(c).getChange().getOwner()).isEqualTo(changeOwner.getAccountId());
}
@Test
public void createdOnChangeNotes() throws Exception {
Change c = newChange();
Timestamp createdOn = newNotes(c).getChange().getCreatedOn();
assertThat(createdOn).isNotNull();
// An update doesn't affect the createdOn timestamp.
ChangeUpdate update = newUpdate(c, changeOwner);
update.setTopic("topic"); // Change something to get a new commit.
update.commit();
assertThat(newNotes(c).getChange().getCreatedOn()).isEqualTo(createdOn);
}
@Test
public void lastUpdatedOnChangeNotes() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
Timestamp ts1 = notes.getChange().getLastUpdatedOn();
assertThat(ts1).isEqualTo(notes.getChange().getCreatedOn());
// Various kinds of updates that update the timestamp.
ChangeUpdate update = newUpdate(c, changeOwner);
update.setTopic("topic"); // Change something to get a new commit.
update.commit();
Timestamp ts2 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts2).isGreaterThan(ts1);
update = newUpdate(c, changeOwner);
update.setChangeMessage("Some message");
update.commit();
Timestamp ts3 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts3).isGreaterThan(ts2);
update = newUpdate(c, changeOwner);
update.setHashtags(ImmutableSet.of("foo"));
update.commit();
Timestamp ts4 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts4).isGreaterThan(ts3);
incrementPatchSet(c);
Timestamp ts5 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts5).isGreaterThan(ts4);
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
Timestamp ts6 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts6).isGreaterThan(ts5);
update = newUpdate(c, changeOwner);
update.setStatus(Change.Status.ABANDONED);
update.commit();
Timestamp ts7 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts7).isGreaterThan(ts6);
update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccountId(), ReviewerStateInternal.REVIEWER);
update.commit();
Timestamp ts8 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts8).isGreaterThan(ts7);
update = newUpdate(c, changeOwner);
update.setGroups(ImmutableList.of("a", "b"));
update.commit();
Timestamp ts9 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts9).isGreaterThan(ts8);
// Finish off by merging the change.
update = newUpdate(c, changeOwner);
update.merge(
new SubmissionId(c),
ImmutableList.of(
submitRecord(
"NOT_READY",
null,
submitLabel("Verified", "OK", changeOwner.getAccountId()),
submitLabel("Alternative-Code-Review", "NEED", null))));
update.commit();
Timestamp ts10 = newNotes(c).getChange().getLastUpdatedOn();
assertThat(ts10).isGreaterThan(ts9);
}
@Test
public void subjectLeadingWhitespaceChangeNotes() throws Exception {
Change c = TestChanges.newChange(project, changeOwner.getAccountId());
String trimmedSubj = c.getSubject();
c.setCurrentPatchSet(c.currentPatchSetId(), " " + trimmedSubj, c.getOriginalSubject());
ChangeUpdate update = newUpdateForNewChange(c, changeOwner);
update.setChangeId(c.getKey().get());
update.setBranch(c.getDest().branch());
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getSubject()).isEqualTo(trimmedSubj);
String tabSubj = "\t\t" + trimmedSubj;
c = TestChanges.newChange(project, changeOwner.getAccountId());
c.setCurrentPatchSet(c.currentPatchSetId(), tabSubj, c.getOriginalSubject());
update = newUpdateForNewChange(c, changeOwner);
update.setChangeId(c.getKey().get());
update.setBranch(c.getDest().branch());
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getSubject()).isEqualTo(tabSubj);
}
@Test
public void commitChangeNotesUnique() throws Exception {
// PatchSetId -> ObjectId must be a one to one mapping
Change c = newChange();
ChangeNotes notes = newNotes(c);
PatchSet ps = notes.getCurrentPatchSet();
assertThat(ps).isNotNull();
// new revId for the same patch set, ps1
ChangeUpdate update = newUpdate(c, changeOwner);
RevCommit commit = tr.commit().message("PS1 again").create();
update.setCommit(rw, commit);
update.commit();
StorageException e = assertThrows(StorageException.class, () -> newNotes(c));
assertCause(
e,
ConfigInvalidException.class,
"Multiple revisions parsed for patch set 1:"
+ " "
+ commit.name()
+ " and "
+ ps.commitId().name());
}
@Test
public void patchSetChangeNotes() throws Exception {
Change c = newChange();
// ps1 created by newChange()
ChangeNotes notes = newNotes(c);
PatchSet ps1 = notes.getCurrentPatchSet();
assertThat(notes.getChange().currentPatchSetId()).isEqualTo(ps1.id());
assertThat(notes.getChange().getSubject()).isEqualTo("Change subject");
assertThat(notes.getChange().getOriginalSubject()).isEqualTo("Change subject");
assertThat(ps1.id()).isEqualTo(PatchSet.id(c.getId(), 1));
assertThat(ps1.uploader()).isEqualTo(changeOwner.getAccountId());
// ps2 by other user
RevCommit commit = incrementPatchSet(c, otherUser);
notes = newNotes(c);
PatchSet ps2 = notes.getCurrentPatchSet();
assertThat(ps2.id()).isEqualTo(PatchSet.id(c.getId(), 2));
assertThat(notes.getChange().getSubject()).isEqualTo("PS2");
assertThat(notes.getChange().getOriginalSubject()).isEqualTo("Change subject");
assertThat(notes.getChange().currentPatchSetId()).isEqualTo(ps2.id());
assertThat(ps2.commitId()).isNotEqualTo(ps1.commitId());
assertThat(ps2.commitId()).isEqualTo(commit);
assertThat(ps2.uploader()).isEqualTo(otherUser.getAccountId());
assertThat(ps2.createdOn()).isEqualTo(notes.getChange().getLastUpdatedOn());
// comment on ps1, current patch set is still ps2
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPatchSetId(ps1.id());
update.setChangeMessage("Comment on old patch set.");
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().currentPatchSetId()).isEqualTo(ps2.id());
}
@Test
public void patchSetStates() throws Exception {
Change c = newChange();
PatchSet.Id psId1 = c.currentPatchSetId();
incrementCurrentPatchSetFieldOnly(c);
PatchSet.Id psId2 = c.currentPatchSetId();
RevCommit commit = tr.commit().message("PS2").create();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setCommit(rw, commit);
update.putApproval("Code-Review", (short) 1);
update.setChangeMessage("This is a message");
update.putComment(
Comment.Status.PUBLISHED,
newComment(
c.currentPatchSetId(),
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
TimeUtil.nowTs(),
"Comment",
(short) 1,
commit,
false));
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getPatchSets().keySet()).containsExactly(psId1, psId2);
assertThat(notes.getApprovals()).isNotEmpty();
assertThat(notes.getChangeMessages()).isNotEmpty();
assertThat(notes.getComments()).isNotEmpty();
// publish ps2
update = newUpdate(c, changeOwner);
update.setPatchSetState(PatchSetState.PUBLISHED);
update.commit();
// delete ps2
update = newUpdate(c, changeOwner);
update.setPatchSetState(PatchSetState.DELETED);
update.commit();
notes = newNotes(c);
assertThat(notes.getPatchSets().keySet()).containsExactly(psId1);
assertThat(notes.getApprovals()).isEmpty();
assertThat(notes.getChangeMessages()).isEmpty();
assertThat(notes.getComments()).isEmpty();
}
@Test
public void patchSetGroups() throws Exception {
Change c = newChange();
PatchSet.Id psId1 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
assertThat(notes.getPatchSets().get(psId1).groups()).isEmpty();
// ps1
ChangeUpdate update = newUpdate(c, changeOwner);
update.setGroups(ImmutableList.of("a", "b"));
update.commit();
notes = newNotes(c);
assertThat(notes.getPatchSets().get(psId1).groups()).containsExactly("a", "b").inOrder();
incrementCurrentPatchSetFieldOnly(c);
PatchSet.Id psId2 = c.currentPatchSetId();
update = newUpdate(c, changeOwner);
update.setCommit(rw, tr.commit().message("PS2").create());
update.setGroups(ImmutableList.of("d"));
update.commit();
notes = newNotes(c);
assertThat(notes.getPatchSets().get(psId2).groups()).containsExactly("d");
assertThat(notes.getPatchSets().get(psId1).groups()).containsExactly("a", "b").inOrder();
}
@Test
public void pushCertificate() throws Exception {
String pushCert =
"certificate version 0.1\n"
+ "pusher This is not a real push cert\n"
+ "-----BEGIN PGP SIGNATURE-----\n"
+ "Version: GnuPG v1\n"
+ "\n"
+ "Nor is this a real signature.\n"
+ "-----END PGP SIGNATURE-----\n";
// ps2 with push cert
Change c = newChange();
PatchSet.Id psId1 = c.currentPatchSetId();
incrementCurrentPatchSetFieldOnly(c);
PatchSet.Id psId2 = c.currentPatchSetId();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPatchSetId(psId2);
RevCommit commit = tr.commit().message("PS2").create();
update.setCommit(rw, commit, pushCert);
update.commit();
ChangeNotes notes = newNotes(c);
readNote(notes, commit);
Map<PatchSet.Id, PatchSet> patchSets = notes.getPatchSets();
assertThat(patchSets.get(psId1).pushCertificate()).isEmpty();
assertThat(patchSets.get(psId2).pushCertificate()).hasValue(pushCert);
assertThat(notes.getComments()).isEmpty();
// comment on ps2
update = newUpdate(c, changeOwner);
update.setPatchSetId(psId2);
Timestamp ts = TimeUtil.nowTs();
update.putComment(
Comment.Status.PUBLISHED,
newComment(
psId2,
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
ts,
"Comment",
(short) 1,
commit,
false));
update.commit();
notes = newNotes(c);
patchSets = notes.getPatchSets();
assertThat(patchSets.get(psId1).pushCertificate()).isEmpty();
assertThat(patchSets.get(psId2).pushCertificate()).hasValue(pushCert);
assertThat(notes.getComments()).isNotEmpty();
}
@Test
public void emptyExceptSubject() throws Exception {
ChangeUpdate update = newUpdate(newChange(), changeOwner);
update.setSubjectForCommit("Create change");
assertThat(update.commit()).isNotNull();
}
@Test
public void multipleUpdatesInManager() throws Exception {
Change c = newChange();
ChangeUpdate update1 = newUpdate(c, changeOwner);
update1.putApproval("Verified", (short) 1);
ChangeUpdate update2 = newUpdate(c, otherUser);
update2.putApproval("Code-Review", (short) 2);
try (NoteDbUpdateManager updateManager = updateManagerFactory.create(project)) {
updateManager.add(update1);
updateManager.add(update2);
updateManager.execute();
}
ChangeNotes notes = newNotes(c);
List<PatchSetApproval> psas = notes.getApprovals().get(c.currentPatchSetId());
assertThat(psas).hasSize(2);
assertThat(psas.get(0).accountId()).isEqualTo(changeOwner.getAccount().id());
assertThat(psas.get(0).label()).isEqualTo("Verified");
assertThat(psas.get(0).value()).isEqualTo((short) 1);
assertThat(psas.get(1).accountId()).isEqualTo(otherUser.getAccount().id());
assertThat(psas.get(1).label()).isEqualTo("Code-Review");
assertThat(psas.get(1).value()).isEqualTo((short) 2);
}
@Test
public void multipleUpdatesIncludingComments() throws Exception {
Change c = newChange();
ChangeUpdate update1 = newUpdate(c, otherUser);
String uuid1 = "uuid1";
String message1 = "comment 1";
CommentRange range1 = new CommentRange(1, 1, 2, 1);
Timestamp time1 = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
RevCommit tipCommit;
try (NoteDbUpdateManager updateManager = updateManagerFactory.create(project)) {
Comment comment1 =
newComment(
psId,
"file1",
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
time1,
message1,
(short) 0,
ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"),
false);
update1.setPatchSetId(psId);
update1.putComment(Comment.Status.PUBLISHED, comment1);
updateManager.add(update1);
ChangeUpdate update2 = newUpdate(c, otherUser);
update2.putApproval("Code-Review", (short) 2);
updateManager.add(update2);
updateManager.execute();
}
ChangeNotes notes = newNotes(c);
ObjectId tip = notes.getRevision();
tipCommit = rw.parseCommit(tip);
RevCommit commitWithApprovals = tipCommit;
assertThat(commitWithApprovals).isNotNull();
RevCommit commitWithComments = commitWithApprovals.getParent(0);
assertThat(commitWithComments).isNotNull();
try (ChangeNotesRevWalk rw = ChangeNotesCommit.newRevWalk(repo)) {
ChangeNotesParser notesWithComments =
new ChangeNotesParser(
c.getId(), commitWithComments.copy(), rw, changeNoteJson, args.metrics);
ChangeNotesState state = notesWithComments.parseAll();
assertThat(state.approvals()).isEmpty();
assertThat(state.publishedComments()).hasSize(1);
}
try (ChangeNotesRevWalk rw = ChangeNotesCommit.newRevWalk(repo)) {
ChangeNotesParser notesWithApprovals =
new ChangeNotesParser(
c.getId(), commitWithApprovals.copy(), rw, changeNoteJson, args.metrics);
ChangeNotesState state = notesWithApprovals.parseAll();
assertThat(state.approvals()).hasSize(1);
assertThat(state.publishedComments()).hasSize(1);
}
}
@Test
public void multipleUpdatesAcrossRefs() throws Exception {
Change c1 = newChange();
ChangeUpdate update1 = newUpdate(c1, changeOwner);
update1.putApproval("Verified", (short) 1);
Change c2 = newChange();
ChangeUpdate update2 = newUpdate(c2, otherUser);
update2.putApproval("Code-Review", (short) 2);
Ref initial1 = repo.exactRef(update1.getRefName());
assertThat(initial1).isNotNull();
Ref initial2 = repo.exactRef(update2.getRefName());
assertThat(initial2).isNotNull();
try (NoteDbUpdateManager updateManager = updateManagerFactory.create(project)) {
updateManager.add(update1);
updateManager.add(update2);
updateManager.execute();
}
Ref ref1 = repo.exactRef(update1.getRefName());
assertThat(ref1.getObjectId()).isEqualTo(update1.getResult());
assertThat(ref1.getObjectId()).isNotEqualTo(initial1.getObjectId());
Ref ref2 = repo.exactRef(update2.getRefName());
assertThat(ref2.getObjectId()).isEqualTo(update2.getResult());
assertThat(ref2.getObjectId()).isNotEqualTo(initial2.getObjectId());
PatchSetApproval approval1 =
newNotes(c1).getApprovals().get(c1.currentPatchSetId()).iterator().next();
assertThat(approval1.label()).isEqualTo("Verified");
PatchSetApproval approval2 =
newNotes(c2).getApprovals().get(c2.currentPatchSetId()).iterator().next();
assertThat(approval2.label()).isEqualTo("Code-Review");
}
@Test
public void changeMessageOnePatchSet() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.setChangeMessage("Just a little code change.\n");
update.commit();
ChangeNotes notes = newNotes(c);
ChangeMessage cm = Iterables.getOnlyElement(notes.getChangeMessages());
assertThat(cm.getMessage()).isEqualTo("Just a little code change.\n");
assertThat(cm.getAuthor()).isEqualTo(changeOwner.getAccount().id());
assertThat(cm.getPatchSetId()).isEqualTo(c.currentPatchSetId());
}
@Test
public void noChangeMessage() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChangeMessages()).isEmpty();
}
@Test
public void changeMessageWithTrailingDoubleNewline() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setChangeMessage("Testing trailing double newline\n\n");
update.commit();
ChangeNotes notes = newNotes(c);
ChangeMessage cm1 = Iterables.getOnlyElement(notes.getChangeMessages());
assertThat(cm1.getMessage()).isEqualTo("Testing trailing double newline\n\n");
assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().id());
}
@Test
public void changeMessageWithMultipleParagraphs() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setChangeMessage("Testing paragraph 1\n\nTesting paragraph 2\n\nTesting paragraph 3");
update.commit();
ChangeNotes notes = newNotes(c);
ChangeMessage cm1 = Iterables.getOnlyElement(notes.getChangeMessages());
assertThat(cm1.getMessage())
.isEqualTo(
"Testing paragraph 1\n"
+ "\n"
+ "Testing paragraph 2\n"
+ "\n"
+ "Testing paragraph 3");
assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().id());
}
@Test
public void changeMessagesMultiplePatchSets() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.setChangeMessage("This is the change message for the first PS.");
update.commit();
PatchSet.Id ps1 = c.currentPatchSetId();
incrementPatchSet(c);
update = newUpdate(c, changeOwner);
update.setChangeMessage("This is the change message for the second PS.");
update.commit();
PatchSet.Id ps2 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChangeMessages()).hasSize(2);
ChangeMessage cm1 = notes.getChangeMessages().get(0);
assertThat(cm1.getPatchSetId()).isEqualTo(ps1);
assertThat(cm1.getMessage()).isEqualTo("This is the change message for the first PS.");
assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().id());
ChangeMessage cm2 = notes.getChangeMessages().get(1);
assertThat(cm2.getPatchSetId()).isEqualTo(ps2);
assertThat(cm2.getMessage()).isEqualTo("This is the change message for the second PS.");
assertThat(cm2.getAuthor()).isEqualTo(changeOwner.getAccount().id());
assertThat(cm2.getPatchSetId()).isEqualTo(ps2);
}
@Test
public void changeMessageMultipleInOnePatchSet() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.setChangeMessage("First change message.\n");
update.commit();
PatchSet.Id ps1 = c.currentPatchSetId();
update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().id(), REVIEWER);
update.setChangeMessage("Second change message.\n");
update.commit();
ChangeNotes notes = newNotes(c);
List<ChangeMessage> cm = notes.getChangeMessages();
assertThat(cm).hasSize(2);
assertThat(cm.get(0).getMessage()).isEqualTo("First change message.\n");
assertThat(cm.get(0).getAuthor()).isEqualTo(changeOwner.getAccount().id());
assertThat(cm.get(0).getPatchSetId()).isEqualTo(ps1);
assertThat(cm.get(1).getMessage()).isEqualTo("Second change message.\n");
assertThat(cm.get(1).getAuthor()).isEqualTo(changeOwner.getAccount().id());
assertThat(cm.get(1).getPatchSetId()).isEqualTo(ps1);
}
@Test
public void patchLineCommentsFileComment() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
Comment comment =
newComment(
psId,
"file1",
"uuid",
null,
0,
otherUser,
null,
TimeUtil.nowTs(),
"message",
(short) 1,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void patchLineCommentsZeroColumns() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 0, 2, 0);
Comment comment =
newComment(
psId,
"file1",
"uuid",
range,
range.getEndLine(),
otherUser,
null,
TimeUtil.nowTs(),
"message",
(short) 1,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void patchLineCommentZeroRange() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(0, 0, 0, 0);
Comment comment =
newComment(
psId,
"file",
"uuid",
range,
range.getEndLine(),
otherUser,
null,
TimeUtil.nowTs(),
"message",
(short) 1,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void patchLineCommentEmptyFilename() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 2, 3, 4);
Comment comment =
newComment(
psId,
"",
"uuid",
range,
range.getEndLine(),
otherUser,
null,
TimeUtil.nowTs(),
"message",
(short) 1,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void patchLineCommentNotesFormatMultiplePatchSetsSameCommitId() throws Exception {
Change c = newChange();
PatchSet.Id psId1 = c.currentPatchSetId();
incrementPatchSet(c);
PatchSet.Id psId2 = c.currentPatchSetId();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String uuid3 = "uuid3";
String message1 = "comment 1";
String message2 = "comment 2";
String message3 = "comment 3";
CommentRange range1 = new CommentRange(1, 1, 2, 1);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
Timestamp time = TimeUtil.nowTs();
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
Comment comment1 =
newComment(
psId1,
"file1",
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
time,
message1,
(short) 0,
commitId,
false);
Comment comment2 =
newComment(
psId1,
"file1",
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
time,
message2,
(short) 0,
commitId,
false);
Comment comment3 =
newComment(
psId2,
"file1",
uuid3,
range1,
range1.getEndLine(),
otherUser,
null,
time,
message3,
(short) 0,
commitId,
false);
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId2);
update.putComment(Comment.Status.PUBLISHED, comment3);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments())
.isEqualTo(
ImmutableListMultimap.of(
commitId, comment1,
commitId, comment2,
commitId, comment3));
}
@Test
public void patchLineCommentNotesFormatRealAuthor() throws Exception {
Change c = newChange();
CurrentUser ownerAsOtherUser = userFactory.runAs(null, otherUserId, changeOwner);
ChangeUpdate update = newUpdate(c, ownerAsOtherUser);
String uuid = "uuid";
String message = "comment";
CommentRange range = new CommentRange(1, 1, 2, 1);
Timestamp time = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
Comment comment =
newComment(
psId,
"file",
uuid,
range,
range.getEndLine(),
otherUser,
null,
time,
message,
(short) 1,
commitId,
false);
comment.setRealAuthor(changeOwner.getAccountId());
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void patchLineCommentNotesFormatWeirdUser() throws Exception {
Account.Builder account = Account.builder(Account.id(3), TimeUtil.nowTs());
account.setFullName("Weird\n\u0002<User>\n");
account.setPreferredEmail(" we\r\nird@ex>ample<.com");
accountCache.put(account.build());
IdentifiedUser user = userFactory.create(Account.id(3));
Change c = newChange();
ChangeUpdate update = newUpdate(c, user);
String uuid = "uuid";
CommentRange range = new CommentRange(1, 1, 2, 1);
Timestamp time = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment comment =
newComment(
psId,
"file1",
uuid,
range,
range.getEndLine(),
user,
null,
time,
"comment",
(short) 1,
ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"),
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments())
.isEqualTo(ImmutableListMultimap.of(comment.getCommitId(), comment));
}
@Test
public void patchLineCommentMultipleOnePatchsetOneFileBothSides() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid1 = "uuid1";
String uuid2 = "uuid2";
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
ObjectId commitId2 = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
String messageForBase = "comment for base";
String messageForPS = "comment for ps";
CommentRange range = new CommentRange(1, 1, 2, 1);
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment commentForBase =
newComment(
psId,
"filename",
uuid1,
range,
range.getEndLine(),
otherUser,
null,
now,
messageForBase,
(short) 0,
commitId1,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, commentForBase);
update.commit();
update = newUpdate(c, otherUser);
Comment commentForPS =
newComment(
psId,
"filename",
uuid2,
range,
range.getEndLine(),
otherUser,
null,
now,
messageForPS,
(short) 1,
commitId2,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, commentForPS);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId1, commentForBase,
commitId2, commentForPS));
}
@Test
public void patchLineCommentMultipleOnePatchsetOneFile() throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id psId = c.currentPatchSetId();
String filename = "filename";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp timeForComment1 = TimeUtil.nowTs();
Timestamp timeForComment2 = TimeUtil.nowTs();
Comment comment1 =
newComment(
psId,
filename,
uuid1,
range,
range.getEndLine(),
otherUser,
null,
timeForComment1,
"comment 1",
side,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
Comment comment2 =
newComment(
psId,
filename,
uuid2,
range,
range.getEndLine(),
otherUser,
null,
timeForComment2,
"comment 2",
side,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId, comment1,
commitId, comment2))
.inOrder();
}
@Test
public void patchLineCommentMultipleOnePatchsetMultipleFiles() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id psId = c.currentPatchSetId();
String filename1 = "filename1";
String filename2 = "filename2";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
psId,
filename1,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment 1",
side,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
Comment comment2 =
newComment(
psId,
filename2,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment 2",
side,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId, comment1,
commitId, comment2))
.inOrder();
}
@Test
public void patchLineCommentMultiplePatchsets() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
ObjectId commitId2 = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
ps1,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId1,
false);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
incrementPatchSet(c);
PatchSet.Id ps2 = c.currentPatchSetId();
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
Comment comment2 =
newComment(
ps2,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps2",
side,
commitId2,
false);
update.setPatchSetId(ps2);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId1, comment1,
commitId2, comment2));
}
@Test
public void patchLineCommentSingleDraftToPublished() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
ps1,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId,
false);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.DRAFT, comment1);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(ImmutableListMultimap.of(commitId, comment1));
assertThat(notes.getComments()).isEmpty();
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(commitId, comment1));
}
@Test
public void patchLineCommentMultipleDraftsSameSidePublishOne() throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
ObjectId commitId = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range1 = new CommentRange(1, 1, 2, 2);
CommentRange range2 = new CommentRange(2, 2, 3, 3);
String filename = "filename1";
short side = (short) 1;
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
// Write two drafts on the same side of one patch set.
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
Comment comment1 =
newComment(
psId,
filename,
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId,
false);
Comment comment2 =
newComment(
psId,
filename,
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
now,
"other on ps1",
side,
commitId,
false);
update.putComment(Comment.Status.DRAFT, comment1);
update.putComment(Comment.Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId, comment1,
commitId, comment2))
.inOrder();
assertThat(notes.getComments()).isEmpty();
// Publish first draft.
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(ImmutableListMultimap.of(commitId, comment2));
assertThat(notes.getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(commitId, comment1));
}
@Test
public void patchLineCommentsMultipleDraftsBothSidesPublishAll() throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
ObjectId commitId2 = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range1 = new CommentRange(1, 1, 2, 2);
CommentRange range2 = new CommentRange(2, 2, 3, 3);
String filename = "filename1";
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
// Write two drafts, one on each side of the patchset.
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
Comment baseComment =
newComment(
psId,
filename,
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
now,
"comment on base",
(short) 0,
commitId1,
false);
Comment psComment =
newComment(
psId,
filename,
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
now,
"comment on ps",
(short) 1,
commitId2,
false);
update.putComment(Comment.Status.DRAFT, baseComment);
update.putComment(Comment.Status.DRAFT, psComment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId1, baseComment,
commitId2, psComment));
assertThat(notes.getComments()).isEmpty();
// Publish both comments.
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, baseComment);
update.putComment(Comment.Status.PUBLISHED, psComment);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
commitId1, baseComment,
commitId2, psComment));
}
@Test
public void patchLineCommentsDeleteAllDrafts() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id psId = c.currentPatchSetId();
String filename = "filename";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment =
newComment(
psId,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.DRAFT, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(1);
assertThat(notes.getDraftCommentNotes().getNoteMap().contains(commitId)).isTrue();
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
update.deleteComment(comment);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getDraftCommentNotes().getNoteMap()).isNull();
}
@Test
public void patchLineCommentsDeleteAllDraftsForOneRevision() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
ObjectId commitId2 = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
ps1,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId1,
false);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.DRAFT, comment1);
update.commit();
incrementPatchSet(c);
PatchSet.Id ps2 = c.currentPatchSetId();
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
Comment comment2 =
newComment(
ps2,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps2",
side,
commitId2,
false);
update.setPatchSetId(ps2);
update.putComment(Comment.Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(2);
update = newUpdate(c, otherUser);
update.setPatchSetId(ps2);
update.deleteComment(comment2);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(1);
NoteMap noteMap = notes.getDraftCommentNotes().getNoteMap();
assertThat(noteMap.contains(commitId1)).isTrue();
assertThat(noteMap.contains(commitId2)).isFalse();
}
@Test
public void addingPublishedCommentDoesNotCreateNoOpCommitOnEmptyDraftRef() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment =
newComment(
ps1,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId,
false);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
assertThat(repo.exactRef(changeMetaRef(c.getId()))).isNotNull();
String draftRef = refsDraftComments(c.getId(), otherUser.getAccountId());
assertThat(exactRefAllUsers(draftRef)).isNull();
}
@Test
public void addingPublishedCommentDoesNotCreateNoOpCommitOnNonEmptyDraftRef() throws Exception {
Change c = newChange();
ObjectId commitId = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment draft =
newComment(
ps1,
filename,
"uuid1",
range,
range.getEndLine(),
otherUser,
null,
now,
"draft comment on ps1",
side,
commitId,
false);
update.putComment(Comment.Status.DRAFT, draft);
update.commit();
String draftRef = refsDraftComments(c.getId(), otherUser.getAccountId());
ObjectId old = exactRefAllUsers(draftRef);
assertThat(old).isNotNull();
update = newUpdate(c, otherUser);
Comment pub =
newComment(
ps1,
filename,
"uuid2",
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId,
false);
update.putComment(Comment.Status.PUBLISHED, pub);
update.commit();
assertThat(exactRefAllUsers(draftRef)).isEqualTo(old);
}
@Test
public void fileComment() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid = "uuid";
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
String messageForBase = "comment for base";
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment comment =
newComment(
psId,
"filename",
uuid,
null,
0,
otherUser,
null,
now,
messageForBase,
(short) 0,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void patchLineCommentNoRange() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid = "uuid";
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
String messageForBase = "comment for base";
Timestamp now = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment comment =
newComment(
psId,
"filename",
uuid,
null,
1,
otherUser,
null,
now,
messageForBase,
(short) 0,
commitId,
false);
update.setPatchSetId(psId);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(commitId, comment));
}
@Test
public void putCommentsForMultipleRevisions() throws Exception {
Change c = newChange();
String uuid = "uuid";
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
ObjectId commitId2 = ObjectId.fromString("abcd4567abcd4567abcd4567abcd4567abcd4567");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
String filename = "filename1";
short side = (short) 1;
incrementPatchSet(c);
PatchSet.Id ps2 = c.currentPatchSetId();
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(ps2);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
ps1,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId1,
false);
Comment comment2 =
newComment(
ps2,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps2",
side,
commitId2,
false);
update.putComment(Comment.Status.DRAFT, comment1);
update.putComment(Comment.Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(2);
assertThat(notes.getComments()).isEmpty();
update = newUpdate(c, otherUser);
update.setPatchSetId(ps2);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments()).hasSize(2);
}
@Test
public void publishSubsetOfCommentsOnRevision() throws Exception {
Change c = newChange();
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
ps1,
"file1",
"uuid1",
range,
range.getEndLine(),
otherUser,
null,
now,
"comment1",
side,
commitId1,
false);
Comment comment2 =
newComment(
ps1,
"file2",
"uuid2",
range,
range.getEndLine(),
otherUser,
null,
now,
"comment2",
side,
commitId1,
false);
update.putComment(Comment.Status.DRAFT, comment1);
update.putComment(Comment.Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId).get(commitId1))
.containsExactly(comment1, comment2);
assertThat(notes.getComments()).isEmpty();
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId).get(commitId1)).containsExactly(comment1);
assertThat(notes.getComments().get(commitId1)).containsExactly(comment2);
}
@Test
public void updateWithServerIdent() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, internalUser);
update.setChangeMessage("A message.");
update.commit();
ChangeMessage msg = Iterables.getLast(newNotes(c).getChangeMessages());
assertThat(msg.getMessage()).isEqualTo("A message.");
assertThat(msg.getAuthor()).isNull();
ChangeUpdate failingUpdate = newUpdate(c, internalUser);
assertThrows(
IllegalStateException.class, () -> failingUpdate.putApproval("Code-Review", (short) 1));
}
@Test
public void filterOutAndFixUpZombieDraftComments() throws Exception {
Change c = newChange();
ObjectId commitId1 = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 1, 2, 1);
PatchSet.Id ps1 = c.currentPatchSetId();
short side = (short) 1;
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(
ps1,
"file1",
"uuid1",
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps1",
side,
commitId1,
false);
Comment comment2 =
newComment(
ps1,
"file2",
"uuid2",
range,
range.getEndLine(),
otherUser,
null,
now,
"another comment",
side,
commitId1,
false);
update.putComment(Comment.Status.DRAFT, comment1);
update.putComment(Comment.Status.DRAFT, comment2);
update.commit();
String refName = refsDraftComments(c.getId(), otherUserId);
ObjectId oldDraftId = exactRefAllUsers(refName);
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.PUBLISHED, comment2);
update.commit();
assertThat(exactRefAllUsers(refName)).isNotNull();
assertThat(exactRefAllUsers(refName)).isNotEqualTo(oldDraftId);
// Re-add draft version of comment2 back to draft ref without updating
// change ref. Simulates the case where deleting the draft failed
// non-atomically after adding the published comment succeeded.
ChangeDraftUpdate draftUpdate = newUpdate(c, otherUser).createDraftUpdateIfNull();
draftUpdate.putComment(comment2);
try (NoteDbUpdateManager manager = updateManagerFactory.create(c.getProject())) {
manager.add(draftUpdate);
manager.execute();
}
// Looking at drafts directly shows the zombie comment.
DraftCommentNotes draftNotes = draftNotesFactory.create(c.getId(), otherUserId);
assertThat(draftNotes.load().getComments().get(commitId1)).containsExactly(comment1, comment2);
// Zombie comment is filtered out of drafts via ChangeNotes.
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId).get(commitId1)).containsExactly(comment1);
assertThat(notes.getComments().get(commitId1)).containsExactly(comment2);
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(Comment.Status.PUBLISHED, comment1);
update.commit();
// Updating an unrelated comment causes the zombie comment to get fixed up.
assertThat(exactRefAllUsers(refName)).isNull();
}
@Test
public void updateCommentsInSequentialUpdates() throws Exception {
Change c = newChange();
CommentRange range = new CommentRange(1, 1, 2, 1);
ObjectId commitId = ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
ChangeUpdate update1 = newUpdate(c, otherUser);
Comment comment1 =
newComment(
c.currentPatchSetId(),
"filename",
"uuid1",
range,
range.getEndLine(),
otherUser,
null,
new Timestamp(update1.getWhen().getTime()),
"comment 1",
(short) 1,
commitId,
false);
update1.putComment(Comment.Status.PUBLISHED, comment1);
ChangeUpdate update2 = newUpdate(c, otherUser);
Comment comment2 =
newComment(
c.currentPatchSetId(),
"filename",
"uuid2",
range,
range.getEndLine(),
otherUser,
null,
new Timestamp(update2.getWhen().getTime()),
"comment 2",
(short) 1,
commitId,
false);
update2.putComment(Comment.Status.PUBLISHED, comment2);
try (NoteDbUpdateManager manager = updateManagerFactory.create(project)) {
manager.add(update1);
manager.add(update2);
manager.execute();
}
ChangeNotes notes = newNotes(c);
List<Comment> comments = notes.getComments().get(commitId);
assertThat(comments).hasSize(2);
assertThat(comments.get(0).message).isEqualTo("comment 1");
assertThat(comments.get(1).message).isEqualTo("comment 2");
}
@Test
public void realUser() throws Exception {
Change c = newChange();
CurrentUser ownerAsOtherUser = userFactory.runAs(null, otherUserId, changeOwner);
ChangeUpdate update = newUpdate(c, ownerAsOtherUser);
update.setChangeMessage("Message on behalf of other user");
update.commit();
ChangeMessage msg = Iterables.getLast(newNotes(c).getChangeMessages());
assertThat(msg.getMessage()).isEqualTo("Message on behalf of other user");
assertThat(msg.getAuthor()).isEqualTo(otherUserId);
assertThat(msg.getRealAuthor()).isEqualTo(changeOwner.getAccountId());
}
@Test
public void ignoreEntitiesBeyondCurrentPatchSet() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
int numMessages = notes.getChangeMessages().size();
int numPatchSets = notes.getPatchSets().size();
int numApprovals = notes.getApprovals().size();
int numComments = notes.getComments().size();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPatchSetId(PatchSet.id(c.getId(), c.currentPatchSetId().get() + 1));
update.setChangeMessage("Should be ignored");
update.putApproval("Code-Review", (short) 2);
CommentRange range = new CommentRange(1, 1, 2, 1);
Comment comment =
newComment(
update.getPatchSetId(),
"filename",
"uuid",
range,
range.getEndLine(),
changeOwner,
null,
new Timestamp(update.getWhen().getTime()),
"comment",
(short) 1,
ObjectId.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"),
false);
update.putComment(Comment.Status.PUBLISHED, comment);
update.commit();
notes = newNotes(c);
assertThat(notes.getChangeMessages()).hasSize(numMessages);
assertThat(notes.getPatchSets()).hasSize(numPatchSets);
assertThat(notes.getApprovals()).hasSize(numApprovals);
assertThat(notes.getComments()).hasSize(numComments);
}
@Test
public void currentPatchSet() throws Exception {
Change c = newChange();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
incrementPatchSet(c);
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPatchSetId(PatchSet.id(c.getId(), 1));
update.setCurrentPatchSet();
update.commit();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
incrementPatchSet(c);
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(3);
// Delete PS3, PS1 becomes current, as the most recent event explicitly set
// it to current.
update = newUpdate(c, changeOwner);
update.setPatchSetState(PatchSetState.DELETED);
update.commit();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
// Delete PS1, PS2 becomes current.
update = newUpdate(c, changeOwner);
update.setPatchSetId(PatchSet.id(c.getId(), 1));
update.setPatchSetState(PatchSetState.DELETED);
update.commit();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
}
@Test
public void privateDefault() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().isPrivate()).isFalse();
}
@Test
public void privateSetPrivate() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPrivate(true);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().isPrivate()).isTrue();
}
@Test
public void privateSetPrivateMultipleTimes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPrivate(true);
update.commit();
update = newUpdate(c, changeOwner);
update.setPrivate(false);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().isPrivate()).isFalse();
}
@Test
public void defaultReviewersByEmailIsEmpty() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
assertThat(notes.getReviewersByEmail().all()).isEmpty();
}
@Test
public void putReviewerByEmail() throws Exception {
Address adr = new Address("Foo Bar", "foo.bar@gerritcodereview.com");
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adr, ReviewerStateInternal.REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getReviewersByEmail().all()).containsExactly(adr);
}
@Test
public void putAndRemoveReviewerByEmail() throws Exception {
Address adr = new Address("Foo Bar", "foo.bar@gerritcodereview.com");
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adr, ReviewerStateInternal.REVIEWER);
update.commit();
update = newUpdate(c, changeOwner);
update.removeReviewerByEmail(adr);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getReviewersByEmail().all()).isEmpty();
}
@Test
public void putRemoveAndAddBackReviewerByEmail() throws Exception {
Address adr = new Address("Foo Bar", "foo.bar@gerritcodereview.com");
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adr, ReviewerStateInternal.REVIEWER);
update.commit();
update = newUpdate(c, changeOwner);
update.removeReviewerByEmail(adr);
update.commit();
update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adr, ReviewerStateInternal.CC);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getReviewersByEmail().all()).containsExactly(adr);
}
@Test
public void putReviewerByEmailAndCcByEmail() throws Exception {
Address adrReviewer = new Address("Foo Bar", "foo.bar@gerritcodereview.com");
Address adrCc = new Address("Foo Bor", "foo.bar.2@gerritcodereview.com");
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adrReviewer, ReviewerStateInternal.REVIEWER);
update.commit();
update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adrCc, ReviewerStateInternal.CC);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getReviewersByEmail().byState(ReviewerStateInternal.REVIEWER))
.containsExactly(adrReviewer);
assertThat(notes.getReviewersByEmail().byState(ReviewerStateInternal.CC))
.containsExactly(adrCc);
assertThat(notes.getReviewersByEmail().all()).containsExactly(adrReviewer, adrCc);
}
@Test
public void putReviewerByEmailAndChangeToCc() throws Exception {
Address adr = new Address("Foo Bar", "foo.bar@gerritcodereview.com");
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adr, ReviewerStateInternal.REVIEWER);
update.commit();
update = newUpdate(c, changeOwner);
update.putReviewerByEmail(adr, ReviewerStateInternal.CC);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getReviewersByEmail().byState(ReviewerStateInternal.REVIEWER)).isEmpty();
assertThat(notes.getReviewersByEmail().byState(ReviewerStateInternal.CC)).containsExactly(adr);
assertThat(notes.getReviewersByEmail().all()).containsExactly(adr);
}
@Test
public void hasReviewStarted() throws Exception {
ChangeNotes notes = newNotes(newChange());
assertThat(notes.getChange().hasReviewStarted()).isTrue();
notes = newNotes(newWorkInProgressChange());
assertThat(notes.getChange().hasReviewStarted()).isFalse();
Change c = newWorkInProgressChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().hasReviewStarted()).isFalse();
update = newUpdate(c, changeOwner);
update.setWorkInProgress(true);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().hasReviewStarted()).isFalse();
update = newUpdate(c, changeOwner);
update.setWorkInProgress(false);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().hasReviewStarted()).isTrue();
// Once review is started, setting WIP should have no impact.
c = newChange();
notes = newNotes(c);
assertThat(notes.getChange().hasReviewStarted()).isTrue();
update = newUpdate(c, changeOwner);
update.setWorkInProgress(true);
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().hasReviewStarted()).isTrue();
}
@Test
public void pendingReviewers() throws Exception {
Address adr1 = new Address("Foo Bar1", "foo.bar1@gerritcodereview.com");
Address adr2 = new Address("Foo Bar2", "foo.bar2@gerritcodereview.com");
Account.Id ownerId = changeOwner.getAccount().id();
Account.Id otherUserId = otherUser.getAccount().id();
ChangeNotes notes = newNotes(newChange());
assertThat(notes.getPendingReviewers().asTable()).isEmpty();
assertThat(notes.getPendingReviewersByEmail().asTable()).isEmpty();
Change c = newWorkInProgressChange();
notes = newNotes(c);
assertThat(notes.getPendingReviewers().asTable()).isEmpty();
assertThat(notes.getPendingReviewersByEmail().asTable()).isEmpty();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(ownerId, REVIEWER);
update.putReviewer(otherUserId, CC);
update.putReviewerByEmail(adr1, REVIEWER);
update.putReviewerByEmail(adr2, CC);
update.commit();
notes = newNotes(c);
assertThat(notes.getPendingReviewers().byState(REVIEWER)).containsExactly(ownerId);
assertThat(notes.getPendingReviewers().byState(CC)).containsExactly(otherUserId);
assertThat(notes.getPendingReviewers().byState(REMOVED)).isEmpty();
assertThat(notes.getPendingReviewersByEmail().byState(REVIEWER)).containsExactly(adr1);
assertThat(notes.getPendingReviewersByEmail().byState(CC)).containsExactly(adr2);
assertThat(notes.getPendingReviewersByEmail().byState(REMOVED)).isEmpty();
update = newUpdate(c, changeOwner);
update.removeReviewer(ownerId);
update.removeReviewerByEmail(adr1);
update.commit();
notes = newNotes(c);
assertThat(notes.getPendingReviewers().byState(REVIEWER)).isEmpty();
assertThat(notes.getPendingReviewers().byState(CC)).containsExactly(otherUserId);
assertThat(notes.getPendingReviewers().byState(REMOVED)).containsExactly(ownerId);
assertThat(notes.getPendingReviewersByEmail().byState(REVIEWER)).isEmpty();
assertThat(notes.getPendingReviewersByEmail().byState(CC)).containsExactly(adr2);
assertThat(notes.getPendingReviewersByEmail().byState(REMOVED)).containsExactly(adr1);
update = newUpdate(c, changeOwner);
update.setWorkInProgress(false);
update.commit();
notes = newNotes(c);
assertThat(notes.getPendingReviewers().asTable()).isEmpty();
assertThat(notes.getPendingReviewersByEmail().asTable()).isEmpty();
update = newUpdate(c, changeOwner);
update.putReviewer(ownerId, REVIEWER);
update.putReviewerByEmail(adr1, REVIEWER);
update.commit();
notes = newNotes(c);
assertThat(notes.getPendingReviewers().asTable()).isEmpty();
assertThat(notes.getPendingReviewersByEmail().asTable()).isEmpty();
}
@Test
public void revertOfIsNullByDefault() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getRevertOf()).isNull();
}
@Test
public void setRevertOfPersistsValue() throws Exception {
Change changeToRevert = newChange();
Change c = TestChanges.newChange(project, changeOwner.getAccountId());
ChangeUpdate update = newUpdateForNewChange(c, changeOwner);
update.setChangeId(c.getKey().get());
update.setRevertOf(changeToRevert.getId().get());
update.commit();
assertThat(newNotes(c).getChange().getRevertOf()).isEqualTo(changeToRevert.getId());
}
@Test
public void setRevertOfToCurrentChangeFails() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> update.setRevertOf(c.getId().get()));
assertThat(thrown).hasMessageThat().contains("A change cannot revert itself");
}
@Test
public void setRevertOfOnChildCommitFails() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setRevertOf(newChange().getId().get());
StorageException thrown = assertThrows(StorageException.class, () -> update.commit());
assertThat(thrown)
.hasMessageThat()
.contains("Given ChangeUpdate is only allowed on initial commit");
}
@Test
public void updateCount() throws Exception {
Change c = newChange();
assertThat(newNotes(c).getUpdateCount()).isEqualTo(1);
ChangeUpdate update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) -1);
update.commit();
assertThat(newNotes(c).getUpdateCount()).isEqualTo(2);
update = newUpdate(c, changeOwner);
update.putApproval("Code-Review", (short) 1);
update.commit();
assertThat(newNotes(c).getUpdateCount()).isEqualTo(3);
}
@Test
public void createPatchSetAfterPatchSetDeletion() throws Exception {
Change c = newChange();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
// Create PS2.
incrementCurrentPatchSetFieldOnly(c);
RevCommit commit = tr.commit().message("PS" + c.currentPatchSetId().get()).create();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setCommit(rw, commit);
update.setGroups(ImmutableList.of(commit.name()));
update.commit();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
// Delete PS2.
update = newUpdate(c, changeOwner);
update.setPatchSetState(PatchSetState.DELETED);
update.commit();
c = newNotes(c).getChange();
assertThat(c.currentPatchSetId().get()).isEqualTo(1);
// Create another PS2
incrementCurrentPatchSetFieldOnly(c);
commit = tr.commit().message("PS" + c.currentPatchSetId().get()).create();
update = newUpdate(c, changeOwner);
update.setPatchSetState(PatchSetState.PUBLISHED);
update.setCommit(rw, commit);
update.setGroups(ImmutableList.of(commit.name()));
update.commit();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
}
private String readNote(ChangeNotes notes, ObjectId noteId) throws Exception {
ObjectId dataId = notes.revisionNoteMap.noteMap.getNote(noteId).getData();
return new String(rw.getObjectReader().open(dataId, OBJ_BLOB).getCachedBytes(), UTF_8);
}
private ObjectId exactRefAllUsers(String refName) throws Exception {
try (Repository allUsersRepo = repoManager.openRepository(allUsers)) {
Ref ref = allUsersRepo.exactRef(refName);
return ref != null ? ref.getObjectId() : null;
}
}
private void assertCause(
Throwable e, Class<? extends Throwable> expectedClass, String expectedMsg) {
Throwable cause = null;
for (Throwable t : Throwables.getCausalChain(e)) {
if (expectedClass.isAssignableFrom(t.getClass())) {
cause = t;
break;
}
}
assertWithMessage(
expectedClass.getSimpleName()
+ " in causal chain of:\n"
+ Throwables.getStackTraceAsString(e))
.that(cause)
.isNotNull();
assertThat(cause.getMessage()).isEqualTo(expectedMsg);
}
private void incrementCurrentPatchSetFieldOnly(Change c) {
TestChanges.incrementPatchSet(c);
}
private RevCommit incrementPatchSet(Change c) throws Exception {
return incrementPatchSet(c, userFactory.create(c.getOwner()));
}
private RevCommit incrementPatchSet(Change c, IdentifiedUser user) throws Exception {
incrementCurrentPatchSetFieldOnly(c);
RevCommit commit = tr.commit().message("PS" + c.currentPatchSetId().get()).create();
ChangeUpdate update = newUpdate(c, user);
update.setCommit(rw, commit);
update.commit();
return tr.parseBody(commit);
}
}