blob: 2e702c103cd42a8d3b0f280a281321377d9cb3a5 [file] [log] [blame]
// Copyright (C) 2018 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.rest.binding;
import static com.google.gerrit.acceptance.rest.util.RestCall.Method.GET;
import static com.google.gerrit.extensions.common.testing.RobotCommentInfoSubject.assertThatList;
import static java.util.stream.Collectors.toList;
import static org.apache.http.HttpStatus.SC_NOT_FOUND;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.rest.util.RestApiCallHelper;
import com.google.gerrit.acceptance.rest.util.RestCall;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
import com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput;
import com.google.gerrit.extensions.client.Comment;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.FixReplacementInfo;
import com.google.gerrit.extensions.common.FixSuggestionInfo;
import com.google.gerrit.extensions.common.RobotCommentInfo;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.junit.Test;
/**
* Tests for checking the bindings of the changes REST API.
*
* <p>These tests only verify that the change REST endpoints are correctly bound, they do no test
* the functionality of the change REST endpoints.
*/
public class ChangesRestApiBindingsIT extends AbstractDaemonTest {
/**
* Change REST endpoints to be tested, each URL contains a placeholder for the change identifier.
*/
private static final ImmutableList<RestCall> CHANGE_ENDPOINTS =
ImmutableList.of(
RestCall.get("/changes/%s"),
RestCall.get("/changes/%s/detail"),
RestCall.get("/changes/%s/topic"),
RestCall.put("/changes/%s/topic"),
RestCall.delete("/changes/%s/topic"),
RestCall.get("/changes/%s/in"),
RestCall.get("/changes/%s/hashtags"),
RestCall.get("/changes/%s/comments"),
RestCall.get("/changes/%s/robotcomments"),
RestCall.get("/changes/%s/drafts"),
RestCall.get("/changes/%s/attention"),
RestCall.post("/changes/%s/attention"),
RestCall.get("/changes/%s/assignee"),
RestCall.get("/changes/%s/past_assignees"),
RestCall.put("/changes/%s/assignee"),
RestCall.delete("/changes/%s/assignee"),
RestCall.post("/changes/%s/private"),
RestCall.post("/changes/%s/private.delete"),
RestCall.delete("/changes/%s/private"),
RestCall.post("/changes/%s/wip"),
RestCall.post("/changes/%s/ready"),
RestCall.put("/changes/%s/ignore"),
RestCall.put("/changes/%s/unignore"),
RestCall.put("/changes/%s/reviewed"),
RestCall.put("/changes/%s/unreviewed"),
RestCall.get("/changes/%s/messages"),
RestCall.put("/changes/%s/message"),
RestCall.post("/changes/%s/merge"),
RestCall.post("/changes/%s/abandon"),
RestCall.post("/changes/%s/move"),
RestCall.post("/changes/%s/rebase"),
RestCall.post("/changes/%s/restore"),
RestCall.post("/changes/%s/revert"),
RestCall.post("/changes/%s/revert_submission"),
RestCall.get("/changes/%s/pure_revert"),
RestCall.post("/changes/%s/submit"),
RestCall.get("/changes/%s/submitted_together"),
RestCall.post("/changes/%s/index"),
RestCall.get("/changes/%s/check"),
RestCall.post("/changes/%s/check"),
RestCall.get("/changes/%s/reviewers"),
RestCall.post("/changes/%s/reviewers"),
RestCall.get("/changes/%s/suggest_reviewers"),
RestCall.builder(GET, "/changes/%s/revisions")
// GET /changes/<change-id>/revisions is not implemented
.expectedResponseCode(SC_NOT_FOUND)
.build(),
RestCall.get("/changes/%s/edit"),
RestCall.post("/changes/%s/edit"),
RestCall.post("/changes/%s/edit:rebase"),
RestCall.get("/changes/%s/edit:message"),
RestCall.put("/changes/%s/edit:message"),
// Publish edit and create a new edit
RestCall.post("/changes/%s/edit:publish"),
RestCall.put("/changes/%s/edit/a.txt"),
// Deletion of change edit and change must be tested last
RestCall.delete("/changes/%s/edit"),
RestCall.delete("/changes/%s"));
/**
* Reviewer REST endpoints to be tested, each URL contains placeholders for the change identifier
* and the reviewer identifier.
*/
private static final ImmutableList<RestCall> REVIEWER_ENDPOINTS =
ImmutableList.of(
RestCall.get("/changes/%s/reviewers/%s"),
RestCall.get("/changes/%s/reviewers/%s/votes"),
RestCall.post("/changes/%s/reviewers/%s/delete"),
RestCall.delete("/changes/%s/reviewers/%s"));
/**
* Vote REST endpoints to be tested, each URL contains placeholders for the change identifier, the
* reviewer identifier and the label identifier.
*/
private static final ImmutableList<RestCall> VOTE_ENDPOINTS =
ImmutableList.of(
RestCall.post("/changes/%s/reviewers/%s/votes/%s/delete"),
RestCall.delete("/changes/%s/reviewers/%s/votes/%s"));
/**
* Revision REST endpoints to be tested, each URL contains placeholders for the change identifier
* and the revision identifier.
*/
private static final ImmutableList<RestCall> REVISION_ENDPOINTS =
ImmutableList.of(
RestCall.get("/changes/%s/revisions/%s/actions"),
RestCall.post("/changes/%s/revisions/%s/cherrypick"),
RestCall.get("/changes/%s/revisions/%s/commit"),
RestCall.get("/changes/%s/revisions/%s/mergeable"),
RestCall.get("/changes/%s/revisions/%s/related"),
RestCall.get("/changes/%s/revisions/%s/review"),
RestCall.post("/changes/%s/revisions/%s/review"),
RestCall.get("/changes/%s/revisions/%s/preview_submit"),
RestCall.post("/changes/%s/revisions/%s/submit"),
RestCall.get("/changes/%s/revisions/%s/submit_type"),
RestCall.post("/changes/%s/revisions/%s/test.submit_rule"),
RestCall.post("/changes/%s/revisions/%s/test.submit_type"),
RestCall.post("/changes/%s/revisions/%s/rebase"),
RestCall.get("/changes/%s/revisions/%s/description"),
RestCall.put("/changes/%s/revisions/%s/description"),
RestCall.get("/changes/%s/revisions/%s/patch"),
RestCall.get("/changes/%s/revisions/%s/archive"),
RestCall.get("/changes/%s/revisions/%s/mergelist"),
RestCall.get("/changes/%s/revisions/%s/reviewers"),
RestCall.get("/changes/%s/revisions/%s/drafts"),
RestCall.put("/changes/%s/revisions/%s/drafts"),
RestCall.get("/changes/%s/revisions/%s/comments"),
RestCall.get("/changes/%s/revisions/%s/robotcomments"),
RestCall.get("/changes/%s/revisions/%s/ported_comments"),
RestCall.get("/changes/%s/revisions/%s/ported_drafts"),
RestCall.builder(GET, "/changes/%s/revisions/%s/fixes")
// GET /changes/<change>/revisions/<revision>/fixes is not implemented
.expectedResponseCode(SC_NOT_FOUND)
.build(),
RestCall.get("/changes/%s/revisions/%s/files"));
/**
* Revision reviewer REST endpoints to be tested, each URL contains placeholders for the change
* identifier, the revision identifier and the reviewer identifier.
*/
private static final ImmutableList<RestCall> REVISION_REVIEWER_ENDPOINTS =
ImmutableList.of(
RestCall.get("/changes/%s/revisions/%s/reviewers/%s"),
RestCall.get("/changes/%s/revisions/%s/reviewers/%s/votes"),
RestCall.post("/changes/%s/revisions/%s/reviewers/%s/delete"),
RestCall.delete("/changes/%s/revisions/%s/reviewers/%s"));
/**
* Revision vote REST endpoints to be tested, each URL contains placeholders for the change
* identifier, the revision identifier, the reviewer identifier and the label identifier.
*/
private static final ImmutableList<RestCall> REVISION_VOTE_ENDPOINTS =
ImmutableList.of(
RestCall.post("/changes/%s/revisions/%s/reviewers/%s/votes/%s/delete"),
RestCall.delete("/changes/%s/revisions/%s/reviewers/%s/votes/%s"));
/**
* Draft comment REST endpoints to be tested, each URL contains placeholders for the change
* identifier, the revision identifier and the draft comment identifier.
*/
private static final ImmutableList<RestCall> DRAFT_COMMENT_ENDPOINTS =
ImmutableList.of(
RestCall.get("/changes/%s/revisions/%s/drafts/%s"),
RestCall.put("/changes/%s/revisions/%s/drafts/%s"),
RestCall.delete("/changes/%s/revisions/%s/drafts/%s"));
/**
* Comment REST endpoints to be tested, each URL contains placeholders for the change identifier,
* the revision identifier and the comment identifier.
*/
private static final ImmutableList<RestCall> COMMENT_ENDPOINTS =
ImmutableList.of(
RestCall.get("/changes/%s/revisions/%s/comments/%s"),
RestCall.delete("/changes/%s/revisions/%s/comments/%s"),
RestCall.post("/changes/%s/revisions/%s/comments/%s/delete"));
/**
* Robot comment REST endpoints to be tested, each URL contains placeholders for the change
* identifier, the revision identifier and the robot comment identifier.
*/
private static final ImmutableList<RestCall> ROBOT_COMMENT_ENDPOINTS =
ImmutableList.of(RestCall.get("/changes/%s/revisions/%s/robotcomments/%s"));
/**
* Fix REST endpoints to be tested, each URL contains placeholders for the change identifier, the
* revision identifier and the fix identifier.
*/
private static final ImmutableList<RestCall> FIX_ENDPOINTS =
ImmutableList.of(RestCall.post("/changes/%s/revisions/%s/fixes/%s/apply"));
/**
* Revision file REST endpoints to be tested, each URL contains placeholders for the change
* identifier, the revision identifier and the file identifier.
*/
private static final ImmutableList<RestCall> REVISION_FILE_ENDPOINTS =
ImmutableList.of(
RestCall.put("/changes/%s/revisions/%s/files/%s/reviewed"),
RestCall.delete("/changes/%s/revisions/%s/files/%s/reviewed"),
RestCall.get("/changes/%s/revisions/%s/files/%s/content"),
RestCall.get("/changes/%s/revisions/%s/files/%s/download"),
RestCall.get("/changes/%s/revisions/%s/files/%s/diff"),
RestCall.get("/changes/%s/revisions/%s/files/%s/blame"));
/**
* Change message REST endpoints to be tested, each URL contains placeholders for the change
* identifier and the change message identifier.
*/
private static final ImmutableList<RestCall> CHANGE_MESSAGE_ENDPOINTS =
ImmutableList.of(RestCall.get("/changes/%s/messages/%s"));
/**
* Change edit REST endpoints that create an edit to be tested, each URL contains placeholders for
* the change identifier and the change edit identifier.
*/
private static final ImmutableList<RestCall> CHANGE_EDIT_CREATE_ENDPOINTS =
ImmutableList.of(
// Create change edit by editing an existing file.
RestCall.put("/changes/%s/edit/%s"),
// Create change edit by deleting an existing file.
RestCall.delete("/changes/%s/edit/%s"));
/**
* Change edit REST endpoints to be tested, each URL contains placeholders for the change
* identifier and the change edit identifier.
*/
private static final ImmutableList<RestCall> CHANGE_EDIT_ENDPOINTS =
ImmutableList.of(
// Calls on existing change edit.
RestCall.get("/changes/%s/edit/%s"),
RestCall.put("/changes/%s/edit/%s"),
RestCall.get("/changes/%s/edit/%s/meta"),
// Delete content of a file in an existing change edit.
RestCall.delete("/changes/%s/edit/%s"));
private static final ImmutableList<RestCall> ATTENTION_SET_ENDPOINTS =
ImmutableList.of(
RestCall.post("/changes/%s/attention/%s/delete"),
RestCall.delete("/changes/%s/attention/%s"));
private static final String FILENAME = "test.txt";
@Test
public void changeEndpoints() throws Exception {
String changeId = createChange().getChangeId();
gApi.changes().id(changeId).edit().create();
RestApiCallHelper.execute(adminRestSession, CHANGE_ENDPOINTS, changeId);
}
@Test
public void reviewerEndpoints() throws Exception {
String changeId = createChange().getChangeId();
AddReviewerInput addReviewerInput = new AddReviewerInput();
addReviewerInput.reviewer = user.email();
RestApiCallHelper.execute(
adminRestSession,
REVIEWER_ENDPOINTS,
() -> gApi.changes().id(changeId).addReviewer(addReviewerInput),
changeId,
addReviewerInput.reviewer);
}
@Test
public void voteEndpoints() throws Exception {
String changeId = createChange().getChangeId();
RestApiCallHelper.execute(
adminRestSession,
VOTE_ENDPOINTS,
() -> gApi.changes().id(changeId).current().review(ReviewInput.approve()),
changeId,
admin.email(),
"Code-Review");
}
@Test
public void revisionEndpoints() throws Exception {
String changeId = createChange().getChangeId();
RestApiCallHelper.execute(adminRestSession, REVISION_ENDPOINTS, changeId, "current");
}
@Test
public void revisionReviewerEndpoints() throws Exception {
String changeId = createChange().getChangeId();
AddReviewerInput addReviewerInput = new AddReviewerInput();
addReviewerInput.reviewer = user.email();
RestApiCallHelper.execute(
adminRestSession,
REVISION_REVIEWER_ENDPOINTS,
() -> gApi.changes().id(changeId).addReviewer(addReviewerInput),
changeId,
"current",
addReviewerInput.reviewer);
}
@Test
public void revisionVoteEndpoints() throws Exception {
String changeId = createChange().getChangeId();
RestApiCallHelper.execute(
adminRestSession,
REVISION_VOTE_ENDPOINTS,
() -> gApi.changes().id(changeId).current().review(ReviewInput.approve()),
changeId,
"current",
admin.email(),
"Code-Review");
}
@Test
public void draftCommentEndpoints() throws Exception {
String changeId = createChange().getChangeId();
for (RestCall restCall : DRAFT_COMMENT_ENDPOINTS) {
DraftInput draftInput = new DraftInput();
draftInput.path = Patch.COMMIT_MSG;
draftInput.side = Side.REVISION;
draftInput.line = 1;
draftInput.message = "draft comment";
CommentInfo draftInfo = gApi.changes().id(changeId).current().createDraft(draftInput).get();
RestApiCallHelper.execute(adminRestSession, restCall, changeId, "current", draftInfo.id);
}
}
@Test
public void commentEndpoints() throws Exception {
String changeId = createChange().getChangeId();
for (RestCall restCall : COMMENT_ENDPOINTS) {
DraftInput draftInput = new DraftInput();
draftInput.path = Patch.COMMIT_MSG;
draftInput.side = Side.REVISION;
draftInput.line = 1;
draftInput.message = "draft comment";
CommentInfo commentInfo = gApi.changes().id(changeId).current().createDraft(draftInput).get();
ReviewInput reviewInput = new ReviewInput();
reviewInput.drafts = DraftHandling.PUBLISH;
gApi.changes().id(changeId).current().review(reviewInput);
RestApiCallHelper.execute(adminRestSession, restCall, changeId, "current", commentInfo.id);
}
}
@Test
public void robotCommentEndpoints() throws Exception {
String changeId = createChange().getChangeId();
RobotCommentInput robotCommentInput = new RobotCommentInput();
robotCommentInput.robotId = "happyRobot";
robotCommentInput.robotRunId = "1";
robotCommentInput.line = 1;
robotCommentInput.message = "nit: trailing whitespace";
robotCommentInput.path = Patch.COMMIT_MSG;
ReviewInput reviewInput = new ReviewInput();
reviewInput.robotComments =
Collections.singletonMap(robotCommentInput.path, ImmutableList.of(robotCommentInput));
reviewInput.message = "robot comment test";
gApi.changes().id(changeId).current().review(reviewInput);
List<RobotCommentInfo> robotCommentInfos =
gApi.changes().id(changeId).current().robotCommentsAsList();
RobotCommentInfo robotCommentInfo = Iterables.getOnlyElement(robotCommentInfos);
RestApiCallHelper.execute(
adminRestSession, ROBOT_COMMENT_ENDPOINTS, changeId, "current", robotCommentInfo.id);
}
@Test
public void fixEndpoints() throws Exception {
String changeId = createChange("Subject", FILENAME, "content").getChangeId();
RobotCommentInput robotCommentInput = new RobotCommentInput();
robotCommentInput.robotId = "happyRobot";
robotCommentInput.robotRunId = "1";
robotCommentInput.line = 1;
robotCommentInput.message = "nit: trailing whitespace";
robotCommentInput.path = FILENAME;
FixReplacementInfo fixReplacementInfo = new FixReplacementInfo();
fixReplacementInfo.path = FILENAME;
fixReplacementInfo.replacement = "some replacement code";
fixReplacementInfo.range = createRange(1, 1, 1, 2);
FixSuggestionInfo fixSuggestionInfo = new FixSuggestionInfo();
fixSuggestionInfo.fixId = "An ID which must be overwritten.";
fixSuggestionInfo.description = "A description for a suggested fix.";
fixSuggestionInfo.replacements = ImmutableList.of(fixReplacementInfo);
robotCommentInput.fixSuggestions = ImmutableList.of(fixSuggestionInfo);
ReviewInput reviewInput = new ReviewInput();
reviewInput.robotComments =
Collections.singletonMap(robotCommentInput.path, ImmutableList.of(robotCommentInput));
reviewInput.message = "robot comment test";
gApi.changes().id(changeId).current().review(reviewInput);
List<RobotCommentInfo> robotCommentInfos =
gApi.changes().id(changeId).current().robotCommentsAsList();
List<String> fixIds = getFixIds(robotCommentInfos);
String fixId = Iterables.getOnlyElement(fixIds);
RestApiCallHelper.execute(adminRestSession, FIX_ENDPOINTS, changeId, "current", fixId);
}
@Test
public void revisionFileEndpoints() throws Exception {
String changeId = createChange("Subject", FILENAME, "content").getChangeId();
RestApiCallHelper.execute(
adminRestSession, REVISION_FILE_ENDPOINTS, changeId, "current", FILENAME);
}
@Test
public void changeMessageEndpoints() throws Exception {
String changeId = createChange().getChangeId();
// A change message is created on change creation.
String changeMessageId = Iterables.getOnlyElement(gApi.changes().id(changeId).messages()).id;
RestApiCallHelper.execute(
adminRestSession, CHANGE_MESSAGE_ENDPOINTS, changeId, changeMessageId);
}
@Test
public void changeEditCreateEndpoints() throws Exception {
String changeId = createChange("Subject", FILENAME, "content").getChangeId();
// Each of the REST calls creates the change edit newly.
RestApiCallHelper.execute(
adminRestSession,
CHANGE_EDIT_CREATE_ENDPOINTS,
() -> adminRestSession.delete("/changes/" + changeId + "/edit"),
changeId,
FILENAME);
}
@Test
public void changeEditEndpoints() throws Exception {
String changeId = createChange("Subject", FILENAME, "content").getChangeId();
gApi.changes().id(changeId).edit().create();
RestApiCallHelper.execute(adminRestSession, CHANGE_EDIT_ENDPOINTS, changeId, FILENAME);
}
@Test
public void attentionSetEndpoints() throws Exception {
String changeId = createChange().getChangeId();
gApi.changes().id(changeId).edit().create();
RestApiCallHelper.execute(
adminRestSession, ATTENTION_SET_ENDPOINTS, changeId, user.id().toString());
}
private static Comment.Range createRange(
int startLine, int startCharacter, int endLine, int endCharacter) {
Comment.Range range = new Comment.Range();
range.startLine = startLine;
range.startCharacter = startCharacter;
range.endLine = endLine;
range.endCharacter = endCharacter;
return range;
}
private static List<String> getFixIds(List<RobotCommentInfo> robotComments) {
assertThatList(robotComments).isNotNull();
return robotComments.stream()
.map(robotCommentInfo -> robotCommentInfo.fixSuggestions)
.filter(Objects::nonNull)
.flatMap(List::stream)
.map(fixSuggestionInfo -> fixSuggestionInfo.fixId)
.collect(toList());
}
}