diff options
Diffstat (limited to 'javatests/com/google/gerrit/acceptance/rest/ChangesRestApiBindingsIT.java')
-rw-r--r-- | javatests/com/google/gerrit/acceptance/rest/ChangesRestApiBindingsIT.java | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/acceptance/rest/ChangesRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/ChangesRestApiBindingsIT.java new file mode 100644 index 0000000000..c00c2aad40 --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/rest/ChangesRestApiBindingsIT.java @@ -0,0 +1,509 @@ +// 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; + +import static com.google.common.truth.TruthJUnit.assume; +import static com.google.gerrit.acceptance.rest.AbstractRestApiBindingsTest.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.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 com.google.gerrit.reviewdb.client.Patch; +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 (for details see JavaDoc on {@link + * AbstractRestApiBindingsTest}). + */ +public class ChangesRestApiBindingsIT extends AbstractRestApiBindingsTest { + /** + * 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/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.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")); + + /** + * Change REST endpoints to be tested with NoteDb, each URL contains a placeholder for the change + * identifier. + */ + private static final ImmutableList<RestCall> CHANGE_ENDPOINTS_NOTEDB = + ImmutableList.of( + RestCall.post("/changes/%s/hashtags"), RestCall.post("/changes/%s/rebuild.notedb")); + + /** + * 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.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 String FILENAME = "test.txt"; + + @Test + public void changeEndpoints() throws Exception { + String changeId = createChange().getChangeId(); + gApi.changes().id(changeId).edit().create(); + execute(CHANGE_ENDPOINTS, changeId); + } + + @Test + public void changeEndpointsNoteDb() throws Exception { + assume().that(notesMigration.readChanges()).isTrue(); + + String changeId = createChange().getChangeId(); + execute(CHANGE_ENDPOINTS_NOTEDB, changeId); + } + + @Test + public void reviewerEndpoints() throws Exception { + String changeId = createChange().getChangeId(); + + AddReviewerInput addReviewerInput = new AddReviewerInput(); + addReviewerInput.reviewer = user.email; + + execute( + REVIEWER_ENDPOINTS, + () -> gApi.changes().id(changeId).addReviewer(addReviewerInput), + changeId, + addReviewerInput.reviewer); + } + + @Test + public void voteEndpoints() throws Exception { + String changeId = createChange().getChangeId(); + + execute( + 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(); + execute(REVISION_ENDPOINTS, changeId, "current"); + } + + @Test + public void revisionReviewerEndpoints() throws Exception { + String changeId = createChange().getChangeId(); + + AddReviewerInput addReviewerInput = new AddReviewerInput(); + addReviewerInput.reviewer = user.email; + + execute( + REVISION_REVIEWER_ENDPOINTS, + () -> gApi.changes().id(changeId).addReviewer(addReviewerInput), + changeId, + "current", + addReviewerInput.reviewer); + } + + @Test + public void revisionVoteEndpoints() throws Exception { + String changeId = createChange().getChangeId(); + + execute( + 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(); + + execute(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); + + execute(restCall, changeId, "current", commentInfo.id); + } + } + + @Test + public void robotCommentEndpoints() throws Exception { + assume().that(notesMigration.readChanges()).isTrue(); + + 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); + + execute(ROBOT_COMMENT_ENDPOINTS, changeId, "current", robotCommentInfo.id); + } + + @Test + public void fixEndpoints() throws Exception { + assume().that(notesMigration.readChanges()).isTrue(); + + 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); + + execute(FIX_ENDPOINTS, changeId, "current", fixId); + } + + @Test + public void revisionFileEndpoints() throws Exception { + String changeId = createChange("Subject", FILENAME, "content").getChangeId(); + execute(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; + + execute(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. + execute( + 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(); + execute(CHANGE_EDIT_ENDPOINTS, changeId, FILENAME); + } + + 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()); + } +} |