Re-do and repair Conduit's maniphestEdit
maniphestEdit was split out over a few methods, nested in unnecessary
`if`s, and added projects already on a Maniphest and did not
effectively allow to delete projects. We simplify the code, make it
work, and add tests.
Change-Id: I2f114cd58fa2c6d173c7f9bfb92d9081a54af673
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/PhabricatorItsFacade.java b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/PhabricatorItsFacade.java
index e3d2e11..94ad847 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/PhabricatorItsFacade.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/PhabricatorItsFacade.java
@@ -48,7 +48,7 @@
public void addComment(final String bugId, final String comment) throws IOException {
int task_id = Integer.parseInt(bugId);
try {
- conduit.maniphestEdit(task_id, comment);
+ conduit.maniphestEdit(task_id, comment, null, null);
} catch (ConduitException e) {
throw new IOException("Could not update message for task " + task_id, e);
}
@@ -81,19 +81,21 @@
String chopped[] = actionString.split(" ");
if (chopped.length >= 1) {
String action = chopped[0];
- switch (action) {
- case "add-project":
- assertParameters(action, chopped, 1);
-
- conduit.maniphestEdit(chopped[1], taskId, Conduit.ACTION_PROJECT_ADD);
- break;
- case "remove-project":
- assertParameters(action, chopped, 1);
-
- conduit.maniphestEdit(chopped[1], taskId, Conduit.ACTION_PROJECT_REMOVE);
- break;
- default:
- throw new IOException("Unknown action " + action);
+ try {
+ switch (action) {
+ case "add-project":
+ assertParameters(action, chopped, 1);
+ conduit.maniphestEdit(taskId, null, chopped[1], null);
+ break;
+ case "remove-project":
+ assertParameters(action, chopped, 1);
+ conduit.maniphestEdit(taskId, null, null, chopped[1]);
+ break;
+ default:
+ throw new IOException("Unknown action " + action);
+ }
+ } catch (ConduitException e) {
+ throw new IOException("Could not perform action " + action, e);
}
} else {
throw new IOException("Could not parse action " + actionString);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/Conduit.java b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/Conduit.java
index 0a61f34..cea0908 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/Conduit.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/Conduit.java
@@ -14,9 +14,9 @@
package com.googlesource.gerrit.plugins.its.phabricator.conduit;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -26,12 +26,10 @@
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ManiphestEdit;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ManiphestSearch;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ProjectSearch;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* Bindings for Phabricator's Conduit API
@@ -92,68 +90,44 @@
}
/** Runs the API's 'maniphest.edit' method */
- public ManiphestEdit maniphestEdit(int taskId, String comment) throws ConduitException {
- return maniphestEdit(taskId, comment, null, ACTION_COMMENT);
- }
-
- /** Runs the API's 'maniphest.edit' method */
- public ManiphestEdit maniphestEdit(int taskId, Iterable<String> projects, String action)
- throws ConduitException {
- return maniphestEdit(taskId, null, projects, action);
- }
-
- public void maniphestEdit(String projectName, int taskId, String actions) throws IOException {
- try {
- ProjectSearch projectSearch = projectSearch(projectName);
- String projectPhid = projectSearch.getPhid();
-
- Set<String> projectPhids = Sets.newHashSet(projectPhid);
-
- ManiphestSearch taskSearch = maniphestSearch(taskId);
- for (JsonElement jsonElement2 :
- taskSearch.getAttachments().getProjects().getProjectPHIDs().getAsJsonArray()) {
- projectPhids.add(jsonElement2.getAsString());
- }
-
- maniphestEdit(taskId, projectPhids, actions);
- } catch (ConduitException e) {
- throw new IOException("Error on conduit", e);
- }
- }
-
- /** Runs the API's 'maniphest.edit' method */
public ManiphestEdit maniphestEdit(
- int taskId, String comment, Iterable<String> projects, String action)
+ int taskId, String comment, String projectNameToAdd, String projectNameToRemove)
throws ConduitException {
- HashMap<String, Object> params = new HashMap<>();
- HashMap<String, Object> transaction = new HashMap<>();
+ ManiphestEdit result = null;
List<Object> transactions = new ArrayList<>();
- transaction.put("type", action);
- if (action.equals(ACTION_COMMENT)) {
- if (comment == null) {
- throw new IllegalArgumentException(
- "The value of comment (null) is invalid for the action" + action);
- }
+
+ if (!Strings.isNullOrEmpty(comment)) {
+ HashMap<String, Object> transaction = new HashMap<>();
+ transaction.put("type", ACTION_COMMENT);
transaction.put("value", comment);
- }
- if (action.equals(ACTION_PROJECT_ADD) || action.equals(ACTION_PROJECT_REMOVE)) {
- if ((action.equals(ACTION_PROJECT_ADD) || action.equals(ACTION_PROJECT_REMOVE))
- && projects == null) {
- throw new IllegalArgumentException(
- "The value of projects (null) is invalid for the action " + action);
- }
- transaction.put("value", projects);
- }
-
- if (!transaction.isEmpty()) {
transactions.add(transaction);
- params.put("transactions", transactions);
}
- params.put("objectIdentifier", taskId);
- JsonElement callResult = conduitConnection.call("maniphest.edit", params, token);
- ManiphestEdit result = gson.fromJson(callResult, ManiphestEdit.class);
+ if (!Strings.isNullOrEmpty(projectNameToAdd)) {
+ HashMap<String, Object> transaction = new HashMap<>();
+ transaction.put("type", ACTION_PROJECT_ADD);
+ transaction.put("value", ImmutableList.of(projectSearch(projectNameToAdd).getPhid()));
+
+ transactions.add(transaction);
+ }
+
+ if (!Strings.isNullOrEmpty(projectNameToRemove)) {
+ HashMap<String, Object> transaction = new HashMap<>();
+ transaction.put("type", ACTION_PROJECT_REMOVE);
+ transaction.put("value", ImmutableList.of(projectSearch(projectNameToRemove).getPhid()));
+
+ transactions.add(transaction);
+ }
+
+ if (!transactions.isEmpty()) {
+ HashMap<String, Object> params = new HashMap<>();
+ params.put("objectIdentifier", taskId);
+ params.put("transactions", transactions);
+ JsonElement callResult = conduitConnection.call("maniphest.edit", params, token);
+ result = gson.fromJson(callResult, ManiphestEdit.class);
+ }
+
return result;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/GenericEdit.java b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/GenericEdit.java
new file mode 100644
index 0000000..b01db44
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/GenericEdit.java
@@ -0,0 +1,57 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.phabricator.conduit.results;
+
+import java.util.List;
+
+/**
+ * Models the result for API methods
+ *
+ * <p>JSON looks like:
+ *
+ * <pre>
+ * {
+ * "object":{
+ * "id":2,
+ * "phid":"PHID-TASK-wzydcwamkp5rjhg45ocq"
+ * },
+ * "transactions":[
+ * {"phid":"PHID-XACT-TASK-sghfp7saytwmun3"}
+ * ]
+ * }
+ * </pre>
+ */
+public class GenericEdit {
+ private ResultObject object;
+ private List<Transaction> transactions;
+
+ public ResultObject getObject() {
+ return object;
+ }
+
+ public List<Transaction> getTransactions() {
+ return transactions;
+ }
+
+ public class Transaction extends PhabObject {}
+
+ public class ResultObject extends PhabObject {
+ private int id;
+
+ public int getId() {
+ return id;
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/ManiphestEdit.java b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/ManiphestEdit.java
index e9e3805..dc416dd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/ManiphestEdit.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/ManiphestEdit.java
@@ -20,31 +20,14 @@
*
* <pre>
* {
- * "id":"48",
- * "phid":"PHID-TASK-pemd324eosnymq3tdkyo",
- * "authorPHID":"PHID-USER-na3one2sht11aone",
- * "ownerPHID":null,
- * "ccPHIDs":[
- * "PHID-USER-h4n62fq2kt2v3a2qjyqh"
- * ],
- * "status":"open",
- * "statusName":"Open",
- * "isClosed":false,
- * "priority": "Needs Triage",
- * "priorityColor":"violet",
- * "title":"QChris test task",
- * "description":"",
- * "projectPHIDs":[],
- * "uri":"https://phab-01.wmflabs.org/T47",
- * "auxiliary":{
- * "std:maniphest:security_topic":"default",
- * "isdc:sprint:storypoints":null
+ * "object":{
+ * "id":2,
+ * "phid":"PHID-TASK-wzydcwamkp5rjhg45ocq"
* },
- * "objectName":"T47",
- * "dateCreated":"1413484594",
- * "dateModified":1413549869,
- * "dependsOnTaskPHIDs":[]
+ * "transactions":[
+ * {"phid":"PHID-XACT-TASK-sghfp7saytwmun3"}
+ * ]
* }
* </pre>
*/
-public class ManiphestEdit extends Task {}
+public class ManiphestEdit extends GenericEdit {}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/PhabObject.java b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/PhabObject.java
new file mode 100644
index 0000000..bc2cd46
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/results/PhabObject.java
@@ -0,0 +1,23 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.phabricator.conduit.results;
+
+public class PhabObject {
+ private String phid;
+
+ public String getPhid() {
+ return phid;
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/ConduitTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/ConduitTest.java
index 20f9f17..6a57860 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/ConduitTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/phabricator/conduit/ConduitTest.java
@@ -15,11 +15,15 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -27,6 +31,7 @@
import com.google.gson.JsonPrimitive;
import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ConduitPing;
+import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ManiphestEdit;
import com.googlesource.gerrit.plugins.its.phabricator.conduit.results.ProjectSearch;
import java.util.HashMap;
import java.util.Map;
@@ -109,7 +114,166 @@
assertThat(actual.getPhid()).isEqualTo("PHID-PROJ-foo");
}
- // TODO: Add tests for maniphestEdit
+ @Test
+ public void testManiphestEditNoop() throws Exception {
+ Conduit conduit = createConduit();
+ ManiphestEdit actual = conduit.maniphestEdit(4711, null, null, null);
+
+ verifyZeroInteractions(conduitConnection);
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void testManiphestEditEmpty() throws Exception {
+ Conduit conduit = createConduit();
+ ManiphestEdit actual = conduit.maniphestEdit(4711, "", "", "");
+
+ verifyZeroInteractions(conduitConnection);
+ assertThat(actual).isNull();
+ }
+
+ @Test
+ public void testManiphestEditAddComment() throws Exception {
+ Map<String, Object> transaction = new HashMap<>();
+ transaction.put("type", "comment");
+ transaction.put("value", "foo");
+
+ Map<String, Object> params = new HashMap<>();
+ params.put("objectIdentifier", 4711);
+ params.put("transactions", ImmutableList.of(transaction));
+
+ JsonArray data = new JsonArray();
+ data.add(createProjectJson(2, "foo"));
+
+ JsonObject response = createEditResponse(1);
+ when(conduitConnection.call("maniphest.edit", params, TOKEN)).thenReturn(response);
+
+ Conduit conduit = createConduit();
+
+ ManiphestEdit actual = conduit.maniphestEdit(4711, "foo", null, null);
+
+ assertThat(actual.getObject().getId()).isEqualTo(4712);
+ assertThat(actual.getObject().getPhid()).isEqualTo("PHID-foo");
+ assertThat(actual.getTransactions()).hasSize(1);
+ assertThat(actual.getTransactions().get(0).getPhid()).isEqualTo("trans@0");
+ }
+
+ @Test
+ public void testManiphestEditAddProject() throws Exception {
+ Map<String, Object> transaction = new HashMap<>();
+ transaction.put("type", "projects.add");
+ transaction.put("value", ImmutableList.of("PHID-bar"));
+
+ Map<String, Object> params = new HashMap<>();
+ params.put("objectIdentifier", 4711);
+ params.put("transactions", ImmutableList.of(transaction));
+
+ JsonArray data = new JsonArray();
+ data.add(createProjectJson(2, "foo"));
+
+ JsonObject response = createEditResponse(1);
+ when(conduitConnection.call("maniphest.edit", params, TOKEN)).thenReturn(response);
+
+ Conduit conduit = spy(createConduit());
+
+ // shortcut the needed project search
+ doReturn(new ProjectSearch(12, "PHID-bar")).when(conduit).projectSearch("foo");
+
+ ManiphestEdit actual = conduit.maniphestEdit(4711, null, "foo", null);
+
+ assertThat(actual.getObject().getId()).isEqualTo(4712);
+ assertThat(actual.getObject().getPhid()).isEqualTo("PHID-foo");
+ assertThat(actual.getTransactions()).hasSize(1);
+ assertThat(actual.getTransactions().get(0).getPhid()).isEqualTo("trans@0");
+ }
+
+ @Test
+ public void testManiphestEditRemoveProject() throws Exception {
+ Map<String, Object> transaction = new HashMap<>();
+ transaction.put("type", "projects.remove");
+ transaction.put("value", ImmutableList.of("PHID-bar"));
+
+ Map<String, Object> params = new HashMap<>();
+ params.put("objectIdentifier", 4711);
+ params.put("transactions", ImmutableList.of(transaction));
+
+ JsonArray data = new JsonArray();
+ data.add(createProjectJson(2, "foo"));
+
+ JsonObject response = createEditResponse(1);
+ when(conduitConnection.call("maniphest.edit", params, TOKEN)).thenReturn(response);
+
+ Conduit conduit = spy(createConduit());
+
+ // shortcut the needed project search
+ doReturn(new ProjectSearch(12, "PHID-bar")).when(conduit).projectSearch("foo");
+
+ ManiphestEdit actual = conduit.maniphestEdit(4711, null, null, "foo");
+
+ assertThat(actual.getObject().getId()).isEqualTo(4712);
+ assertThat(actual.getObject().getPhid()).isEqualTo("PHID-foo");
+ assertThat(actual.getTransactions()).hasSize(1);
+ assertThat(actual.getTransactions().get(0).getPhid()).isEqualTo("trans@0");
+ }
+
+ @Test
+ public void testManiphestEditAllParams() throws Exception {
+ Map<String, Object> transaction1 = new HashMap<>();
+ transaction1.put("type", "comment");
+ transaction1.put("value", "foo");
+
+ Map<String, Object> transaction2 = new HashMap<>();
+ transaction2.put("type", "projects.add");
+ transaction2.put("value", ImmutableList.of("PHID-bar"));
+
+ Map<String, Object> transaction3 = new HashMap<>();
+ transaction3.put("type", "projects.remove");
+ transaction3.put("value", ImmutableList.of("PHID-baz"));
+
+ Map<String, Object> params = new HashMap<>();
+ params.put("objectIdentifier", 4711);
+ params.put("transactions", ImmutableList.of(transaction1, transaction2, transaction3));
+
+ JsonArray data = new JsonArray();
+ data.add(createProjectJson(2, "foo"));
+
+ JsonObject response = createEditResponse(3);
+ when(conduitConnection.call("maniphest.edit", params, TOKEN)).thenReturn(response);
+
+ Conduit conduit = spy(createConduit());
+
+ // shortcut the needed project searches
+ doReturn(new ProjectSearch(12, "PHID-bar")).when(conduit).projectSearch("bar");
+ doReturn(new ProjectSearch(12, "PHID-baz")).when(conduit).projectSearch("baz");
+
+ ManiphestEdit actual = conduit.maniphestEdit(4711, "foo", "bar", "baz");
+
+ assertThat(actual.getObject().getId()).isEqualTo(4712);
+ assertThat(actual.getObject().getPhid()).isEqualTo("PHID-foo");
+ assertThat(actual.getTransactions()).hasSize(3);
+ assertThat(actual.getTransactions().get(0).getPhid()).isEqualTo("trans@0");
+ assertThat(actual.getTransactions().get(1).getPhid()).isEqualTo("trans@1");
+ assertThat(actual.getTransactions().get(2).getPhid()).isEqualTo("trans@2");
+ }
+
+ private JsonObject createEditResponse(int transactions) {
+ JsonObject resultObject = new JsonObject();
+ resultObject.addProperty("id", 4712);
+ resultObject.addProperty("phid", "PHID-foo");
+
+ JsonArray transactionArray = new JsonArray();
+ for (int i = 0; i < transactions; i++) {
+ JsonObject transaction = new JsonObject();
+ transaction.addProperty("phid", "trans@" + i);
+ transactionArray.add(transaction);
+ }
+
+ JsonObject response = new JsonObject();
+ response.add("object", resultObject);
+ response.add("transactions", transactionArray);
+
+ return response;
+ }
private JsonObject createProjectJson(int id, String name) {
JsonObject fields = new JsonObject();