blob: c29cf9969dafc4e1f4974b14184167dc6ed825b7 [file] [log] [blame]
// Copyright (C) 2020 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.acceptance.testsuite.change;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.extensions.common.testing.CommentInfoSubject.assertThat;
import static com.google.gerrit.extensions.common.testing.CommentInfoSubject.assertThatList;
import static com.google.gerrit.extensions.common.testing.RobotCommentInfoSubject.assertThat;
import static com.google.gerrit.extensions.common.testing.RobotCommentInfoSubject.assertThatList;
import com.google.common.truth.Correspondence;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.RobotCommentInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.truth.NullAwareCorrespondence;
import com.google.inject.Inject;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.List;
import org.junit.Test;
public class PatchsetOperationsImplTest extends AbstractDaemonTest {
@Inject private ChangeOperations changeOperations;
@Inject private AccountOperations accountOperations;
@Inject private RequestScopeOperations requestScopeOperations;
@Test
public void commentCanBeCreatedWithoutSpecifyingAnyParameters() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid = changeOperations.change(changeId).currentPatchset().newComment().create();
List<CommentInfo> comments = getCommentsFromServer(changeId);
assertThatList(comments).comparingElementsUsing(hasUuid()).containsExactly(commentUuid);
}
@Test
public void commentCanBeCreatedOnOlderPatchset() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
PatchSet.Id previousPatchsetId =
changeOperations.change(changeId).currentPatchset().get().patchsetId();
changeOperations.change(changeId).newPatchset().create();
String commentUuid =
changeOperations.change(changeId).patchset(previousPatchsetId).newComment().create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).patchSet().isEqualTo(previousPatchsetId.get());
}
@Test
public void commentIsCreatedWithSpecifiedMessage() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.message("Test comment message")
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).message().isEqualTo("Test comment message");
}
@Test
public void commentCanBeCreatedWithEmptyMessage() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newComment().noMessage().create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).message().isNull();
}
@Test
public void patchsetLevelCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newComment().onPatchsetLevel().create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).path().isEqualTo(Patch.PATCHSET_LEVEL);
}
@Test
public void fileCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().file("file1").content("Line 1").create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.onFileLevelOf("file1")
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).path().isEqualTo("file1");
assertThat(comment).line().isNull();
assertThat(comment).range().isNull();
}
@Test
public void lineCommentCanBeCreated() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.file("file1")
.content("Line 1\nLine 2\nLine 3\nLine 4\n")
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.onLine(3)
.ofFile("file1")
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).line().isEqualTo(3);
assertThat(comment).range().isNull();
}
@Test
public void rangeCommentCanBeCreated() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.file("file1")
.content("Line 1\nLine 2\nLine 3\nLine 4\n")
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.fromLine(2)
.charOffset(4)
.toLine(3)
.charOffset(5)
.ofFile("file1")
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).range().startLine().isEqualTo(2);
assertThat(comment).range().startCharacter().isEqualTo(4);
assertThat(comment).range().endLine().isEqualTo(3);
assertThat(comment).range().endCharacter().isEqualTo(5);
// Line is automatically filled from specified range. It's the end line.
assertThat(comment).line().isEqualTo(3);
}
@Test
public void commentCanBeCreatedOnPatchsetCommit() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.onPatchsetCommit()
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
// Null is often used instead of Side.REVISION as Side.REVISION is the default.
assertThat(comment).side().isAnyOf(Side.REVISION, null);
assertThat(comment).parent().isNull();
}
@Test
public void commentCanBeCreatedOnParentCommit() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newComment().onParentCommit().create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(1);
}
@Test
public void commentCanBeCreatedOnSecondParentCommit() throws Exception {
// Second parents only exist for merge commits. The test API currently doesn't support the
// creation of changes with merge commits yet, though. As there's no explicit validation keeping
// us from adding comments on the non-existing second parent of a regular commit, just use the
// latter. That's still better than not having this test at all.
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.onSecondParentCommit()
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(2);
}
@Test
public void commentCanBeCreatedOnAutoMergeCommit() throws Exception {
// Second parents only exist for merge commits. The test API currently doesn't support the
// creation of changes with merge commits yet, though. As there's no explicit validation keeping
// us from adding comments on the non-existing second parent of a regular commit, just use the
// latter. That's still better than not having this test at all.
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.onAutoMergeCommit()
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isNull();
}
@Test
public void commentCanBeCreatedAsResolved() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newComment().resolved().create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).unresolved().isFalse();
}
@Test
public void commentCanBeCreatedAsUnresolved() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newComment().unresolved().create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).unresolved().isTrue();
}
@Test
public void replyToCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String parentCommentUuid =
changeOperations.change(changeId).currentPatchset().newComment().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.parentUuid(parentCommentUuid)
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).inReplyTo().isEqualTo(parentCommentUuid);
}
@Test
public void tagCanBeAttachedToAComment() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.tag("my special tag")
.create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).tag().isEqualTo("my special tag");
}
@Test
public void commentIsCreatedWithSpecifiedAuthor() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
Account.Id accountId = accountOperations.newAccount().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newComment().author(accountId).create();
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).author().id().isEqualTo(accountId.get());
}
@Test
public void commentIsCreatedWithSpecifiedCreationTime() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
// Don't use nanos. NoteDb supports only second precision.
Instant creationTime =
LocalDateTime.of(2020, Month.SEPTEMBER, 15, 12, 10, 43).atZone(ZoneOffset.UTC).toInstant();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.createdOn(creationTime)
.create();
Timestamp creationTimestamp = Timestamp.from(creationTime);
CommentInfo comment = getCommentFromServer(changeId, commentUuid);
assertThat(comment).updated().isEqualTo(creationTimestamp);
}
@Test
public void zoneOfCreationDateCanBeOmitted() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
// As we don't care about the exact time zone internally used as a default, do a relative test
// so that we don't need to assert on exact instants in time. For a relative test, we need two
// comments whose creation date should be exactly the specified amount apart.
// Don't use nanos or millis. NoteDb supports only second precision.
LocalDateTime creationTime1 = LocalDateTime.of(2020, Month.SEPTEMBER, 15, 12, 10, 43);
LocalDateTime creationTime2 = creationTime1.plusMinutes(10);
String commentUuid1 =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.createdOn(creationTime1)
.create();
String commentUuid2 =
changeOperations
.change(changeId)
.currentPatchset()
.newComment()
.createdOn(creationTime2)
.create();
CommentInfo comment1 = getCommentFromServer(changeId, commentUuid1);
Instant comment1Creation = comment1.updated.toInstant();
CommentInfo comment2 = getCommentFromServer(changeId, commentUuid2);
Instant comment2Creation = comment2.updated.toInstant();
Duration commentCreationDifference = Duration.between(comment1Creation, comment2Creation);
assertThat(commentCreationDifference).isEqualTo(Duration.ofMinutes(10));
}
@Test
public void draftCommentCanBeCreatedWithoutSpecifyingAnyParameters() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newDraftComment().create();
List<CommentInfo> comments = getDraftCommentsFromServer(changeId);
assertThatList(comments).comparingElementsUsing(hasUuid()).containsExactly(commentUuid);
}
@Test
public void draftCommentCanBeCreatedOnOlderPatchset() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
PatchSet.Id previousPatchsetId =
changeOperations.change(changeId).currentPatchset().get().patchsetId();
changeOperations.change(changeId).newPatchset().create();
String commentUuid =
changeOperations.change(changeId).patchset(previousPatchsetId).newDraftComment().create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).patchSet().isEqualTo(previousPatchsetId.get());
}
@Test
public void draftCommentIsCreatedWithSpecifiedMessage() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.message("Test comment message")
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).message().isEqualTo("Test comment message");
}
@Test
public void draftCommentCanBeCreatedWithEmptyMessage() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newDraftComment().noMessage().create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).message().isNull();
}
@Test
public void draftPatchsetLevelCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onPatchsetLevel()
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).path().isEqualTo(Patch.PATCHSET_LEVEL);
}
@Test
public void draftFileCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().file("file1").content("Line 1").create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onFileLevelOf("file1")
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).path().isEqualTo("file1");
assertThat(comment).line().isNull();
assertThat(comment).range().isNull();
}
@Test
public void draftLineCommentCanBeCreated() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.file("file1")
.content("Line 1\nLine 2\nLine 3\nLine 4\n")
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onLine(3)
.ofFile("file1")
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).line().isEqualTo(3);
assertThat(comment).range().isNull();
}
@Test
public void draftRangeCommentCanBeCreated() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.file("file1")
.content("Line 1\nLine 2\nLine 3\nLine 4\n")
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.fromLine(2)
.charOffset(4)
.toLine(3)
.charOffset(5)
.ofFile("file1")
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).range().startLine().isEqualTo(2);
assertThat(comment).range().startCharacter().isEqualTo(4);
assertThat(comment).range().endLine().isEqualTo(3);
assertThat(comment).range().endCharacter().isEqualTo(5);
// Line is automatically filled from specified range. It's the end line.
assertThat(comment).line().isEqualTo(3);
}
@Test
public void draftCommentCanBeCreatedOnPatchsetCommit() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onPatchsetCommit()
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
// Null is often used instead of Side.REVISION as Side.REVISION is the default.
assertThat(comment).side().isAnyOf(Side.REVISION, null);
assertThat(comment).parent().isNull();
}
@Test
public void draftCommentCanBeCreatedOnParentCommit() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onParentCommit()
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(1);
}
@Test
public void draftCommentCanBeCreatedOnSecondParentCommit() throws Exception {
// Second parents only exist for merge commits. The test API currently doesn't support the
// creation of changes with merge commits yet, though. As there's no explicit validation keeping
// us from adding comments on the non-existing second parent of a regular commit, just use the
// latter. That's still better than not having this test at all.
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onSecondParentCommit()
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(2);
}
@Test
public void draftCommentCanBeCreatedOnAutoMergeCommit() throws Exception {
// Second parents only exist for merge commits. The test API currently doesn't support the
// creation of changes with merge commits yet, though. As there's no explicit validation keeping
// us from adding comments on the non-existing second parent of a regular commit, just use the
// latter. That's still better than not having this test at all.
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.onAutoMergeCommit()
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isNull();
}
@Test
public void draftCommentCanBeCreatedAsResolved() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newDraftComment().resolved().create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).unresolved().isFalse();
}
@Test
public void draftCommentCanBeCreatedAsUnresolved() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newDraftComment().unresolved().create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).unresolved().isTrue();
}
@Test
public void draftReplyToDraftCommentCanBeCreated() {
Change.Id changeId = changeOperations.newChange().create();
String parentCommentUuid =
changeOperations.change(changeId).currentPatchset().newDraftComment().create();
// Gerrit's other APIs shouldn't support the creation of a draft reply to a draft comment but
// there's currently no reason to not support such a comment via the test API if a test really
// wants to create such a comment.
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.parentUuid(parentCommentUuid)
.create();
}
@Test
public void draftReplyToPublishedCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String parentCommentUuid =
changeOperations.change(changeId).currentPatchset().newComment().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.parentUuid(parentCommentUuid)
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).inReplyTo().isEqualTo(parentCommentUuid);
}
@Test
public void tagCanBeAttachedToADraftComment() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.tag("my special tag")
.create();
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).tag().isEqualTo("my special tag");
}
@Test
public void draftCommentIsCreatedWithSpecifiedAuthor() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
Account.Id accountId = accountOperations.newAccount().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.author(accountId)
.create();
// A user can only retrieve their own draft comments.
requestScopeOperations.setApiUser(accountId);
List<CommentInfo> comments = getDraftCommentsFromServer(changeId);
// Draft comments never have the author field set. As a user can only retrieve their own draft
// comments, we implicitly know that the author was correctly set when we find the created
// comment in the draft comments of that user.
assertThatList(comments).comparingElementsUsing(hasUuid()).containsExactly(commentUuid);
}
@Test
public void draftCommentIsCreatedWithSpecifiedCreationTime() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
// Don't use nanos. NoteDb supports only second precision.
Instant creationTime =
LocalDateTime.of(2020, Month.SEPTEMBER, 15, 12, 10, 43).atZone(ZoneOffset.UTC).toInstant();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.createdOn(creationTime)
.create();
Timestamp creationTimestamp = Timestamp.from(creationTime);
CommentInfo comment = getDraftCommentFromServer(changeId, commentUuid);
assertThat(comment).updated().isEqualTo(creationTimestamp);
}
@Test
public void zoneOfCreationDateOfDraftCommentCanBeOmitted() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
// As we don't care about the exact time zone internally used as a default, do a relative test
// so that we don't need to assert on exact instants in time. For a relative test, we need two
// comments whose creation date should be exactly the specified amount apart.
// Don't use nanos or millis. NoteDb supports only second precision.
LocalDateTime creationTime1 = LocalDateTime.of(2020, Month.SEPTEMBER, 15, 12, 10, 43);
LocalDateTime creationTime2 = creationTime1.plusMinutes(10);
String commentUuid1 =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.createdOn(creationTime1)
.create();
String commentUuid2 =
changeOperations
.change(changeId)
.currentPatchset()
.newDraftComment()
.createdOn(creationTime2)
.create();
CommentInfo comment1 = getDraftCommentFromServer(changeId, commentUuid1);
Instant comment1Creation = comment1.updated.toInstant();
CommentInfo comment2 = getDraftCommentFromServer(changeId, commentUuid2);
Instant comment2Creation = comment2.updated.toInstant();
Duration commentCreationDifference = Duration.between(comment1Creation, comment2Creation);
assertThat(commentCreationDifference).isEqualTo(Duration.ofMinutes(10));
}
@Test
public void noDraftCommentsAreCreatedOnCreationOfPublishedComment() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
changeOperations.change(changeId).currentPatchset().newComment().create();
List<CommentInfo> comments = getDraftCommentsFromServer(changeId);
assertThatList(comments).isEmpty();
}
@Test
public void noPublishedCommentsAreCreatedOnCreationOfDraftComment() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
changeOperations.change(changeId).currentPatchset().newDraftComment().create();
List<CommentInfo> comments = getCommentsFromServer(changeId);
assertThatList(comments).isEmpty();
}
@Test
public void robotCommentCanBeCreatedWithoutSpecifyingAnyParameters() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newRobotComment().create();
List<RobotCommentInfo> robotComments = getRobotCommentsFromServerFromCurrentPatchset(changeId);
assertThatList(robotComments).comparingElementsUsing(hasUuid()).containsExactly(commentUuid);
}
@Test
public void robotCommentCanBeCreatedOnOlderPatchset() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
PatchSet.Id previousPatchsetId =
changeOperations.change(changeId).currentPatchset().get().patchsetId();
changeOperations.change(changeId).newPatchset().create();
String commentUuid =
changeOperations.change(changeId).patchset(previousPatchsetId).newRobotComment().create();
CommentInfo comment = getRobotCommentFromServer(previousPatchsetId, commentUuid);
assertThat(comment).uuid().isEqualTo(commentUuid);
}
@Test
public void robotCommentIsCreatedWithSpecifiedMessage() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.message("Test comment message")
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).message().isEqualTo("Test comment message");
}
@Test
public void robotCommentCanBeCreatedWithEmptyMessage() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newRobotComment().noMessage().create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).message().isNull();
}
@Test
public void patchsetLevelRobotCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onPatchsetLevel()
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).path().isEqualTo(Patch.PATCHSET_LEVEL);
}
@Test
public void fileRobotCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().file("file1").content("Line 1").create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onFileLevelOf("file1")
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).path().isEqualTo("file1");
assertThat(comment).line().isNull();
assertThat(comment).range().isNull();
}
@Test
public void lineRobotCommentCanBeCreated() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.file("file1")
.content("Line 1\nLine 2\nLine 3\nLine 4\n")
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onLine(3)
.ofFile("file1")
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).line().isEqualTo(3);
assertThat(comment).range().isNull();
}
@Test
public void rangeRobotCommentCanBeCreated() throws Exception {
Change.Id changeId =
changeOperations
.newChange()
.file("file1")
.content("Line 1\nLine 2\nLine 3\nLine 4\n")
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.fromLine(2)
.charOffset(4)
.toLine(3)
.charOffset(5)
.ofFile("file1")
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).range().startLine().isEqualTo(2);
assertThat(comment).range().startCharacter().isEqualTo(4);
assertThat(comment).range().endLine().isEqualTo(3);
assertThat(comment).range().endCharacter().isEqualTo(5);
// Line is automatically filled from specified range. It's the end line.
assertThat(comment).line().isEqualTo(3);
}
@Test
public void robotCommentCanBeCreatedOnPatchsetCommit() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onPatchsetCommit()
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
// Null is often used instead of Side.REVISION as Side.REVISION is the default.
assertThat(comment).side().isAnyOf(Side.REVISION, null);
assertThat(comment).parent().isNull();
}
@Test
public void robotCommentCanBeCreatedOnParentCommit() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onParentCommit()
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(1);
}
@Test
public void robotCommentCanBeCreatedOnSecondParentCommit() throws Exception {
Change.Id parent1ChangeId = changeOperations.newChange().create();
Change.Id parent2ChangeId = changeOperations.newChange().create();
Change.Id changeId =
changeOperations
.newChange()
.mergeOf()
.change(parent1ChangeId)
.and()
.change(parent2ChangeId)
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onSecondParentCommit()
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(2);
}
@Test
public void robotCommentCanBeCreatedOnNonExistingSecondParentCommit() throws Exception {
Change.Id parentChangeId = changeOperations.newChange().create();
Change.Id changeId = changeOperations.newChange().childOf().change(parentChangeId).create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onSecondParentCommit()
.create();
// We want to be able to create such invalid robot comments for testing purposes (e.g. testing
// error handling or resilience of an endpoint) and hence we need to allow such invalid robot
// comments in the test API.
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isEqualTo(2);
}
@Test
public void robotCommentCanBeCreatedOnAutoMergeCommit() throws Exception {
Change.Id parent1ChangeId = changeOperations.newChange().create();
Change.Id parent2ChangeId = changeOperations.newChange().create();
Change.Id changeId =
changeOperations
.newChange()
.mergeOf()
.change(parent1ChangeId)
.and()
.change(parent2ChangeId)
.create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.onAutoMergeCommit()
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).side().isEqualTo(Side.PARENT);
assertThat(comment).parent().isNull();
}
@Test
public void robotCommentCanBeCreatedAsResolved() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newRobotComment().resolved().create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).unresolved().isFalse();
}
@Test
public void robotCommentCanBeCreatedAsUnresolved() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newRobotComment().unresolved().create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).unresolved().isTrue();
}
@Test
public void replyToRobotCommentCanBeCreated() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String parentCommentUuid =
changeOperations.change(changeId).currentPatchset().newRobotComment().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.parentUuid(parentCommentUuid)
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).inReplyTo().isEqualTo(parentCommentUuid);
}
@Test
public void tagCanBeAttachedToARobotComment() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.tag("my special tag")
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).tag().isEqualTo("my special tag");
}
@Test
public void robotCommentIsCreatedWithSpecifiedAuthor() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
Account.Id accountId = accountOperations.newAccount().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.author(accountId)
.create();
CommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).author().id().isEqualTo(accountId.get());
}
@Test
public void robotCommentIsCreatedWithRobotId() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.robotId("robot-id")
.create();
RobotCommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).robotId().isEqualTo("robot-id");
}
@Test
public void robotCommentIsCreatedWithRobotRunId() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.robotId("robot-run-id")
.create();
RobotCommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).robotId().isEqualTo("robot-run-id");
}
@Test
public void robotCommentIsCreatedWithUrl() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations.change(changeId).currentPatchset().newRobotComment().url("url").create();
RobotCommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).url().isEqualTo("url");
}
@Test
public void robotCommentIsCreatedWithProperty() throws Exception {
Change.Id changeId = changeOperations.newChange().create();
String commentUuid =
changeOperations
.change(changeId)
.currentPatchset()
.newRobotComment()
.addProperty("key", "value")
.create();
RobotCommentInfo comment = getRobotCommentFromServerInCurrentPatchset(changeId, commentUuid);
assertThat(comment).properties().containsExactly("key", "value");
}
private List<CommentInfo> getCommentsFromServer(Change.Id changeId) throws RestApiException {
return gApi.changes().id(changeId.get()).commentsAsList();
}
private List<RobotCommentInfo> getRobotCommentsFromServerFromCurrentPatchset(Change.Id changeId)
throws RestApiException {
return gApi.changes().id(changeId.get()).current().robotCommentsAsList();
}
private List<CommentInfo> getDraftCommentsFromServer(Change.Id changeId) throws RestApiException {
return gApi.changes().id(changeId.get()).draftsAsList();
}
private CommentInfo getCommentFromServer(Change.Id changeId, String uuid)
throws RestApiException {
return gApi.changes().id(changeId.get()).commentsAsList().stream()
.filter(comment -> comment.id.equals(uuid))
.findAny()
.orElseThrow(
() ->
new IllegalStateException(
String.format("Comment %s not found on change %d", uuid, changeId.get())));
}
private RobotCommentInfo getRobotCommentFromServerInCurrentPatchset(
Change.Id changeId, String uuid) throws RestApiException {
return gApi.changes().id(changeId.get()).current().robotCommentsAsList().stream()
.filter(comment -> comment.id.equals(uuid))
.findAny()
.orElseThrow(
() ->
new IllegalStateException(
String.format(
"Robot Comment %s not found on change %d on the latest patchset",
uuid, changeId.get())));
}
private RobotCommentInfo getRobotCommentFromServer(PatchSet.Id patchsetId, String uuid)
throws RestApiException {
return gApi.changes().id(patchsetId.changeId().toString())
.revision(patchsetId.getId().toString()).robotCommentsAsList().stream()
.filter(comment -> comment.id.equals(uuid))
.findAny()
.orElseThrow(
() ->
new IllegalStateException(
String.format(
"Robot Comment %s not found on change %d on patchset %d",
uuid, patchsetId.changeId().get(), patchsetId.get())));
}
private CommentInfo getDraftCommentFromServer(Change.Id changeId, String uuid)
throws RestApiException {
return gApi.changes().id(changeId.get()).draftsAsList().stream()
.filter(comment -> comment.id.equals(uuid))
.findAny()
.orElseThrow(
() ->
new IllegalStateException(
String.format(
"Draft comment %s not found on change %d", uuid, changeId.get())));
}
private Correspondence<CommentInfo, String> hasUuid() {
return NullAwareCorrespondence.transforming(comment -> comment.id, "hasUuid");
}
}