blob: 4037a6d183901d633f2c9375a1e4ac9415404846 [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.gerrit.server.notedb.ReviewerStateInternal.CC;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static com.google.gerrit.testutil.TestChanges.incrementPatchSet;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
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.CommentRange;
import com.google.gerrit.reviewdb.client.PatchLineComment;
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.server.git.VersionedMetaData.BatchMetaDataUpdate;
import com.google.gwtorm.server.OrmException;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
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.eclipse.jgit.transport.ReceiveCommand;
import org.junit.Test;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
public class ChangeNotesTest extends AbstractChangeNotesTest {
@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, 3000)));
}
@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()).isEmpty();
}
@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()).isEmpty();
// 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 = Ordering.natural().onResultOf(
new Function<PatchSetApproval, Integer>() {
@Override
public Integer apply(PatchSetApproval in) {
return in.getAccountId().get();
}
}).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 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);
assertThat(notes.getReviewers()).isEqualTo(
ImmutableSetMultimap.of(
REVIEWER, new Account.Id(1),
REVIEWER, new Account.Id(2)));
}
@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);
assertThat(notes.getReviewers()).isEqualTo(
ImmutableSetMultimap.of(
REVIEWER, new Account.Id(1),
CC, new Account.Id(2)));
}
@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);
assertThat(notes.getReviewers()).isEqualTo(
ImmutableSetMultimap.of(REVIEWER, new Account.Id(2)));
update = newUpdate(c, otherUser);
update.putReviewer(otherUser.getAccount().getId(), CC);
update.commit();
notes = newNotes(c);
assertThat(notes.getReviewers()).isEqualTo(
ImmutableSetMultimap.of(CC, new Account.Id(2)));
}
@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();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubjectForCommit("Submit patch set 1");
update.merge("1-1453387607626-96fabc25", 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("1-1453387607626-96fabc25");
}
@Test
public void latestSubmitRecordsOnly() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
update.setSubjectForCommit("Submit patch set 1");
update.merge("1-1453387607626-96fabc25", 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("1-1453387901516-5d1e2450", 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("1-1453387901516-5d1e2450");
}
@Test
public void emptyChangeUpdate() throws Exception {
Change c = newChange();
// The initial empty update creates a commit which is needed to track the
// creation time of the change.
ChangeUpdate update = newUpdate(c, changeOwner);
ObjectId revision = update.getRevision();
assertThat(revision).isNotNull();
// Any further empty update doesn't create a new commit.
update = newUpdate(c, changeOwner);
update.commit();
assertThat(update.getRevision()).isEqualTo(revision);
}
@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.getRevision());
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 lastUpdatedOn = notes.getChange().getLastUpdatedOn();
assertThat(lastUpdatedOn).isNotNull();
assertThat(lastUpdatedOn).isEqualTo(notes.getChange().getCreatedOn());
// An update creates a new lastUpdatedOn timestamp.
ChangeUpdate update = newUpdate(c, changeOwner);
update.setTopic("topic"); // Change something to get a new commit.
update.commit();
assertThat(newNotes(c).getChange().getLastUpdatedOn())
.isGreaterThan(lastUpdatedOn);
}
@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();
exception.expect(OrmException.class);
exception.expectMessage("Multiple revisions parsed for patch set");
notes = newNotes(c);
}
@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
incrementPatchSet(c);
RevCommit commit = tr.commit().message("PS2").create();
ChangeUpdate update = newUpdate(c, otherUser);
update.setCommit(rw, commit);
update.commit();
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(update.getWhen());
}
@Test
public void patchSetStates() throws Exception {
Change c = newChange();
PatchSet.Id psId1 = c.currentPatchSetId();
// ps2
incrementPatchSet(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.insertComment(newPublishedComment(c.currentPatchSetId(), "a.txt",
"uuid1", new CommentRange(1, 2, 3, 4), 1, changeOwner, null,
TimeUtil.nowTs(), "Comment", (short) 1, commit.name()));
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();
// ps2
incrementPatchSet(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";
String trimmedCert = CharMatcher.is('\n').trimTrailingFrom(pushCert);
// ps2 with push cert
Change c = newChange();
PatchSet.Id psId1 = c.currentPatchSetId();
incrementPatchSet(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);
assertThat(readNote(notes, commit)).isEqualTo(pushCert);
Map<PatchSet.Id, PatchSet> patchSets = notes.getPatchSets();
assertThat(patchSets.get(psId1).getPushCertificate()).isNull();
assertThat(patchSets.get(psId2).getPushCertificate())
.isEqualTo(trimmedCert);
assertThat(notes.getComments()).isEmpty();
// comment on ps2
update = newUpdate(c, changeOwner);
update.setPatchSetId(psId2);
Timestamp ts = TimeUtil.nowTs();
update.insertComment(newPublishedComment(psId2, "a.txt",
"uuid1", new CommentRange(1, 2, 3, 4), 1, changeOwner, null, ts,
"Comment", (short) 1, commit.name()));
update.commit();
notes = newNotes(c);
assertThat(readNote(notes, commit)).isEqualTo(
pushCert
+ "Patch-set: 2\n"
+ "Revision: " + commit.name() + "\n"
+ "File: a.txt\n"
+ "\n"
+ "1:2-3:4\n"
+ CommentsInNotesUtil.formatTime(serverIdent, ts) + "\n"
+ "Author: Change Owner <1@gerrit>\n"
+ "UUID: uuid1\n"
+ "Bytes: 7\n"
+ "Comment\n"
+ "\n");
patchSets = notes.getPatchSets();
assertThat(patchSets.get(psId1).getPushCertificate()).isNull();
assertThat(patchSets.get(psId2).getPushCertificate())
.isEqualTo(trimmedCert);
assertThat(notes.getComments()).isNotEmpty();
}
@Test
public void emptyExceptSubject() throws Exception {
ChangeUpdate update = newUpdate(newChange(), changeOwner);
update.setSubjectForCommit("Create change");
update.commit();
assertThat(update.getRevision()).isNotNull();
}
@Test
public void multipleUpdatesInBatch() 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);
BatchMetaDataUpdate batch = update1.openUpdate();
try {
update1.writeCommit(batch);
update2.writeCommit(batch);
batch.commit();
} finally {
batch.close();
}
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();
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
BatchMetaDataUpdate batch = update1.openUpdateInBatch(bru);
PatchLineComment comment1 = newPublishedComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update1.setPatchSetId(psId);
update1.upsertComment(comment1);
update1.writeCommit(batch);
ChangeUpdate update2 = newUpdate(c, otherUser);
update2.putApproval("Code-Review", (short) 2);
update2.writeCommit(batch);
RevCommit tipCommit;
try (RevWalk rw = new RevWalk(repo)) {
batch.commit();
bru.execute(rw, NullProgressMonitor.INSTANCE);
ChangeNotes notes = newNotes(c);
ObjectId tip = notes.getRevision();
tipCommit = rw.parseCommit(tip);
} finally {
batch.close();
}
RevCommit commitWithApprovals = tipCommit;
assertThat(commitWithApprovals).isNotNull();
RevCommit commitWithComments = commitWithApprovals.getParent(0);
assertThat(commitWithComments).isNotNull();
try (RevWalk rw = new RevWalk(repo)) {
try (ChangeNotesParser notesWithComments =
new ChangeNotesParser(c, commitWithComments.copy(), rw, repoManager)) {
notesWithComments.parseAll();
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals1 =
notesWithComments.buildApprovals();
assertThat(approvals1).isEmpty();
assertThat(notesWithComments.comments).hasSize(1);
}
}
try (RevWalk rw = new RevWalk(repo)) {
try (ChangeNotesParser notesWithApprovals =
new ChangeNotesParser(c, commitWithApprovals.copy(), rw, repoManager)) {
notesWithApprovals.parseAll();
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals2 =
notesWithApprovals.buildApprovals();
assertThat(approvals2).hasSize(1);
assertThat(notesWithApprovals.comments).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);
BatchMetaDataUpdate batch1 = null;
BatchMetaDataUpdate batch2 = null;
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
try {
batch1 = update1.openUpdateInBatch(bru);
update1.writeCommit(batch1);
batch1.commit();
assertThat(repo.exactRef(update1.getRefName())).isNotNull();
batch2 = update2.openUpdateInBatch(bru);
update2.writeCommit(batch2);
batch2.commit();
assertThat(repo.exactRef(update2.getRefName())).isNotNull();
} finally {
if (batch1 != null) {
batch1.close();
}
if (batch2 != null) {
batch2.close();
}
}
List<ReceiveCommand> cmds = bru.getCommands();
assertThat(cmds).hasSize(2);
assertThat(cmds.get(0).getRefName()).isEqualTo(update1.getRefName());
assertThat(cmds.get(1).getRefName()).isEqualTo(update2.getRefName());
try (RevWalk rw = new RevWalk(repo)) {
bru.execute(rw, NullProgressMonitor.INSTANCE);
}
assertThat(cmds.get(0).getResult()).isEqualTo(ReceiveCommand.Result.OK);
assertThat(cmds.get(1).getResult()).isEqualTo(ReceiveCommand.Result.OK);
assertThat(repo.exactRef(update1.getRefName())).isNotNull();
assertThat(repo.exactRef(update2.getRefName())).isNotNull();
}
@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"
+ "\n"
+ "Testing paragraph 2\n"
+ "\n"
+ "Testing 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 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();
PatchLineComment comment1 = newPublishedComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
(short) 1, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
update.upsertComment(comment1);
update.commit();
update = newUpdate(c, otherUser);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
PatchLineComment comment2 = newPublishedComment(psId, "file1",
uuid2, range2, range2.getEndLine(), otherUser, null, time2, message2,
(short) 1, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
update.upsertComment(comment2);
update.commit();
update = newUpdate(c, otherUser);
CommentRange range3 = new CommentRange(3, 0, 4, 1);
PatchLineComment comment3 = newPublishedComment(psId, "file2",
uuid3, range3, range3.getEndLine(), otherUser, null, time3, message3,
(short) 1, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
update.upsertComment(comment3);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree =
Lists.newArrayList(notes.getNoteMap().iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes =
walk.getObjectReader().open(
note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
assertThat(noteString).isEqualTo("Patch-set: 1\n"
+ "Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ CommentsInNotesUtil.formatTime(serverIdent, time1) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
+ "\n"
+ "2:1-3:1\n"
+ CommentsInNotesUtil.formatTime(serverIdent, time2) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
+ "\n"
+ "File: file2\n"
+ "\n"
+ "3:0-4:1\n"
+ CommentsInNotesUtil.formatTime(serverIdent, time3) + "\n"
+ "Author: Other Account <2@gerrit>\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();
PatchLineComment comment1 = newPublishedComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
update.upsertComment(comment1);
update.commit();
update = newUpdate(c, otherUser);
CommentRange range2 = new CommentRange(2, 1, 3, 1);
PatchLineComment comment2 = newPublishedComment(psId, "file1",
uuid2, range2, range2.getEndLine(), otherUser, null, time2, message2,
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
update.setPatchSetId(psId);
update.upsertComment(comment2);
update.commit();
ChangeNotes notes = newNotes(c);
try (RevWalk walk = new RevWalk(repo)) {
ArrayList<Note> notesInTree =
Lists.newArrayList(notes.getNoteMap().iterator());
Note note = Iterables.getOnlyElement(notesInTree);
byte[] bytes =
walk.getObjectReader().open(
note.getData(), Constants.OBJ_BLOB).getBytes();
String noteString = new String(bytes, UTF_8);
assertThat(noteString).isEqualTo("Base-for-patch-set: 1\n"
+ "Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ "File: file1\n"
+ "\n"
+ "1:1-2:1\n"
+ CommentsInNotesUtil.formatTime(serverIdent, time1) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
+ "\n"
+ "2:1-3:1\n"
+ CommentsInNotesUtil.formatTime(serverIdent, time2) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
+ "\n");
}
}
@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();
PatchLineComment commentForBase =
newPublishedComment(psId, "filename", uuid1,
range, range.getEndLine(), otherUser, null, now, messageForBase,
(short) 0, rev1);
update.setPatchSetId(psId);
update.upsertComment(commentForBase);
update.commit();
update = newUpdate(c, otherUser);
PatchLineComment commentForPS =
newPublishedComment(psId, "filename", uuid2,
range, range.getEndLine(), otherUser, null, now, messageForPS,
(short) 1, rev2);
update.setPatchSetId(psId);
update.upsertComment(commentForPS);
update.commit();
assertThat(newNotes(c).getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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();
PatchLineComment comment1 = newPublishedComment(psId, filename,
uuid1, range, range.getEndLine(), otherUser, null, timeForComment1,
"comment 1", side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment1);
update.commit();
update = newUpdate(c, otherUser);
PatchLineComment comment2 = newPublishedComment(psId, filename,
uuid2, range, range.getEndLine(), otherUser, null, timeForComment2,
"comment 2", side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment2);
update.commit();
assertThat(newNotes(c).getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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();
PatchLineComment comment1 = newPublishedComment(psId, filename1,
uuid, range, range.getEndLine(), otherUser, null, now, "comment 1",
side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment1);
update.commit();
update = newUpdate(c, otherUser);
PatchLineComment comment2 = newPublishedComment(psId, filename2,
uuid, range, range.getEndLine(), otherUser, null, now, "comment 2",
side, rev);
update.setPatchSetId(psId);
update.upsertComment(comment2);
update.commit();
assertThat(newNotes(c).getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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();
PatchLineComment comment1 = newPublishedComment(ps1, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps1",
side, rev1);
update.setPatchSetId(ps1);
update.upsertComment(comment1);
update.commit();
incrementPatchSet(c);
PatchSet.Id ps2 = c.currentPatchSetId();
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
PatchLineComment comment2 = newPublishedComment(ps2, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps2",
side, rev2);
update.setPatchSetId(ps2);
update.upsertComment(comment2);
update.commit();
assertThat(newNotes(c).getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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();
PatchLineComment comment1 = newComment(ps1, filename, uuid, range,
range.getEndLine(), otherUser, null, now, "comment on ps1", side,
rev, Status.DRAFT);
update.setPatchSetId(ps1);
update.insertComment(comment1);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).containsExactlyEntriesIn(
ImmutableMultimap.of(new RevId(rev), comment1));
assertThat(notes.getComments()).isEmpty();
comment1.setStatus(Status.PUBLISHED);
update = newUpdate(c, otherUser);
update.setPatchSetId(ps1);
update.updateComment(comment1);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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);
PatchLineComment comment1 = newComment(psId, filename, uuid1,
range1, range1.getEndLine(), otherUser, null, now, "comment on ps1",
side, rev, Status.DRAFT);
PatchLineComment comment2 = newComment(psId, filename, uuid2,
range2, range2.getEndLine(), otherUser, null, now, "other on ps1",
side, rev, Status.DRAFT);
update.insertComment(comment1);
update.insertComment(comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).containsExactlyEntriesIn(
ImmutableMultimap.of(
new RevId(rev), comment1,
new RevId(rev), comment2)).inOrder();
assertThat(notes.getComments()).isEmpty();
// Publish first draft.
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
comment1.setStatus(Status.PUBLISHED);
update.updateComment(comment1);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).containsExactlyEntriesIn(
ImmutableMultimap.of(new RevId(rev), comment2));
assertThat(notes.getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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);
PatchLineComment baseComment = newComment(psId, filename, uuid1,
range1, range1.getEndLine(), otherUser, null, now, "comment on base",
(short) 0, rev1, Status.DRAFT);
PatchLineComment psComment = newComment(psId, filename, uuid2,
range2, range2.getEndLine(), otherUser, null, now, "comment on ps",
(short) 1, rev2, Status.DRAFT);
update.insertComment(baseComment);
update.insertComment(psComment);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).containsExactlyEntriesIn(
ImmutableMultimap.of(
new RevId(rev1), baseComment,
new RevId(rev2), psComment));
assertThat(notes.getComments()).isEmpty();
// Publish both comments.
update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
baseComment.setStatus(Status.PUBLISHED);
psComment.setStatus(Status.PUBLISHED);
update.updateComment(baseComment);
update.updateComment(psComment);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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();
PatchLineComment comment = newComment(psId, filename, uuid, range,
range.getEndLine(), otherUser, null, now, "comment on ps1", side,
rev, Status.DRAFT);
update.setPatchSetId(psId);
update.upsertComment(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();
PatchLineComment comment1 = newComment(ps1, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps1",
side, rev1, Status.DRAFT);
update.setPatchSetId(ps1);
update.upsertComment(comment1);
update.commit();
incrementPatchSet(c);
PatchSet.Id ps2 = c.currentPatchSetId();
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
PatchLineComment comment2 = newComment(ps2, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps2",
side, rev2, Status.DRAFT);
update.setPatchSetId(ps2);
update.upsertComment(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 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();
PatchLineComment comment = newPublishedComment(
psId, "filename", uuid, null, 0, otherUser, null, now, messageForBase,
(short) 0, rev);
update.setPatchSetId(psId);
update.upsertComment(comment);
update.commit();
assertThat(newNotes(c).getComments()).containsExactlyEntriesIn(
ImmutableMultimap.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();
PatchLineComment comment = newPublishedComment(
psId, "filename", uuid, null, 1, otherUser, null, now, messageForBase,
(short) 0, rev);
update.setPatchSetId(psId);
update.upsertComment(comment);
update.commit();
assertThat(newNotes(c).getComments()).containsExactlyEntriesIn(
ImmutableMultimap.of(new RevId(rev), comment));
}
@Test
public void updateCommentsForMultipleRevisions() 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();
PatchLineComment comment1 = newComment(ps1, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps1",
side, rev1, Status.DRAFT);
PatchLineComment comment2 = newComment(ps2, filename,
uuid, range, range.getEndLine(), otherUser, null, now, "comment on ps2",
side, rev2, Status.DRAFT);
update.upsertComment(comment1);
update.upsertComment(comment2);
update.commit();
ChangeNotes notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).hasSize(2);
assertThat(notes.getComments()).isEmpty();
update = newUpdate(c, otherUser);
update.setPatchSetId(ps2);
comment1.setStatus(Status.PUBLISHED);
comment2.setStatus(Status.PUBLISHED);
update.upsertComment(comment1);
update.upsertComment(comment2);
update.commit();
notes = newNotes(c);
assertThat(notes.getDraftComments(otherUserId)).isEmpty();
assertThat(notes.getComments()).hasSize(2);
}
private String readNote(ChangeNotes notes, ObjectId noteId) throws Exception {
ObjectId dataId = notes.getNoteMap().getNote(noteId).getData();
return new String(
rw.getObjectReader().open(dataId, OBJ_BLOB).getCachedBytes(), UTF_8);
}
}