Merge "RestApiModule: use existing overload methods"
diff --git a/javatests/com/google/gerrit/acceptance/rest/AbstractRestApiBindingsTest.java b/javatests/com/google/gerrit/acceptance/rest/AbstractRestApiBindingsTest.java
new file mode 100644
index 0000000..26bc345
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/AbstractRestApiBindingsTest.java
@@ -0,0 +1,155 @@
+// 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.base.Preconditions.checkState;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static org.apache.http.HttpStatus.SC_FORBIDDEN;
+import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
+import static org.apache.http.HttpStatus.SC_NOT_FOUND;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import java.util.List;
+import java.util.Optional;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Ignore;
+
+/**
+ * Base class for testing the REST API bindings.
+ *
+ * <p>This test sends a request to each REST endpoint and verifies that an implementation is found
+ * (no '404 Not Found' response) and that the request doesn't fail (no '500 Internal Server Error'
+ * response). It doesn't verify that the REST endpoint works correctly. This is okay since the
+ * purpose of the test is only to verify that the REST endpoint implementations are correctly bound.
+ */
+@Ignore
+public abstract class AbstractRestApiBindingsTest extends AbstractDaemonTest {
+ protected void execute(List<RestCall> restCalls, String... args) throws Exception {
+ execute(restCalls, () -> {}, args);
+ }
+
+ protected void execute(List<RestCall> restCalls, BeforeRestCall beforeRestCall, String... args)
+ throws Exception {
+ for (RestCall restCall : restCalls) {
+ beforeRestCall.run();
+ execute(restCall, args);
+ }
+ }
+
+ protected void execute(RestCall restCall, String... args) throws Exception {
+ String method = restCall.httpMethod().name();
+ String uri = restCall.uri(args);
+
+ RestResponse response;
+ switch (restCall.httpMethod()) {
+ case GET:
+ response = adminRestSession.get(uri);
+ break;
+ case PUT:
+ response = adminRestSession.put(uri);
+ break;
+ case POST:
+ response = adminRestSession.post(uri);
+ break;
+ case DELETE:
+ response = adminRestSession.delete(uri);
+ break;
+ default:
+ fail("unsupported method: %s", restCall.httpMethod().name());
+ throw new IllegalStateException();
+ }
+
+ int status = response.getStatusCode();
+ String body = response.hasContent() ? response.getEntityContent() : "";
+
+ String msg = String.format("%s %s returned %d: %s", method, uri, status, body);
+ if (restCall.expectedResponseCode().isPresent()) {
+ assertWithMessage(msg).that(status).isEqualTo(restCall.expectedResponseCode().get());
+ } else {
+ assertWithMessage(msg).that(status).isNotIn(ImmutableList.of(SC_FORBIDDEN, SC_NOT_FOUND));
+ assertWithMessage(msg).that(status).isLessThan(SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ enum Method {
+ GET,
+ PUT,
+ POST,
+ DELETE
+ }
+
+ @AutoValue
+ abstract static class RestCall {
+ static RestCall get(String uriFormat) {
+ return builder(Method.GET, uriFormat).build();
+ }
+
+ static RestCall put(String uriFormat) {
+ return builder(Method.PUT, uriFormat).build();
+ }
+
+ static RestCall post(String uriFormat) {
+ return builder(Method.POST, uriFormat).build();
+ }
+
+ static RestCall delete(String uriFormat) {
+ return builder(Method.DELETE, uriFormat).build();
+ }
+
+ static Builder builder(Method httpMethod, String uriFormat) {
+ return new AutoValue_AbstractRestApiBindingsTest_RestCall.Builder()
+ .httpMethod(httpMethod)
+ .uriFormat(uriFormat);
+ }
+
+ abstract Method httpMethod();
+
+ abstract String uriFormat();
+
+ abstract Optional<Integer> expectedResponseCode();
+
+ String uri(String... args) {
+ String uriFormat = uriFormat();
+ int expectedArgNum = StringUtils.countMatches(uriFormat, "%s");
+ checkState(
+ args.length == expectedArgNum,
+ "uriFormat %s needs %s arguments, got only %s: %s",
+ uriFormat,
+ expectedArgNum,
+ args.length,
+ args);
+ return String.format(uriFormat, (Object[]) args);
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder httpMethod(Method httpMethod);
+
+ abstract Builder uriFormat(String uriFormat);
+
+ abstract Builder expectedResponseCode(int expectedResponseCode);
+
+ abstract RestCall build();
+ }
+ }
+
+ @FunctionalInterface
+ public interface BeforeRestCall {
+ void run() throws Exception;
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/AccountsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/AccountsRestApiBindingsIT.java
new file mode 100644
index 0000000..8de85a9
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/AccountsRestApiBindingsIT.java
@@ -0,0 +1,136 @@
+// 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 com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.extensions.common.ChangeInput;
+import org.junit.Test;
+
+/**
+ * Tests for checking the bindings of the accounts REST API.
+ *
+ * <p>These tests only verify that the account REST endpoints are correctly bound, they do no test
+ * the functionality of the account REST endpoints (for details see JavaDoc on {@link
+ * AbstractRestApiBindingsTest}).
+ */
+public class AccountsRestApiBindingsIT extends AbstractRestApiBindingsTest {
+ /**
+ * Account REST endpoints to be tested, each URL contains a placeholder for the account
+ * identifier.
+ */
+ private static final ImmutableList<RestCall> ACCOUNT_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/accounts/%s"),
+ RestCall.put("/accounts/%s"),
+ RestCall.get("/accounts/%s/detail"),
+ RestCall.get("/accounts/%s/name"),
+ RestCall.put("/accounts/%s/name"),
+ RestCall.delete("/accounts/%s/name"),
+ RestCall.get("/accounts/%s/username"),
+ RestCall.put("/accounts/%s/username"),
+ RestCall.get("/accounts/%s/active"),
+ RestCall.put("/accounts/%s/active"),
+ RestCall.delete("/accounts/%s/active"),
+ RestCall.put("/accounts/%s/password.http"),
+ RestCall.delete("/accounts/%s/password.http"),
+ RestCall.get("/accounts/%s/status"),
+ RestCall.put("/accounts/%s/status"),
+ RestCall.get("/accounts/%s/avatar"),
+ RestCall.get("/accounts/%s/avatar.change.url"),
+ RestCall.get("/accounts/%s/emails/"),
+ RestCall.put("/accounts/%s/emails/new-email@foo.com"),
+ RestCall.get("/accounts/%s/sshkeys/"),
+ RestCall.post("/accounts/%s/sshkeys/"),
+ RestCall.get("/accounts/%s/watched.projects"),
+ RestCall.post("/accounts/%s/watched.projects"),
+ RestCall.post("/accounts/%s/watched.projects:delete"),
+ RestCall.get("/accounts/%s/groups"),
+ RestCall.get("/accounts/%s/preferences"),
+ RestCall.put("/accounts/%s/preferences"),
+ RestCall.get("/accounts/%s/preferences.diff"),
+ RestCall.put("/accounts/%s/preferences.diff"),
+ RestCall.get("/accounts/%s/preferences.edit"),
+ RestCall.put("/accounts/%s/preferences.edit"),
+ RestCall.get("/accounts/%s/starred.changes"),
+ RestCall.get("/accounts/%s/stars.changes"),
+ RestCall.post("/accounts/%s/index"),
+ RestCall.get("/accounts/%s/agreements"),
+ RestCall.put("/accounts/%s/agreements"),
+ RestCall.get("/accounts/%s/external.ids"),
+ RestCall.post("/accounts/%s/external.ids:delete"),
+ RestCall.get("/accounts/%s/oauthtoken"),
+ RestCall.get("/accounts/%s/capabilities"),
+ RestCall.get("/accounts/%s/capabilities/viewPlugins"));
+
+ /**
+ * Email REST endpoints to be tested, each URL contains a placeholders for the account and email
+ * identifier.
+ */
+ private static final ImmutableList<RestCall> EMAIL_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/accounts/%s/emails/%s"),
+ RestCall.put("/accounts/%s/emails/%s"),
+ RestCall.put("/accounts/%s/emails/%s/preferred"),
+
+ // email deletion must be tested last
+ RestCall.delete("/accounts/%s/emails/%s"));
+
+ /**
+ * SSH key REST endpoints to be tested, each URL contains a placeholders for the account and SSH
+ * key identifier.
+ */
+ private static final ImmutableList<RestCall> SSH_KEY_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/accounts/%s/sshkeys/%s"),
+
+ // SSH key deletion must be tested last
+ RestCall.delete("/accounts/%s/sshkeys/%s"));
+
+ /**
+ * Star REST endpoints to be tested, each URL contains a placeholders for the account and change
+ * identifier.
+ */
+ private static final ImmutableList<RestCall> STAR_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.put("/accounts/%s/starred.changes/%s"),
+ RestCall.delete("/accounts/%s/starred.changes/%s"),
+ RestCall.get("/accounts/%s/stars.changes/%s"),
+ RestCall.post("/accounts/%s/stars.changes/%s"));
+
+ @Test
+ public void accountEndpoints() throws Exception {
+ execute(ACCOUNT_ENDPOINTS, "self");
+ }
+
+ @Test
+ public void emailEndpoints() throws Exception {
+ execute(EMAIL_ENDPOINTS, "self", admin.email);
+ }
+
+ @Test
+ @UseSsh
+ public void sshKeyEndpoints() throws Exception {
+ String sshKeySeq = Integer.toString(gApi.accounts().self().listSshKeys().size());
+ execute(SSH_KEY_ENDPOINTS, "self", sshKeySeq);
+ }
+
+ @Test
+ public void starEndpoints() throws Exception {
+ ChangeInput ci = new ChangeInput(project.get(), "master", "Test change");
+ String changeId = gApi.changes().create(ci).get().id;
+ execute(STAR_ENDPOINTS, "self", changeId);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/BUILD b/javatests/com/google/gerrit/acceptance/rest/BUILD
new file mode 100644
index 0000000..b4940bc
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/BUILD
@@ -0,0 +1,21 @@
+load("//javatests/com/google/gerrit/acceptance:tests.bzl", "acceptance_tests")
+
+acceptance_tests(
+ srcs = glob(["*IT.java"]),
+ group = "rest_bindings",
+ labels = ["rest"],
+ deps = [":util"],
+)
+
+java_library(
+ name = "util",
+ testonly = 1,
+ srcs = [
+ "AbstractRestApiBindingsTest.java",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//java/com/google/gerrit/acceptance:lib",
+ "//lib/commons:lang",
+ ],
+)
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 0000000..53c544d
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/ChangesRestApiBindingsIT.java
@@ -0,0 +1,449 @@
+// 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.post("/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: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/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"));
+
+ // TODO(ekempin): Add tests for change message and change edit REST endpoints
+
+ 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);
+ }
+
+ 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());
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/ConfigRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/ConfigRestApiBindingsIT.java
new file mode 100644
index 0000000..b930b20
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/ConfigRestApiBindingsIT.java
@@ -0,0 +1,110 @@
+// 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.Truth8.assertThat;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.server.project.ProjectCacheImpl;
+import com.google.gerrit.server.restapi.config.ListTasks.TaskInfo;
+import com.google.gson.reflect.TypeToken;
+import java.util.List;
+import java.util.Optional;
+import org.junit.Test;
+
+/**
+ * Tests for checking the bindings of the config REST API.
+ *
+ * <p>These tests only verify that the config REST endpoints are correctly bound, they do no test
+ * the functionality of the config REST endpoints (for details see JavaDoc on {@link
+ * AbstractRestApiBindingsTest}).
+ */
+public class ConfigRestApiBindingsIT extends AbstractRestApiBindingsTest {
+ /**
+ * Config REST endpoints to be tested, the URLs contain no placeholders since the only supported
+ * config identifier ('server') can be hard-coded.
+ */
+ private static final ImmutableList<RestCall> CONFIG_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/config/server/version"),
+ RestCall.get("/config/server/info"),
+ RestCall.get("/config/server/preferences"),
+ RestCall.put("/config/server/preferences"),
+ RestCall.get("/config/server/preferences.diff"),
+ RestCall.put("/config/server/preferences.diff"),
+ RestCall.get("/config/server/preferences.edit"),
+ RestCall.put("/config/server/preferences.edit"),
+ RestCall.get("/config/server/top-menus"),
+ RestCall.put("/config/server/email.confirm"),
+ RestCall.post("/config/server/check.consistency"),
+ RestCall.post("/config/server/reload"),
+ RestCall.get("/config/server/summary"),
+ RestCall.get("/config/server/capabilities"),
+ RestCall.get("/config/server/caches"),
+ RestCall.get("/config/server/tasks"));
+
+ /**
+ * Cache REST endpoints to be tested, the URLs contain a placeholder for the cache identifier.
+ * Since there is only supported a single supported config identifier ('server') it can be
+ * hard-coded.
+ */
+ private static final ImmutableList<RestCall> CACHE_ENDPOINTS =
+ ImmutableList.of(RestCall.get("/config/server/caches/%s"));
+
+ /**
+ * Task REST endpoints to be tested, the URLs contain a placeholder for the task identifier. Since
+ * there is only supported a single supported config identifier ('server') it can be hard-coded.
+ */
+ private static final ImmutableList<RestCall> TASK_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/config/server/tasks/%s"),
+
+ // Task deletion must be tested last
+ RestCall.delete("/config/server/tasks/%s"));
+
+ @Test
+ public void configEndpoints() throws Exception {
+ // 'Access Database' is needed for the '/config/server/check.consistency' REST endpoint
+ allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
+
+ execute(CONFIG_ENDPOINTS);
+ }
+
+ @Test
+ public void cacheEndpoints() throws Exception {
+ execute(CACHE_ENDPOINTS, ProjectCacheImpl.CACHE_NAME);
+ }
+
+ @Test
+ public void taskEndpoints() throws Exception {
+ RestResponse r = adminRestSession.get("/config/server/tasks/");
+ List<TaskInfo> result =
+ newGson().fromJson(r.getReader(), new TypeToken<List<TaskInfo>>() {}.getType());
+ r.consume();
+
+ Optional<String> id =
+ result
+ .stream()
+ .filter(t -> "Log File Compressor".equals(t.command))
+ .map(t -> t.id)
+ .findFirst();
+ assertThat(id).isPresent();
+
+ execute(TASK_ENDPOINTS, id.get());
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/GroupsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/GroupsRestApiBindingsIT.java
new file mode 100644
index 0000000..4538f75
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/GroupsRestApiBindingsIT.java
@@ -0,0 +1,100 @@
+// 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 com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+/**
+ * Tests for checking the bindings of the groups REST API.
+ *
+ * <p>These tests only verify that the group REST endpoints are correctly bound, they do no test the
+ * functionality of the group REST endpoints (for details see JavaDoc on {@link
+ * AbstractRestApiBindingsTest}).
+ */
+public class GroupsRestApiBindingsIT extends AbstractRestApiBindingsTest {
+ /**
+ * Group REST endpoints to be tested, each URL contains a placeholder for the group identifier.
+ */
+ private static final ImmutableList<RestCall> GROUP_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/groups/%s"),
+ RestCall.put("/groups/%s"),
+ RestCall.get("/groups/%s/detail"),
+ RestCall.get("/groups/%s/name"),
+ RestCall.put("/groups/%s/name"),
+ RestCall.get("/groups/%s/description"),
+ RestCall.put("/groups/%s/description"),
+ RestCall.delete("/groups/%s/description"),
+ RestCall.get("/groups/%s/owner"),
+ RestCall.put("/groups/%s/owner"),
+ RestCall.get("/groups/%s/options"),
+ RestCall.put("/groups/%s/options"),
+ RestCall.post("/groups/%s/members"),
+ RestCall.post("/groups/%s/members.add"),
+ RestCall.post("/groups/%s/members.delete"),
+ RestCall.post("/groups/%s/groups"),
+ RestCall.post("/groups/%s/groups.add"),
+ RestCall.post("/groups/%s/groups.delete"),
+ RestCall.get("/groups/%s/log.audit"),
+ RestCall.post("/groups/%s/index"),
+ RestCall.get("/groups/%s/members"),
+ RestCall.get("/groups/%s/groups"));
+
+ /**
+ * Member REST endpoints to be tested, each URL contains placeholders for the group identifier and
+ * the member identifier.
+ */
+ private static final ImmutableList<RestCall> MEMBER_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/groups/%s/members/%s"),
+ RestCall.put("/groups/%s/members/%s"),
+
+ // Member deletion must be tested last
+ RestCall.delete("/groups/%s/members/%s"));
+
+ /**
+ * Subgroup REST endpoints to be tested, each URL contains placeholders for the group identifier
+ * and the subgroup identifier.
+ */
+ private static final ImmutableList<RestCall> SUBGROUP_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/groups/%s/groups/%s"),
+ RestCall.put("/groups/%s/groups/%s"),
+
+ // Subgroup deletion must be tested last
+ RestCall.delete("/groups/%s/groups/%s"));
+
+ @Test
+ public void groupEndpoints() throws Exception {
+ String group = gApi.groups().create("test-group").get().name;
+ execute(GROUP_ENDPOINTS, group);
+ }
+
+ @Test
+ public void memberEndpoints() throws Exception {
+ String group = gApi.groups().create("test-group").get().name;
+ gApi.groups().id(group).addMembers(admin.email);
+ execute(MEMBER_ENDPOINTS, group, admin.email);
+ }
+
+ @Test
+ public void subgroupEndpoints() throws Exception {
+ String group = gApi.groups().create("test-group").get().name;
+ String subgroup = gApi.groups().create("test-subgroup").get().name;
+ gApi.groups().id(group).addGroups(subgroup);
+ execute(SUBGROUP_ENDPOINTS, group, subgroup);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/PluginsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/PluginsRestApiBindingsIT.java
new file mode 100644
index 0000000..aba677f
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/PluginsRestApiBindingsIT.java
@@ -0,0 +1,68 @@
+// 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 java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.GerritConfig;
+import com.google.gerrit.common.RawInputUtil;
+import com.google.gerrit.extensions.api.plugins.InstallPluginInput;
+import com.google.gerrit.extensions.restapi.RawInput;
+import org.junit.Test;
+
+/**
+ * Tests for checking the bindings of the plugins REST API.
+ *
+ * <p>These tests only verify that the plugin REST endpoints are correctly bound, they do no test
+ * the functionality of the plugin REST endpoints (for details see JavaDoc on {@link
+ * AbstractRestApiBindingsTest}).
+ */
+public class PluginsRestApiBindingsIT extends AbstractRestApiBindingsTest {
+ /**
+ * Plugin REST endpoints to be tested, each URL contains a placeholder for the plugin identifier.
+ */
+ private static final ImmutableList<RestCall> PLUGIN_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.put("/plugins/%s"),
+
+ // For GET requests prefixing the view name with 'gerrit~' is required.
+ RestCall.get("/plugins/%s/gerrit~status"),
+
+ // POST (and PUT) requests don't require the 'gerrit~' prefix in front of the view name.
+ RestCall.post("/plugins/%s/enable"),
+ RestCall.post("/plugins/%s/disable"),
+ RestCall.post("/plugins/%s/reload"),
+
+ // Plugin deletion must be tested last
+ RestCall.delete("/plugins/%s"));
+
+ private static final String JS_PLUGIN = "Gerrit.install(function(self){});\n";
+ private static final RawInput JS_PLUGIN_CONTENT = RawInputUtil.create(JS_PLUGIN.getBytes(UTF_8));
+
+ @Test
+ @GerritConfig(name = "plugins.allowRemoteAdmin", value = "true")
+ public void pluginEndpoints() throws Exception {
+ String pluginName = "my-plugin";
+ installPlugin(pluginName);
+ execute(PLUGIN_ENDPOINTS, pluginName);
+ }
+
+ private void installPlugin(String pluginName) throws Exception {
+ InstallPluginInput input = new InstallPluginInput();
+ input.raw = JS_PLUGIN_CONTENT;
+ gApi.plugins().install(pluginName + ".js", input);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/ProjectsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/ProjectsRestApiBindingsIT.java
new file mode 100644
index 0000000..d59f037
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/ProjectsRestApiBindingsIT.java
@@ -0,0 +1,246 @@
+// 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.gerrit.acceptance.GitUtil.assertPushOk;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import static com.google.gerrit.acceptance.rest.AbstractRestApiBindingsTest.Method.GET;
+import static com.google.gerrit.reviewdb.client.RefNames.REFS_DASHBOARDS;
+import static com.google.gerrit.server.restapi.project.DashboardsCollection.DEFAULT_DASHBOARD_NAME;
+import static org.apache.http.HttpStatus.SC_NOT_FOUND;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.GitUtil;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.api.projects.TagInput;
+import com.google.gerrit.reviewdb.client.Project;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.PushResult;
+import org.junit.Test;
+
+/**
+ * Tests for checking the bindings of the projects REST API.
+ *
+ * <p>These tests only verify that the project REST endpoints are correctly bound, they do no test
+ * the functionality of the project REST endpoints (for details see JavaDoc on {@link
+ * AbstractRestApiBindingsTest}).
+ */
+public class ProjectsRestApiBindingsIT extends AbstractRestApiBindingsTest {
+ private static final ImmutableList<RestCall> PROJECT_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/projects/%s"),
+ RestCall.put("/projects/%s"),
+ RestCall.get("/projects/%s/description"),
+ RestCall.put("/projects/%s/description"),
+ RestCall.delete("/projects/%s/description"),
+ RestCall.get("/projects/%s/parent"),
+ RestCall.put("/projects/%s/parent"),
+ RestCall.get("/projects/%s/config"),
+ RestCall.put("/projects/%s/config"),
+ RestCall.get("/projects/%s/HEAD"),
+ RestCall.put("/projects/%s/HEAD"),
+ RestCall.get("/projects/%s/access"),
+ RestCall.post("/projects/%s/access"),
+ RestCall.put("/projects/%s/access:review"),
+ RestCall.get("/projects/%s/check.access"),
+ RestCall.post("/projects/%s/check.access"),
+ RestCall.put("/projects/%s/ban"),
+ RestCall.get("/projects/%s/statistics.git"),
+ RestCall.post("/projects/%s/index"),
+ RestCall.post("/projects/%s/gc"),
+ RestCall.get("/projects/%s/children"),
+ RestCall.get("/projects/%s/branches"),
+ RestCall.post("/projects/%s/branches:delete"),
+ RestCall.put("/projects/%s/branches/new-branch"),
+ RestCall.get("/projects/%s/tags"),
+ RestCall.post("/projects/%s/tags:delete"),
+ RestCall.put("/projects/%s/tags/new-tag"),
+ RestCall.builder(GET, "/projects/%s/commits")
+ // GET /projects/<project>/branches/<branch>/commits is not implemented
+ .expectedResponseCode(SC_NOT_FOUND)
+ .build(),
+ RestCall.get("/projects/%s/dashboards"));
+
+ /**
+ * Child project REST endpoints to be tested, each URL contains placeholders for the parent
+ * project identifier and the child project identifier.
+ */
+ private static final ImmutableList<RestCall> CHILD_PROJECT_ENDPOINTS =
+ ImmutableList.of(RestCall.get("/projects/%s/children/%s"));
+
+ /**
+ * Branch REST endpoints to be tested, each URL contains placeholders for the project identifier
+ * and the branch identifier.
+ */
+ private static final ImmutableList<RestCall> BRANCH_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/projects/%s/branches/%s"),
+ RestCall.put("/projects/%s/branches/%s"),
+ RestCall.get("/projects/%s/branches/%s/mergeable"),
+ RestCall.get("/projects/%s/branches/%s/reflog"),
+ RestCall.builder(GET, "/projects/%s/branches/%s/files")
+ // GET /projects/<project>/branches/<branch>/files is not implemented
+ .expectedResponseCode(SC_NOT_FOUND)
+ .build(),
+
+ // Branch deletion must be tested last
+ RestCall.delete("/projects/%s/branches/%s"));
+
+ /**
+ * Branch file REST endpoints to be tested, each URL contains placeholders for the project
+ * identifier, the branch identifier and the file identifier.
+ */
+ private static final ImmutableList<RestCall> BRANCH_FILE_ENDPOINTS =
+ ImmutableList.of(RestCall.get("/projects/%s/branches/%s/files/%s/content"));
+
+ /**
+ * Dashboard REST endpoints to be tested, each URL contains placeholders for the project
+ * identifier and the dashboard identifier.
+ */
+ private static final ImmutableList<RestCall> DASHBOARD_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/projects/%s/dashboards/%s"),
+ RestCall.put("/projects/%s/dashboards/%s"),
+
+ // Dashboard deletion must be tested last
+ RestCall.delete("/projects/%s/dashboards/%s"));
+
+ /**
+ * Tag REST endpoints to be tested, each URL contains placeholders for the project identifier and
+ * the tag identifier.
+ */
+ private static final ImmutableList<RestCall> TAG_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/projects/%s/tags/%s"),
+ RestCall.put("/projects/%s/tags/%s"),
+ RestCall.delete("/projects/%s/tags/%s"));
+
+ /**
+ * Commit REST endpoints to be tested, each URL contains placeholders for the project identifier
+ * and the commit identifier.
+ */
+ private static final ImmutableList<RestCall> COMMIT_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/projects/%s/commits/%s"),
+ RestCall.get("/projects/%s/commits/%s/in"),
+ RestCall.builder(GET, "/projects/%s/commits/%s/files")
+ // GET /projects/<project>/branches/<branch>/files is not implemented
+ .expectedResponseCode(SC_NOT_FOUND)
+ .build(),
+ RestCall.post("/projects/%s/commits/%s/cherrypick"));
+
+ /**
+ * Commit file REST endpoints to be tested, each URL contains placeholders for the project
+ * identifier, the commit identifier and the file identifier.
+ */
+ private static final ImmutableList<RestCall> COMMIT_FILE_ENDPOINTS =
+ ImmutableList.of(RestCall.get("/projects/%s/commits/%s/files/%s/content"));
+
+ private static final String FILENAME = "test.txt";
+
+ @Test
+ public void projectEndpoints() throws Exception {
+ execute(PROJECT_ENDPOINTS, project.get());
+ }
+
+ @Test
+ public void childProjectEndpoints() throws Exception {
+ Project.NameKey childProject = createProject("test-child-repo", project);
+ execute(CHILD_PROJECT_ENDPOINTS, project.get(), childProject.get());
+ }
+
+ @Test
+ public void branchEndpoints() throws Exception {
+ execute(BRANCH_ENDPOINTS, project.get(), "master");
+ }
+
+ @Test
+ public void branchFileEndpoints() throws Exception {
+ createAndSubmitChange(FILENAME);
+ execute(BRANCH_FILE_ENDPOINTS, project.get(), "master", FILENAME);
+ }
+
+ @Test
+ public void dashboardEndpoints() throws Exception {
+ createDefaultDashboard();
+ execute(DASHBOARD_ENDPOINTS, project.get(), DEFAULT_DASHBOARD_NAME);
+ }
+
+ @Test
+ public void tagEndpoints() throws Exception {
+ String tag = "test-tag";
+ gApi.projects().name(project.get()).tag(tag).create(new TagInput());
+ execute(TAG_ENDPOINTS, project.get(), tag);
+ }
+
+ @Test
+ public void commitEndpoints() throws Exception {
+ String commit = createAndSubmitChange(FILENAME);
+ execute(COMMIT_ENDPOINTS, project.get(), commit);
+ }
+
+ @Test
+ public void commitFileEndpoints() throws Exception {
+ String commit = createAndSubmitChange(FILENAME);
+ execute(COMMIT_FILE_ENDPOINTS, project.get(), commit, FILENAME);
+ }
+
+ private String createAndSubmitChange(String filename) throws Exception {
+ RevCommit c =
+ testRepo
+ .commit()
+ .message("A change")
+ .parent(getRemoteHead())
+ .add(filename, "content")
+ .insertChangeId()
+ .create();
+ String id = GitUtil.getChangeId(testRepo, c).get();
+ testRepo.reset(c);
+
+ String r = "refs/for/master";
+ PushResult pr = pushHead(testRepo, r, false);
+ assertPushOk(pr, r);
+
+ gApi.changes().id(id).current().review(ReviewInput.approve());
+ gApi.changes().id(id).current().submit();
+ return c.name();
+ }
+
+ private void createDefaultDashboard() throws Exception {
+ String dashboardRef = REFS_DASHBOARDS + "team";
+ grant(project, "refs/meta/*", Permission.CREATE);
+ gApi.projects().name(project.get()).branch(dashboardRef).create(new BranchInput());
+
+ try (Repository r = repoManager.openRepository(project)) {
+ TestRepository<Repository>.CommitBuilder cb =
+ new TestRepository<>(r).branch(dashboardRef).commit();
+ StringBuilder content = new StringBuilder("[dashboard]\n");
+ content.append("title = ").append("Open Changes").append("\n");
+ content.append("[section \"").append("open").append("\"]\n");
+ content.append("query = ").append("is:open").append("\n");
+ cb.add("overview", content.toString());
+ cb.create();
+ }
+
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().getProject().setLocalDefaultDashboard(dashboardRef + ":overview");
+ u.save();
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/RootCollectionsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/RootCollectionsRestApiBindingsIT.java
new file mode 100644
index 0000000..131ed1a
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/RootCollectionsRestApiBindingsIT.java
@@ -0,0 +1,53 @@
+// 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.gerrit.acceptance.rest.AbstractRestApiBindingsTest.Method.GET;
+import static org.apache.http.HttpStatus.SC_NOT_FOUND;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+/**
+ * Tests for checking the bindings of the root REST API.
+ *
+ * <p>These tests only verify that the root REST endpoints are correctly bound, they do no test the
+ * functionality of the root REST endpoints (for details see JavaDoc on {@link
+ * AbstractRestApiBindingsTest}).
+ */
+public class RootCollectionsRestApiBindingsIT extends AbstractRestApiBindingsTest {
+ /** Root REST endpoints to be tested, the URLs contain no placeholders. */
+ private static final ImmutableList<RestCall> ROOT_ENDPOINTS =
+ ImmutableList.of(
+ RestCall.get("/access/"),
+ RestCall.get("/accounts/"),
+ RestCall.put("/accounts/new-account"),
+ RestCall.builder(GET, "/config/")
+ // GET /config/ is not implemented
+ .expectedResponseCode(SC_NOT_FOUND)
+ .build(),
+ RestCall.get("/changes/"),
+ RestCall.get("/groups/"),
+ RestCall.put("/groups/new-group"),
+ RestCall.get("/plugins/"),
+ RestCall.put("/plugins/new-plugin"),
+ RestCall.get("/projects/"),
+ RestCall.put("/projects/new-project"));
+
+ @Test
+ public void rootEndpoints() throws Exception {
+ execute(ROOT_ENDPOINTS);
+ }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
index 9085971..545d170 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
@@ -28,21 +28,32 @@
:host {
background-color: var(--dialog-background-color);
display: block;
- padding: 1em;
}
- header {
+ section {
display: flex;
+ padding: .5em 1.5em;
}
- footer {
+ section:not(:first-of-type) {
+ border-top: 1px solid var(--border-color);
+ }
+ .flexContainer {
display: flex;
justify-content: space-between;
padding-top: .75em;
}
+ .footer {
+ justify-content: flex-end;
+ }
.closeButtonContainer {
+ align-items: flex-end;
display: flex;
flex: 0;
justify-content: flex-end;
}
+ .patchFiles,
+ .archivesContainer {
+ padding-bottom: .5em;
+ }
.patchFiles {
margin-right: 2em;
}
@@ -56,26 +67,26 @@
margin-right: 0;
}
.title {
- text-align: center;
flex: 1;
+ font-family: var(--font-family-bold);
+ }
+ .hidden {
+ display: none;
}
</style>
- <header>
+ <section>
<span class="title">
Patch set [[patchNum]] of [[_computePatchSetQuantity(change.revisions)]]
</span>
- <span class="closeButtonContainer">
- <gr-button id="closeButton"
- link
- on-tap="_handleCloseTap">Close</gr-button>
- </span>
- </header>
- <gr-download-commands
+ </section>
+ <section class$="[[_computeShowDownloadCommands(_schemes)]]">
+ <gr-download-commands
id="downloadCommands"
commands="[[_computeDownloadCommands(change, patchNum, _selectedScheme)]]"
schemes="[[_schemes]]"
selected-scheme="{{_selectedScheme}}"></gr-download-commands>
- <footer>
+ </section>
+ <section class="flexContainer">
<div class="patchFiles">
<label>Patch file</label>
<div>
@@ -104,7 +115,14 @@
</template>
</div>
</div>
- </footer>
+ </section>
+ <section class="footer">
+ <span class="closeButtonContainer">
+ <gr-button id="closeButton"
+ link
+ on-tap="_handleCloseTap">Close</gr-button>
+ </span>
+ </section>
</template>
<script src="gr-download-dialog.js"></script>
</dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index fa3e5c9..20449b0 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -172,5 +172,9 @@
this._selectedScheme = schemes.sort()[0];
}
},
+
+ _computeShowDownloadCommands(schemes) {
+ return schemes.length ? '' : 'hidden';
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index 84fe8a9..19932c5 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -183,5 +183,10 @@
MockInteractions.tap(element.$$('.closeButtonContainer gr-button'));
});
});
+
+ test('_computeShowDownloadCommands', () => {
+ assert.equal(element._computeShowDownloadCommands([]), 'hidden');
+ assert.equal(element._computeShowDownloadCommands(['test']), '');
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index e27a8ea..cde4131 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -528,6 +528,9 @@
// link, defer to the native behavior.
if (!path || this.descendedFromClass(e.target, 'pathLink')) { return; }
+ // Disregard the event if the click target is in the edit controls.
+ if (this.descendedFromClass(e.target, 'editFileControls')) { return; }
+
e.preventDefault();
this._togglePathExpanded(path);
},
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 5833a9a..29a388e 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -838,6 +838,28 @@
assert.isTrue(reviewStub.calledOnce);
});
+ test('_handleFileListTap editMode', () => {
+ element._filesByPath = {
+ '/COMMIT_MSG': {},
+ 'f1.txt': {},
+ 'f2.txt': {},
+ };
+ element.changeNum = '42';
+ element.patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
+ element.editMode = true;
+ flushAsynchronousOperations();
+ const tapSpy = sandbox.spy(element, '_handleFileListTap');
+ const toggleExpandSpy = sandbox.spy(element, '_togglePathExpanded');
+
+ // Tap the edit controls. Should be ignored by _handleFileListTap.
+ MockInteractions.tap(element.$$('.editFileControls'));
+ assert.isTrue(tapSpy.calledOnce);
+ assert.isFalse(toggleExpandSpy.called);
+ });
+
test('patch set from revisions', () => {
const expected = [
{num: 4, desc: 'test'},
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html
index 7570533..83e99be 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html
@@ -15,8 +15,11 @@
limitations under the License.
-->
-<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
<link rel="import" href="../../../bower_components/polymer/polymer.html">
+
+
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
+<link rel="import" href="../../../bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="../../shared/gr-copy-clipboard/gr-copy-clipboard.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html">
@@ -24,17 +27,15 @@
<dom-module id="gr-download-commands">
<template>
<style include="shared-styles">
- ul {
- list-style: none;
+ paper-tabs {
+ height: 3rem;
margin-bottom: .5em;
+ --paper-tabs-selection-bar-color: var(--link-color);
}
- li {
- display: inline-block;
- margin: 0;
- padding: 0;
- }
- li gr-button {
- margin-right: 1em;
+ paper-tab {
+ max-width: 15rem;
+ text-transform: uppercase;
+ --paper-tab-ink: var(--link-color);
}
label,
input {
@@ -43,11 +44,6 @@
label {
font-family: var(--font-family-bold);
}
- li[selected] gr-button {
- color: var(--primary-text-color);
- font-family: var(--font-family-bold);
- text-decoration: none;
- }
.schemes {
display: flex;
justify-content: space-between;
@@ -55,25 +51,25 @@
.commands {
display: flex;
flex-direction: column;
- border-bottom: 1px solid var(--border-color);
- border-top: 1px solid var(--border-color);
- padding: .5em;
}
gr-copy-clipboard {
width: 60em;
margin-bottom: .5em;
}
+ .hidden {
+ display: none;
+ }
</style>
<div class="schemes">
- <ul hidden$="[[!schemes.length]]" hidden>
+ <paper-tabs
+ id="downloadTabs"
+ class$="[[_computeShowTabs(schemes)]]"
+ selected="[[_computeSelected(schemes, selectedScheme)]]"
+ on-selected-changed="_handleTabChange">
<template is="dom-repeat" items="[[schemes]]" as="scheme">
- <li selected$="[[_computeSelected(scheme, selectedScheme)]]">
- <gr-button link data-scheme$="[[scheme]]" on-tap="_handleSchemeTap">
- [[scheme]]
- </gr-button>
- </li>
+ <paper-tab data-scheme$="[[scheme]]">[[scheme]]</paper-tab>
</template>
- </ul>
+ </paper-tabs>
</div>
<div class="commands" hidden$="[[!schemes.length]]" hidden>
<template is="dom-repeat"
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
index 8f513cb..319cd04 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
@@ -61,17 +61,24 @@
});
},
- _computeSelected(item, selectedItem) {
- return item === selectedItem;
+ _handleTabChange(e) {
+ const scheme = this.schemes[e.detail.value];
+ if (scheme && scheme !== this.selectedScheme) {
+ this.set('selectedScheme', scheme);
+ if (this._loggedIn) {
+ this.$.restAPI.savePreferences(
+ {download_scheme: this.selectedScheme});
+ }
+ }
},
- _handleSchemeTap(e) {
- e.preventDefault();
- const el = Polymer.dom(e).localTarget;
- this.selectedScheme = el.getAttribute('data-scheme');
- if (this._loggedIn) {
- this.$.restAPI.savePreferences({download_scheme: this.selectedScheme});
- }
+ _computeSelected(schemes, selectedScheme) {
+ return (schemes.findIndex(scheme => scheme === selectedScheme) || 0)
+ + '';
+ },
+
+ _computeShowTabs(schemes) {
+ return schemes.length > 1 ? '' : 'hidden';
},
});
})();
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
index 4fe5569..47219a7 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
@@ -81,30 +81,21 @@
});
test('element visibility', () => {
- assert.isFalse(element.$$('ul').hasAttribute('hidden'));
- assert.isFalse(element.$$('.commands').hasAttribute('hidden'));
+ assert.isFalse(isHidden(element.$$('paper-tabs')));
+ assert.isFalse(isHidden(element.$$('.commands')));
element.schemes = [];
- assert.isTrue(element.$$('ul').hasAttribute('hidden'));
- assert.isTrue(element.$$('.commands').hasAttribute('hidden'));
+ assert.isTrue(isHidden(element.$$('paper-tabs')));
+ assert.isTrue(isHidden(element.$$('.commands')));
});
test('tab selection', () => {
- flushAsynchronousOperations();
- let el = element.$$('[data-scheme="http"]').parentElement;
- assert.isTrue(el.hasAttribute('selected'));
- for (const scheme of ['repo', 'ssh']) {
- const el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
- assert.isFalse(el.hasAttribute('selected'));
- }
-
+ assert.equal(element.$.downloadTabs.selected, '0');
MockInteractions.tap(element.$$('[data-scheme="ssh"]'));
- el = element.$$('[data-scheme="ssh"]').parentElement;
- assert.isTrue(el.hasAttribute('selected'));
- for (const scheme of ['http', 'repo']) {
- const el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
- assert.isFalse(el.hasAttribute('selected'));
- }
+ flushAsynchronousOperations();
+
+ assert.equal(element.selectedScheme, 'ssh');
+ assert.equal(element.$.downloadTabs.selected, '2');
});
test('loads scheme from preferences', done => {
@@ -136,18 +127,18 @@
test('saves scheme to preferences', () => {
element._loggedIn = true;
- const savePrefsStub = sinon.stub(element.$.restAPI, 'savePreferences',
+ const savePrefsStub = sandbox.stub(element.$.restAPI, 'savePreferences',
() => { return Promise.resolve(); });
flushAsynchronousOperations();
- const firstSchemeButton = element.$$('li gr-button[data-scheme]');
+ const repoTab = element.$$('paper-tab[data-scheme="repo"]');
- MockInteractions.tap(firstSchemeButton);
+ MockInteractions.tap(repoTab);
assert.isTrue(savePrefsStub.called);
assert.equal(savePrefsStub.lastCall.args[0].download_scheme,
- firstSchemeButton.getAttribute('data-scheme'));
+ repoTab.getAttribute('data-scheme'));
});
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
index 5da46ae..dcb428f 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
@@ -78,10 +78,6 @@
},
},
- listeners: {
- tap: '_handleTap',
- },
-
behaviors: [
Gerrit.BaseUrlBehavior,
Gerrit.KeyboardShortcutBehavior,
@@ -294,10 +290,5 @@
_computeIsDownload(link) {
return !!link.download;
},
-
- _handleTap(e) {
- e.preventDefault();
- e.stopImmediatePropagation();
- },
});
})();
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
index 250c416..456f235 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
@@ -112,21 +112,16 @@
});
test('non link items', () => {
- const nativeTapHandler = sandbox.stub();
const item0 = {name: 'item one', id: 'foo'};
element.items = [item0, {name: 'item two', id: 'bar'}];
const fooTapped = sandbox.stub();
const tapped = sandbox.stub();
element.addEventListener('tap-item-foo', fooTapped);
element.addEventListener('tap-item', tapped);
- element.addEventListener('tap', nativeTapHandler);
flushAsynchronousOperations();
-
MockInteractions.tap(element.$$('.itemAction'));
assert.isTrue(fooTapped.called);
assert.isTrue(tapped.called);
- assert.isFalse(nativeTapHandler.called);
-
assert.deepEqual(tapped.lastCall.args[0].detail, item0);
});