Merge "Pass actions through to Its"
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java
index 13ab6de..029ef8d 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java
@@ -14,12 +14,39 @@
 
 package com.googlesource.gerrit.plugins.hooks.workflow;
 
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.hooks.its.ItsFacade;
+
 /**
  * Executes an {@link ActionRequest}
  */
 public class ActionExecutor {
+  private static final Logger log = LoggerFactory.getLogger(
+      ActionExecutor.class);
+
+  private final ItsFacade its;
+
+  @Inject
+  public ActionExecutor(ItsFacade its) {
+    this.its = its;
+  }
+
+  public void execute(String issue, ActionRequest actionRequest) {
+    try {
+      its.performAction(issue, actionRequest.getUnparsed());
+    } catch (IOException e) {
+      log.error("Error while executing action " + actionRequest, e);
+    }
+  }
+
   public void execute(String issue, Iterable<ActionRequest> actions) {
-    // TODO implement
-    throw new RuntimeException("unimplemented");
+    for (ActionRequest actionRequest : actions) {
+        execute(issue, actionRequest);
+    }
   }
 }
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequest.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequest.java
index bbf2690..89e4bde 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequest.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequest.java
@@ -26,6 +26,7 @@
  * changing an issue's status).
  */
 public class ActionRequest {
+  private final String unparsed;
 
   public interface Factory {
     ActionRequest create(String specification);
@@ -33,5 +34,24 @@
 
   @Inject
   public ActionRequest(@Nullable @Assisted String specification) {
+    if (specification == null) {
+      this.unparsed = "";
+    } else {
+      this.unparsed = specification;
+    }
+  }
+
+  /**
+   * Gets the unparsed specification of this action request.
+   *
+   * @return The unparsed action request.
+   */
+  public String getUnparsed() {
+    return unparsed;
+  }
+
+  @Override
+  public String toString() {
+    return getUnparsed();
   }
 }
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java
new file mode 100644
index 0000000..5a93b4c
--- /dev/null
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java
@@ -0,0 +1,119 @@
+// Copyright (C) 2013 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.hooks.workflow;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+
+import java.io.IOException;
+
+import com.google.common.collect.Sets;
+import com.google.gerrit.server.config.FactoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.googlesource.gerrit.plugins.hooks.its.ItsFacade;
+import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase;
+
+public class ActionExecutorTest extends LoggingMockingTestCase {
+  private Injector injector;
+
+  private ItsFacade its;
+
+  public void testExecuteItem() throws IOException {
+    ActionRequest actionRequest = createMock(ActionRequest.class);
+    expect(actionRequest.getUnparsed()).andReturn("unparsed action 1");
+
+    its.performAction("4711", "unparsed action 1");
+
+    replayMocks();
+
+    ActionExecutor actionExecutor = createActionExecutor();
+    actionExecutor.execute("4711", actionRequest);
+  }
+
+  public void testExecuteItemException() throws IOException {
+    ActionRequest actionRequest = createMock(ActionRequest.class);
+    expect(actionRequest.getUnparsed()).andReturn("unparsed action 1");
+
+    its.performAction("4711", "unparsed action 1");
+    expectLastCall().andThrow(new IOException("injected exception 1"));
+
+    replayMocks();
+
+    ActionExecutor actionExecutor = createActionExecutor();
+    actionExecutor.execute("4711", actionRequest);
+
+    assertLogThrowableMessageContains("injected exception 1");
+  }
+
+  public void testExecuteIterable() throws IOException {
+    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    expect(actionRequest1.getUnparsed()).andReturn("unparsed action 1");
+
+    ActionRequest actionRequest2 = createMock(ActionRequest.class);
+    expect(actionRequest2.getUnparsed()).andReturn("unparsed action 2");
+
+    its.performAction("4711", "unparsed action 1");
+    its.performAction("4711", "unparsed action 2");
+
+    replayMocks();
+
+    ActionExecutor actionExecutor = createActionExecutor();
+    actionExecutor.execute("4711", Sets.newHashSet(
+        actionRequest1, actionRequest2));
+  }
+
+  public void testExecuteIterableExceptions() throws IOException {
+    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    expect(actionRequest1.getUnparsed()).andReturn("unparsed action 1");
+
+    ActionRequest actionRequest2 = createMock(ActionRequest.class);
+    expect(actionRequest2.getUnparsed()).andReturn("unparsed action 2");
+
+    ActionRequest actionRequest3 = createMock(ActionRequest.class);
+    expect(actionRequest3.getUnparsed()).andReturn("unparsed action 3");
+
+    its.performAction("4711", "unparsed action 1");
+    expectLastCall().andThrow(new IOException("injected exception 1"));
+    its.performAction("4711", "unparsed action 2");
+    its.performAction("4711", "unparsed action 3");
+    expectLastCall().andThrow(new IOException("injected exception 3"));
+
+    replayMocks();
+
+    ActionExecutor actionExecutor = createActionExecutor();
+    actionExecutor.execute("4711", Sets.newHashSet(
+        actionRequest1, actionRequest2, actionRequest3));
+
+    assertLogThrowableMessageContains("injected exception 1");
+    assertLogThrowableMessageContains("injected exception 3");
+  }
+
+  private ActionExecutor createActionExecutor() {
+    return injector.getInstance(ActionExecutor.class);
+  }
+
+  public void setUp() throws Exception {
+    super.setUp();
+    injector = Guice.createInjector(new TestModule());
+  }
+
+  private class TestModule extends FactoryModule {
+    @Override
+    protected void configure() {
+      its = createMock(ItsFacade.class);
+      bind(ItsFacade.class).toInstance(its);
+    }
+  }
+}
\ No newline at end of file
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequestTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequestTest.java
new file mode 100644
index 0000000..2445b98
--- /dev/null
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionRequestTest.java
@@ -0,0 +1,75 @@
+// Copyright (C) 2013 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.hooks.workflow;
+
+import java.io.IOException;
+
+import com.google.gerrit.server.config.FactoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase;
+
+public class ActionRequestTest extends LoggingMockingTestCase {
+  private Injector injector;
+
+  public void testUnparsedParameterless() throws IOException {
+    replayMocks();
+
+    ActionRequest actionRequest = createActionRequest("action");
+    assertEquals("Unparsed string does not match", "action",
+        actionRequest.getUnparsed());
+  }
+
+  public void testUnparsedNull() throws IOException {
+    replayMocks();
+
+    ActionRequest actionRequest = createActionRequest(null);
+    assertEquals("Unparsed string does not match", "",
+        actionRequest.getUnparsed());
+  }
+
+  public void testUnparsedSingleParameter() throws IOException {
+    replayMocks();
+
+    ActionRequest actionRequest = createActionRequest("action param");
+    assertEquals("Unparsed string does not match", "action param",
+        actionRequest.getUnparsed());
+  }
+
+  public void testUnparsedMultipleParameters() throws IOException {
+    replayMocks();
+
+    ActionRequest actionRequest = createActionRequest("action param1 param2");
+    assertEquals("Unparsed string does not match", "action param1 param2",
+        actionRequest.getUnparsed());
+  }
+
+  private ActionRequest createActionRequest(String specification) {
+    ActionRequest.Factory factory = injector.getInstance(
+        ActionRequest.Factory.class);
+    return factory.create(specification);
+  }
+
+  public void setUp() throws Exception {
+    super.setUp();
+    injector = Guice.createInjector(new TestModule());
+  }
+
+  private class TestModule extends FactoryModule {
+    @Override
+    protected void configure() {
+      factory(ActionRequest.Factory.class);
+    }
+  }
+}
\ No newline at end of file