blob: 9d6cb60a733c8cc8cb210002460e04316c8dca56 [file] [log] [blame]
// 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.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
import static com.google.gerrit.reviewdb.client.RefNames.refsDraftComments;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.CC;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.junit.Assert.fail;
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.TimeUtil;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.Comment;
import com.google.gerrit.reviewdb.client.CommentRange;
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDbUtil;
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.RequestId;
import com.google.gerrit.testutil.TestChanges;
import com.google.gerrit.testutil.TestTimeUtil;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.notes.Note;
import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.Test;
public class ChangeNotesTest extends AbstractChangeNotesTest {
@Inject private DraftCommentNotes.Factory draftNotesFactory;
@Inject private ChangeNoteUtil noteUtil;
@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().getDescription()).isEqualTo(description);
description = "new, now more descriptive!";
update = newUpdate(c, changeOwner);
update.setPsDescription(description);
update.commit();
notes = newNotes(c);
assertThat(notes.getCurrentPatchSet().getDescription()).isEqualTo(description);
}
@Test
public void tagInlineCommenrts() throws Exception {
String tag = "jenkins";
Change c = newChange();
RevCommit commit = tr.commit().message("PS2").create();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putComment(
Status.PUBLISHED,
newComment(
c.currentPatchSetId(),
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
TimeUtil.nowTs(),
"Comment",
(short) 1,
commit.name(),
false));
update.setTag(tag);
update.commit();
ChangeNotes notes = newNotes(c);
ImmutableListMultimap<RevId, 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().getTag()).isEqualTo(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(
Status.PUBLISHED,
newComment(
c.currentPatchSetId(),
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
TimeUtil.nowTs(),
"Comment",
(short) 1,
commit.name(),
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.getTag()).isEqualTo(integrationTag);
assertThat(approval.getValue()).isEqualTo(-1);
ImmutableListMultimap<RevId, 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).getPatchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(0).getAccountId().get()).isEqualTo(1);
assertThat(psas.get(0).getLabel()).isEqualTo("Code-Review");
assertThat(psas.get(0).getValue()).isEqualTo((short) -1);
assertThat(psas.get(0).getGranted()).isEqualTo(truncate(after(c, 2000)));
assertThat(psas.get(1).getPatchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(1).getAccountId().get()).isEqualTo(1);
assertThat(psas.get(1).getLabel()).isEqualTo("Verified");
assertThat(psas.get(1).getValue()).isEqualTo((short) 1);
assertThat(psas.get(1).getGranted()).isEqualTo(psas.get(0).getGranted());
}
@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.getPatchSetId()).isEqualTo(ps1);
assertThat(psa1.getAccountId().get()).isEqualTo(1);
assertThat(psa1.getLabel()).isEqualTo("Code-Review");
assertThat(psa1.getValue()).isEqualTo((short) -1);
assertThat(psa1.getGranted()).isEqualTo(truncate(after(c, 2000)));
PatchSetApproval psa2 = Iterables.getOnlyElement(psas.get(ps2));
assertThat(psa2.getPatchSetId()).isEqualTo(ps2);
assertThat(psa2.getAccountId().get()).isEqualTo(1);
assertThat(psa2.getLabel()).isEqualTo("Code-Review");
assertThat(psa2.getValue()).isEqualTo((short) +1);
assertThat(psa2.getGranted()).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.getLabel()).isEqualTo("Code-Review");
assertThat(psa.getValue()).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.getLabel()).isEqualTo("Code-Review");
assertThat(psa.getValue()).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).getPatchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(0).getAccountId().get()).isEqualTo(1);
assertThat(psas.get(0).getLabel()).isEqualTo("Code-Review");
assertThat(psas.get(0).getValue()).isEqualTo((short) -1);
assertThat(psas.get(0).getGranted()).isEqualTo(truncate(after(c, 2000)));
assertThat(psas.get(1).getPatchSetId()).isEqualTo(c.currentPatchSetId());
assertThat(psas.get(1).getAccountId().get()).isEqualTo(2);
assertThat(psas.get(1).getLabel()).isEqualTo("Code-Review");
assertThat(psas.get(1).getValue()).isEqualTo((short) 1);
assertThat(psas.get(1).getGranted()).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.getAccountId().get()).isEqualTo(1);
assertThat(psa.getLabel()).isEqualTo("Not-For-Long");
assertThat(psa.getValue()).isEqualTo((short) 1);
update = newUpdate(c, changeOwner);
update.removeApproval("Not-For-Long");
update.commit();
notes = newNotes(c);
assertThat(notes.getApprovals())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
psa.getPatchSetId(),
new PatchSetApproval(psa.getKey(), (short) 0, update.getWhen())));
}
@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.getAccountId()).isEqualTo(otherUserId);
assertThat(psa.getLabel()).isEqualTo("Not-For-Long");
assertThat(psa.getValue()).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.getPatchSetId(),
new PatchSetApproval(psa.getKey(), (short) 0, update.getWhen())));
// 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.getAccountId()).isEqualTo(otherUserId);
assertThat(psa.getLabel()).isEqualTo("Not-For-Long");
assertThat(psa.getValue()).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);
List<PatchSetApproval> approvals =
ReviewDbUtil.intKeyOrdering()
.onResultOf(PatchSetApproval::getAccountId)
.sortedCopy(notes.getApprovals().get(c.currentPatchSetId()));
assertThat(approvals).hasSize(2);
assertThat(approvals.get(0).getAccountId()).isEqualTo(changeOwner.getAccountId());
assertThat(approvals.get(0).getLabel()).isEqualTo("Code-Review");
assertThat(approvals.get(0).getValue()).isEqualTo((short) 1);
assertThat(approvals.get(1).getAccountId()).isEqualTo(otherUser.getAccountId());
assertThat(approvals.get(1).getLabel()).isEqualTo("Code-Review");
assertThat(approvals.get(1).getValue()).isEqualTo((short) -1);
}
@Test
public void approvalsPostSubmit() throws Exception {
Change c = newChange();
RequestId submissionId = RequestId.forChange(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).getLabel()).isEqualTo("Verified");
assertThat(approvals.get(0).getValue()).isEqualTo((short) 1);
assertThat(approvals.get(0).isPostSubmit()).isFalse();
assertThat(approvals.get(1).getLabel()).isEqualTo("Code-Review");
assertThat(approvals.get(1).getValue()).isEqualTo((short) 2);
assertThat(approvals.get(1).isPostSubmit()).isTrue();
}
@Test
public void approvalsDuringSubmit() throws Exception {
Change c = newChange();
RequestId submissionId = RequestId.forChange(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).getAccountId()).isEqualTo(ownerId);
assertThat(approvals.get(0).getLabel()).isEqualTo("Verified");
assertThat(approvals.get(0).getValue()).isEqualTo(1);
assertThat(approvals.get(0).isPostSubmit()).isFalse();
assertThat(approvals.get(1).getAccountId()).isEqualTo(ownerId);
assertThat(approvals.get(1).getLabel()).isEqualTo("Code-Review");
assertThat(approvals.get(1).getValue()).isEqualTo(2);
assertThat(approvals.get(1).isPostSubmit()).isFalse(); // During submit.
assertThat(approvals.get(2).getAccountId()).isEqualTo(otherId);
assertThat(approvals.get(2).getLabel()).isEqualTo("Other-Label");
assertThat(approvals.get(2).getValue()).isEqualTo(2);
assertThat(approvals.get(2).isPostSubmit()).isTrue();
}
@Test
public void multipleReviewers() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.putReviewer(otherUser.getAccount().getId(), 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, new Account.Id(1), ts)
.put(REVIEWER, new Account.Id(2), ts)
.build()));
}
@Test
public void reviewerTypes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.putReviewer(otherUser.getAccount().getId(), 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, new Account.Id(1), ts)
.put(CC, new Account.Id(2), ts)
.build()));
}
@Test
public void oneReviewerMultipleTypes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccount().getId(), REVIEWER);
update.commit();
ChangeNotes notes = newNotes(c);
Timestamp ts = new Timestamp(update.getWhen().getTime());
assertThat(notes.getReviewers())
.isEqualTo(ReviewerSet.fromTable(ImmutableTable.of(REVIEWER, new Account.Id(2), ts)));
update = newUpdate(c, otherUser);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
notes = newNotes(c);
ts = new Timestamp(update.getWhen().getTime());
assertThat(notes.getReviewers())
.isEqualTo(ReviewerSet.fromTable(ImmutableTable.of(CC, new Account.Id(2), ts)));
}
@Test
public void removeReviewer() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(otherUser.getAccount().getId(), 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).getAccountId()).isEqualTo(changeOwner.getAccount().getId());
assertThat(psas.get(1).getAccountId()).isEqualTo(otherUser.getAccount().getId());
update = newUpdate(c, changeOwner);
update.removeReviewer(otherUser.getAccount().getId());
update.commit();
notes = newNotes(c);
psas = notes.getApprovals().get(c.currentPatchSetId());
assertThat(psas).hasSize(1);
assertThat(psas.get(0).getAccountId()).isEqualTo(changeOwner.getAccount().getId());
}
@Test
public void submitRecords() throws Exception {
Change c = newChange();
RequestId submissionId = RequestId.forChange(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.toStringForStorage());
}
@Test
public void latestSubmitRecordsOnly() throws Exception {
Change c = newChange();
RequestId submissionId = RequestId.forChange(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.toStringForStorage());
}
@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 = otherUser.getName() + " <" + 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();
ChangeNotes notes = newNotes(c);
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();
notes = newNotes(c);
assertThat(notes.getPastAssignees()).hasSize(2);
}
@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()).endsWith("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";
update = newUpdate(c, changeOwner);
exception.expect(IllegalArgumentException.class);
exception.expectMessage(
"The Change-Id was already set to "
+ c.getKey()
+ ", so we cannot set this Change-Id: "
+ otherChangeId);
update.setChangeId(otherChangeId);
}
@Test
public void branchChangeNotes() throws Exception {
Change c = newChange();
ChangeNotes notes = newNotes(c);
Branch.NameKey expectedBranch = new Branch.NameKey(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(new Branch.NameKey(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(
RequestId.forChange(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 = newUpdate(c, changeOwner);
update.setChangeId(c.getKey().get());
update.setBranch(c.getDest().get());
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 = newUpdate(c, changeOwner);
update.setChangeId(c.getKey().get());
update.setBranch(c.getDest().get());
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().getSubject()).isEqualTo(tabSubj);
}
@Test
public void commitChangeNotesUnique() throws Exception {
// PatchSetId -> RevId 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();
try {
notes = newNotes(c);
fail("Expected IOException");
} catch (OrmException e) {
assertCause(
e,
ConfigInvalidException.class,
"Multiple revisions parsed for patch set 1:"
+ " RevId{"
+ commit.name()
+ "} and "
+ ps.getRevision().get());
}
}
@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.getId());
assertThat(notes.getChange().getSubject()).isEqualTo("Change subject");
assertThat(notes.getChange().getOriginalSubject()).isEqualTo("Change subject");
assertThat(ps1.getId()).isEqualTo(new PatchSet.Id(c.getId(), 1));
assertThat(ps1.getUploader()).isEqualTo(changeOwner.getAccountId());
// ps2 by other user
RevCommit commit = incrementPatchSet(c, otherUser);
notes = newNotes(c);
PatchSet ps2 = notes.getCurrentPatchSet();
assertThat(ps2.getId()).isEqualTo(new PatchSet.Id(c.getId(), 2));
assertThat(notes.getChange().getSubject()).isEqualTo("PS2");
assertThat(notes.getChange().getOriginalSubject()).isEqualTo("Change subject");
assertThat(notes.getChange().currentPatchSetId()).isEqualTo(ps2.getId());
assertThat(ps2.getRevision().get()).isNotEqualTo(ps1.getRevision());
assertThat(ps2.getRevision().get()).isEqualTo(commit.name());
assertThat(ps2.getUploader()).isEqualTo(otherUser.getAccountId());
assertThat(ps2.getCreatedOn()).isEqualTo(notes.getChange().getLastUpdatedOn());
// comment on ps1, current patch set is still ps2
ChangeUpdate update = newUpdate(c, changeOwner);
update.setPatchSetId(ps1.getId());
update.setChangeMessage("Comment on old patch set.");
update.commit();
notes = newNotes(c);
assertThat(notes.getChange().currentPatchSetId()).isEqualTo(ps2.getId());
}
@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.setPatchSetState(PatchSetState.DRAFT);
update.putApproval("Code-Review", (short) 1);
update.setChangeMessage("This is a message");
update.putComment(
Status.PUBLISHED,
newComment(
c.currentPatchSetId(),
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
TimeUtil.nowTs(),
"Comment",
(short) 1,
commit.name(),
false));
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getPatchSets().get(psId2).isDraft()).isTrue();
assertThat(notes.getPatchSets().keySet()).containsExactly(psId1, psId2);
assertThat(notes.getApprovals()).isNotEmpty();
assertThat(notes.getChangeMessagesByPatchSet()).isNotEmpty();
assertThat(notes.getChangeMessages()).isNotEmpty();
assertThat(notes.getComments()).isNotEmpty();
// publish ps2
update = newUpdate(c, changeOwner);
update.setPatchSetState(PatchSetState.PUBLISHED);
update.commit();
notes = newNotes(c);
assertThat(notes.getPatchSets().get(psId2).isDraft()).isFalse();
// 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.getChangeMessagesByPatchSet()).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).getGroups()).isEmpty();
// ps1
ChangeUpdate update = newUpdate(c, changeOwner);
update.setGroups(ImmutableList.of("a", "b"));
update.commit();
notes = newNotes(c);
assertThat(notes.getPatchSets().get(psId1).getGroups()).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).getGroups()).containsExactly("d");
assertThat(notes.getPatchSets().get(psId1).getGroups()).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);
String note = readNote(notes, commit);
if (!testJson()) {
assertThat(note).isEqualTo(pushCert);
}
Map<PatchSet.Id, PatchSet> patchSets = notes.getPatchSets();
assertThat(patchSets.get(psId1).getPushCertificate()).isNull();
assertThat(patchSets.get(psId2).getPushCertificate()).isEqualTo(pushCert);
assertThat(notes.getComments()).isEmpty();
// comment on ps2
update = newUpdate(c, changeOwner);
update.setPatchSetId(psId2);
Timestamp ts = TimeUtil.nowTs();
update.putComment(
Status.PUBLISHED,
newComment(
psId2,
"a.txt",
"uuid1",
new CommentRange(1, 2, 3, 4),
1,
changeOwner,
null,
ts,
"Comment",
(short) 1,
commit.name(),
false));
update.commit();
notes = newNotes(c);
patchSets = notes.getPatchSets();
assertThat(patchSets.get(psId1).getPushCertificate()).isNull();
assertThat(patchSets.get(psId2).getPushCertificate()).isEqualTo(pushCert);
assertThat(notes.getComments()).isNotEmpty();
if (!testJson()) {
assertThat(readNote(notes, commit))
.isEqualTo(
pushCert
+ "Revision: "
+ commit.name()
+ "\n"
+ "Patch-set: 2\n"
+ "File: a.txt\n"
+ "\n"
+ "1:2-3:4\n"
+ ChangeNoteUtil.formatTime(serverIdent, ts)
+ "\n"
+ "Author: Change Owner <1@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 7\n"
+ "Comment\n"
+ "\n");
}
}
@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).getAccountId()).isEqualTo(changeOwner.getAccount().getId());
assertThat(psas.get(0).getLabel()).isEqualTo("Verified");
assertThat(psas.get(0).getValue()).isEqualTo((short) 1);
assertThat(psas.get(1).getAccountId()).isEqualTo(otherUser.getAccount().getId());
assertThat(psas.get(1).getLabel()).isEqualTo("Code-Review");
assertThat(psas.get(1).getValue()).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,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update1.setPatchSetId(psId);
update1.putComment(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, noteUtil, 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, noteUtil, 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.getLabel()).isEqualTo("Verified");
PatchSetApproval approval2 =
newNotes(c2).getApprovals().get(c2.currentPatchSetId()).iterator().next();
assertThat(approval2.getLabel()).isEqualTo("Code-Review");
}
@Test
public void changeMessageOnePatchSet() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.setChangeMessage("Just a little code change.\n");
update.commit();
PatchSet.Id ps1 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages = notes.getChangeMessagesByPatchSet();
assertThat(changeMessages.keySet()).containsExactly(ps1);
ChangeMessage cm = Iterables.getOnlyElement(changeMessages.get(ps1));
assertThat(cm.getMessage()).isEqualTo("Just a little code change.\n");
assertThat(cm.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
assertThat(cm.getPatchSetId()).isEqualTo(ps1);
}
@Test
public void noChangeMessage() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), 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();
PatchSet.Id ps1 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages = notes.getChangeMessagesByPatchSet();
assertThat(changeMessages).hasSize(1);
ChangeMessage cm1 = Iterables.getOnlyElement(changeMessages.get(ps1));
assertThat(cm1.getMessage()).isEqualTo("Testing trailing double newline\n\n");
assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
}
@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();
PatchSet.Id ps1 = c.currentPatchSetId();
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages = notes.getChangeMessagesByPatchSet();
assertThat(changeMessages).hasSize(1);
ChangeMessage cm1 = Iterables.getOnlyElement(changeMessages.get(ps1));
assertThat(cm1.getMessage())
.isEqualTo(
"Testing paragraph 1\n"
+ "\n"
+ "Testing paragraph 2\n"
+ "\n"
+ "Testing paragraph 3");
assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
}
@Test
public void changeMessagesMultiplePatchSets() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), 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);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages = notes.getChangeMessagesByPatchSet();
assertThat(changeMessages).hasSize(2);
ChangeMessage cm1 = Iterables.getOnlyElement(changeMessages.get(ps1));
assertThat(cm1.getMessage()).isEqualTo("This is the change message for the first PS.");
assertThat(cm1.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
ChangeMessage cm2 = Iterables.getOnlyElement(changeMessages.get(ps2));
assertThat(cm1.getPatchSetId()).isEqualTo(ps1);
assertThat(cm2.getMessage()).isEqualTo("This is the change message for the second PS.");
assertThat(cm2.getAuthor()).isEqualTo(changeOwner.getAccount().getId());
assertThat(cm2.getPatchSetId()).isEqualTo(ps2);
}
@Test
public void changeMessageMultipleInOnePatchSet() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.setChangeMessage("First change message.\n");
update.commit();
PatchSet.Id ps1 = c.currentPatchSetId();
update = newUpdate(c, changeOwner);
update.putReviewer(changeOwner.getAccount().getId(), REVIEWER);
update.setChangeMessage("Second change message.\n");
update.commit();
ChangeNotes notes = newNotes(c);
ListMultimap<PatchSet.Id, ChangeMessage> changeMessages = notes.getChangeMessagesByPatchSet();
assertThat(changeMessages.keySet()).hasSize(1);
List<ChangeMessage> cm = changeMessages.get(ps1);
assertThat(cm).hasSize(2);
assertThat(cm.get(0).getMessage()).isEqualTo("First change message.\n");
assertThat(cm.get(0).getAuthor()).isEqualTo(changeOwner.getAccount().getId());
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().getId());
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();
RevId revId = new RevId("abcd1234abcd1234abcd1234abcd1234abcd1234");
Comment comment =
newComment(
psId,
"file1",
"uuid",
null,
0,
otherUser,
null,
TimeUtil.nowTs(),
"message",
(short) 1,
revId.get(),
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(revId, comment));
}
@Test
public void patchLineCommentsZeroColumns() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
RevId revId = new RevId("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,
revId.get(),
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(revId, comment));
}
@Test
public void patchLineCommentZeroRange() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
RevId revId = new RevId("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,
revId.get(),
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(revId, comment));
}
@Test
public void patchLineCommentEmptyFilename() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
PatchSet.Id psId = c.currentPatchSetId();
RevId revId = new RevId("abcd1234abcd1234abcd1234abcd1234abcd1234");
CommentRange range = new CommentRange(1, 2, 3, 4);
Comment comment =
newComment(
psId,
"",
"uuid",
range,
range.getEndLine(),
otherUser,
null,
TimeUtil.nowTs(),
"message",
(short) 1,
revId.get(),
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(revId, comment));
}
@Test
public void patchLineCommentNotesFormatSide1() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
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);
Timestamp time1 = TimeUtil.nowTs();
Timestamp time2 = TimeUtil.nowTs();
Timestamp time3 = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment comment1 =
newComment(
psId,
"file1",
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
time1,
message1,
(short) 1,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
Comment comment2 =
newComment(
psId,
"file1",
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
time2,
message2,
(short) 1,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
update = newUpdate(c, otherUser);
CommentRange range3 = new CommentRange(3, 0, 4, 1);
Comment comment3 =
newComment(
psId,
"file2",
uuid3,
range3,
range3.getEndLine(),
otherUser,
null,
time3,
message3,
(short) 1,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment3);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree = Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes = walk.getObjectReader().open(note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
if (!testJson()) {
assertThat(noteString)
.isEqualTo(
"Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "Patch-set: 1\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time1)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
+ "\n"
+ "2:1-3:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time2)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
+ "\n"
+ "File: file2\n"
+ "\n"
+ "3:0-4:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time3)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid3\n"
+ "Bytes: 9\n"
+ "comment 3\n"
+ "\n");
}
}
}
@Test
public void patchLineCommentNotesFormatSide0() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String message1 = "comment 1";
String message2 = "comment 2";
CommentRange range1 = new CommentRange(1, 1, 2, 1);
Timestamp time1 = TimeUtil.nowTs();
Timestamp time2 = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment comment1 =
newComment(
psId,
"file1",
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
time1,
message1,
(short) 0,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
Comment comment2 =
newComment(
psId,
"file1",
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
time2,
message2,
(short) 0,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree = Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes = walk.getObjectReader().open(note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
if (!testJson()) {
assertThat(noteString)
.isEqualTo(
"Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "Base-for-patch-set: 1\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time1)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
+ "\n"
+ "2:1-3:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time2)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
+ "\n");
}
}
}
@Test
public void patchLineCommentNotesResolvedChangesValue() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String message1 = "comment 1";
String message2 = "comment 2";
CommentRange range1 = new CommentRange(1, 1, 2, 1);
Timestamp time1 = TimeUtil.nowTs();
Timestamp time2 = TimeUtil.nowTs();
PatchSet.Id psId = c.currentPatchSetId();
Comment comment1 =
newComment(
psId,
"file1",
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
time1,
message1,
(short) 0,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
Comment comment2 =
newComment(
psId,
"file1",
uuid2,
range1,
range1.getEndLine(),
otherUser,
uuid1,
time2,
message2,
(short) 0,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
true);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree = Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes = walk.getObjectReader().open(note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
if (!testJson()) {
assertThat(noteString)
.isEqualTo(
"Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "Base-for-patch-set: 1\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time1)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
+ "\n"
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time2)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Parent: uuid1\n"
+ "Unresolved: true\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
+ "\n");
}
}
}
@Test
public void patchLineCommentNotesFormatMultiplePatchSetsSameRevId() 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();
RevId revId = new RevId("abcd1234abcd1234abcd1234abcd1234abcd1234");
Comment comment1 =
newComment(
psId1,
"file1",
uuid1,
range1,
range1.getEndLine(),
otherUser,
null,
time,
message1,
(short) 0,
revId.get(),
false);
Comment comment2 =
newComment(
psId1,
"file1",
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
time,
message2,
(short) 0,
revId.get(),
false);
Comment comment3 =
newComment(
psId2,
"file1",
uuid3,
range1,
range1.getEndLine(),
otherUser,
null,
time,
message3,
(short) 0,
revId.get(),
false);
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId2);
update.putComment(Status.PUBLISHED, comment3);
update.putComment(Status.PUBLISHED, comment2);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree = Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes = walk.getObjectReader().open(note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
String timeStr = ChangeNoteUtil.formatTime(serverIdent, time);
if (!testJson()) {
assertThat(noteString)
.isEqualTo(
"Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "Base-for-patch-set: 1\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ timeStr
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
+ "\n"
+ "2:1-3:1\n"
+ timeStr
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
+ "\n"
+ "Base-for-patch-set: 2\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ timeStr
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid3\n"
+ "Bytes: 9\n"
+ "comment 3\n"
+ "\n");
}
}
assertThat(notes.getComments())
.isEqualTo(
ImmutableListMultimap.of(
revId, comment1,
revId, comment2,
revId, 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();
RevId revId = new RevId("abcd1234abcd1234abcd1234abcd1234abcd1234");
Comment comment =
newComment(
psId,
"file",
uuid,
range,
range.getEndLine(),
otherUser,
null,
time,
message,
(short) 1,
revId.get(),
false);
comment.setRealAuthor(changeOwner.getAccountId());
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree = Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes = walk.getObjectReader().open(note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
if (!testJson()) {
assertThat(noteString)
.isEqualTo(
"Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "Patch-set: 1\n"
+ "File: file\n"
+ "\n"
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time)
+ "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Real-author: Change Owner <1@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid\n"
+ "Bytes: 7\n"
+ "comment\n"
+ "\n");
}
}
assertThat(notes.getComments()).isEqualTo(ImmutableListMultimap.of(revId, comment));
}
@Test
public void patchLineCommentNotesFormatWeirdUser() throws Exception {
Account account = new Account(new Account.Id(3), TimeUtil.nowTs());
account.setFullName("Weird\n\u0002<User>\n");
account.setPreferredEmail(" we\r\nird@ex>ample<.com");
accountCache.put(account);
IdentifiedUser user = userFactory.create(account.getId());
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,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree = Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes = walk.getObjectReader().open(note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
String timeStr = ChangeNoteUtil.formatTime(serverIdent, time);
if (!testJson()) {
assertThat(noteString)
.isEqualTo(
"Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "Patch-set: 1\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ timeStr
+ "\n"
+ "Author: Weird\u0002User <3@gerrit>\n"
+ "Unresolved: false\n"
+ "UUID: uuid\n"
+ "Bytes: 7\n"
+ "comment\n"
+ "\n");
}
}
assertThat(notes.getComments())
.isEqualTo(ImmutableListMultimap.of(new RevId(comment.revId), comment));
}
@Test
public void patchLineCommentMultipleOnePatchsetOneFileBothSides() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String rev2 = "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,
rev1,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, commentForBase);
update.commit();
update = newUpdate(c, otherUser);
Comment commentForPS =
newComment(
psId,
"filename",
uuid2,
range,
range.getEndLine(),
otherUser,
null,
now,
messageForPS,
(short) 1,
rev2,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, commentForPS);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev1), commentForBase,
new RevId(rev2), commentForPS));
}
@Test
public void patchLineCommentMultipleOnePatchsetOneFile() throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String rev = "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,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
Comment comment2 =
newComment(
psId,
filename,
uuid2,
range,
range.getEndLine(),
otherUser,
null,
timeForComment2,
"comment 2",
side,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev), comment1,
new RevId(rev), comment2))
.inOrder();
}
@Test
public void patchLineCommentMultipleOnePatchsetMultipleFiles() throws Exception {
Change c = newChange();
String uuid = "uuid";
String rev = "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,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
update = newUpdate(c, otherUser);
Comment comment2 =
newComment(
psId,
filename2,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment 2",
side,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev), comment1,
new RevId(rev), comment2))
.inOrder();
}
@Test
public void patchLineCommentMultiplePatchsets() throws Exception {
Change c = newChange();
String uuid = "uuid";
String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String rev2 = "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,
rev1,
false);
update.setPatchSetId(ps1);
update.putComment(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,
rev2,
false);
update.setPatchSetId(ps2);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev1), comment1,
new RevId(rev2), comment2));
}
@Test
public void patchLineCommentSingleDraftToPublished() throws Exception {
Change c = newChange();
String uuid = "uuid";
String rev = "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,
rev,
false);
update.setPatchSetId(ps1);
update.putComment(Status.DRAFT, comment1);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(ImmutableListMultimap.of(new RevId(rev), comment1));
assertThat(notes.getComments()).isEmpty();
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(new RevId(rev), comment1));
}
@Test
public void patchLineCommentMultipleDraftsSameSidePublishOne() throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String rev = "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,
rev,
false);
Comment comment2 =
newComment(
psId,
filename,
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
now,
"other on ps1",
side,
rev,
false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev), comment1,
new RevId(rev), comment2))
.inOrder();
assertThat(notes.getComments()).isEmpty();
// Publish first draft.
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(ImmutableListMultimap.of(new RevId(rev), comment2));
assertThat(notes.getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(new RevId(rev), comment1));
}
@Test
public void patchLineCommentsMultipleDraftsBothSidesPublishAll() throws Exception {
Change c = newChange();
String uuid1 = "uuid1";
String uuid2 = "uuid2";
String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String rev2 = "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,
rev1,
false);
Comment psComment =
newComment(
psId,
filename,
uuid2,
range2,
range2.getEndLine(),
otherUser,
null,
now,
"comment on ps",
(short) 1,
rev2,
false);
update.putComment(Status.DRAFT, baseComment);
update.putComment(Status.DRAFT, psComment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId))
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev1), baseComment,
new RevId(rev2), psComment));
assertThat(notes.getComments()).isEmpty();
// Publish both comments.
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, baseComment);
update.putComment(Status.PUBLISHED, psComment);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments())
.containsExactlyEntriesIn(
ImmutableListMultimap.of(
new RevId(rev1), baseComment,
new RevId(rev2), psComment));
}
@Test
public void patchLineCommentsDeleteAllDrafts() throws Exception {
Change c = newChange();
String uuid = "uuid";
String rev = "abcd1234abcd1234abcd1234abcd1234abcd1234";
ObjectId objId = ObjectId.fromString(rev);
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,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.DRAFT, comment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(1);
assertThat(notes.getDraftCommentNotes().getNoteMap().contains(objId)).isTrue();
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
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";
String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String rev2 = "abcd4567abcd4567abcd4567abcd4567abcd4567";
ObjectId objId1 = ObjectId.fromString(rev1);
ObjectId objId2 = ObjectId.fromString(rev2);
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,
rev1,
false);
update.setPatchSetId(ps1);
update.putComment(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,
rev2,
false);
update.setPatchSetId(ps2);
update.putComment(Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(2);
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
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(objId1)).isTrue();
assertThat(noteMap.contains(objId2)).isFalse();
}
@Test
public void addingPublishedCommentDoesNotCreateNoOpCommitOnEmptyDraftRef() throws Exception {
Change c = newChange();
String uuid = "uuid";
String rev = "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,
rev,
false);
update.putComment(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();
String rev = "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,
rev,
false);
update.putComment(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,
rev,
false);
update.putComment(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";
String rev = "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,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(new RevId(rev), comment));
}
@Test
public void patchLineCommentNoRange() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, otherUser);
String uuid = "uuid";
String rev = "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,
rev,
false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
assertThat(newNotes(c).getComments())
.containsExactlyEntriesIn(ImmutableListMultimap.of(new RevId(rev), comment));
}
@Test
public void putCommentsForMultipleRevisions() throws Exception {
Change c = newChange();
String uuid = "uuid";
String rev1 = "abcd1234abcd1234abcd1234abcd1234abcd1234";
String rev2 = "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,
rev1,
false);
Comment comment2 =
newComment(
ps2,
filename,
uuid,
range,
range.getEndLine(),
otherUser,
null,
now,
"comment on ps2",
side,
rev2,
false);
update.putComment(Status.DRAFT, comment1);
update.putComment(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(Status.PUBLISHED, comment1);
update.putComment(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();
RevId rev1 = new RevId("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,
rev1.get(),
false);
Comment comment2 =
newComment(
ps1,
"file2",
"uuid2",
range,
range.getEndLine(),
otherUser,
null,
now,
"comment2",
side,
rev1.get(),
false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId).get(rev1)).containsExactly(comment1, comment2);
assertThat(notes.getComments()).isEmpty();
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId).get(rev1)).containsExactly(comment1);
assertThat(notes.getComments().get(rev1)).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();
update = newUpdate(c, internalUser);
exception.expect(IllegalStateException.class);
update.putApproval("Code-Review", (short) 1);
}
@Test
public void filterOutAndFixUpZombieDraftComments() throws Exception {
Change c = newChange();
RevId rev1 = new RevId("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,
rev1.get(),
false);
Comment comment2 =
newComment(
ps1,
"file2",
"uuid2",
range,
range.getEndLine(),
otherUser,
null,
now,
"another comment",
side,
rev1.get(),
false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
String refName = refsDraftComments(c.getId(), otherUserId);
ObjectId oldDraftId = exactRefAllUsers(refName);
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(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, otherUserId);
assertThat(draftNotes.load().getComments().get(rev1)).containsExactly(comment1, comment2);
// Zombie comment is filtered out of drafts via ChangeNotes.
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId).get(rev1)).containsExactly(comment1);
assertThat(notes.getComments().get(rev1)).containsExactly(comment2);
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.putComment(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);
String rev = "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,
rev,
false);
update1.putComment(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,
rev,
false);
update2.putComment(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(new RevId(rev));
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(new 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,
"abcd1234abcd1234abcd1234abcd1234abcd1234",
false);
update.putComment(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(new 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(new PatchSet.Id(c.getId(), 1));
update.setPatchSetState(PatchSetState.DELETED);
update.commit();
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
}
@Test
public void readOnlyUntilExpires() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
Timestamp until = new Timestamp(TimeUtil.nowMs() + 10000);
update.setReadOnlyUntil(until);
update.commit();
update = newUpdate(c, changeOwner);
update.setTopic("failing-topic");
try {
update.commit();
assert_().fail("expected OrmException");
} catch (OrmException e) {
assertThat(e.getMessage()).contains("read-only until");
}
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isNotEqualTo("failing-topic");
assertThat(notes.getReadOnlyUntil()).isEqualTo(until);
TestTimeUtil.incrementClock(30, TimeUnit.SECONDS);
update = newUpdate(c, changeOwner);
update.setTopic("succeeding-topic");
update.commit();
// Write succeeded; lease still exists, even though it's expired.
notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isEqualTo("succeeding-topic");
assertThat(notes.getReadOnlyUntil()).isEqualTo(until);
// New lease takes precedence.
update = newUpdate(c, changeOwner);
until = new Timestamp(TimeUtil.nowMs() + 10000);
update.setReadOnlyUntil(until);
update.commit();
assertThat(newNotes(c).getReadOnlyUntil()).isEqualTo(until);
}
@Test
public void readOnlyUntilCleared() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
Timestamp until = new Timestamp(TimeUtil.nowMs() + TimeUnit.DAYS.toMillis(30));
update.setReadOnlyUntil(until);
update.commit();
update = newUpdate(c, changeOwner);
update.setTopic("failing-topic");
try {
update.commit();
assert_().fail("expected OrmException");
} catch (OrmException e) {
assertThat(e.getMessage()).contains("read-only until");
}
// Sentinel timestamp of 0 can be written to clear lease.
update = newUpdate(c, changeOwner);
update.setReadOnlyUntil(new Timestamp(0));
update.commit();
update = newUpdate(c, changeOwner);
update.setTopic("succeeding-topic");
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getChange().getTopic()).isEqualTo("succeeding-topic");
assertThat(notes.getReadOnlyUntil()).isEqualTo(new Timestamp(0));
}
private boolean testJson() {
return noteUtil.getWriteJson();
}
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;
}
}
assertThat(cause)
.named(
expectedClass.getSimpleName()
+ " in causal chain of:\n"
+ Throwables.getStackTraceAsString(e))
.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);
}
}