Add unit test support of IntelliJ plugin.

Summary:
By double-clicking the test target listed in the target list,
unit test will run.

Also add a button "Test all".
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java b/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java
index 2b0cdf6..9b971ff 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java
@@ -21,6 +21,7 @@
 import com.facebook.buck.plugin.intellij.commands.CleanCommand;
 import com.facebook.buck.plugin.intellij.commands.SocketClient.BuckPluginEventListener;
 import com.facebook.buck.plugin.intellij.commands.TargetsCommand;
+import com.facebook.buck.plugin.intellij.commands.TestCommand;
 import com.facebook.buck.plugin.intellij.commands.event.Event;
 import com.facebook.buck.plugin.intellij.commands.event.RuleEnd;
 import com.facebook.buck.plugin.intellij.commands.event.RuleStart;
@@ -167,6 +168,45 @@
     }
   }
 
+  public void testTarget(final BuckTarget target) {
+    Preconditions.checkNotNull(target);
+    try {
+      final BuckRunner buckRunner = getBuckRunner();
+      Task.Backgroundable task = new Task.Backgroundable(project,
+          "Testing",
+          true, /* canBeCanceled */
+          BackgroundFromStartOption.getInstance()) {
+        public void run(ProgressIndicator progressIndicator) {
+          buckUI.getProgressPanel().clear();
+          buckUI.showMessageWindow();
+          TestCommand.runTest(buckRunner, Optional.of(target));
+        }
+      };
+      task.queue();
+    } catch (NoBuckRunnerException e) {
+      reportBuckNotPresent();
+    }
+  }
+
+  public void testAllTargets() {
+    try {
+      final BuckRunner buckRunner = getBuckRunner();
+      Task.Backgroundable task = new Task.Backgroundable(project,
+          "Testing",
+          true, /* canBeCanceled */
+          BackgroundFromStartOption.getInstance()) {
+        public void run(ProgressIndicator progressIndicator) {
+          buckUI.getProgressPanel().clear();
+          buckUI.showMessageWindow();
+          TestCommand.runTest(buckRunner, Optional.<BuckTarget>absent());
+        }
+      };
+      task.queue();
+    } catch (NoBuckRunnerException e) {
+      reportBuckNotPresent();
+    }
+  }
+
   public ImmutableList<BuckTarget> getTargets() {
     return targets;
   }
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/BuckTarget.java b/plugin/src/com/facebook/buck/plugin/intellij/BuckTarget.java
index 59e8d09..0267950 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/BuckTarget.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/BuckTarget.java
@@ -60,6 +60,8 @@
       nodeType = TargetNode.Type.JAVA_BINARY;
     } else if ("java_test".equals(type)) {
       nodeType = TargetNode.Type.JAVA_TEST;
+    } else if ("sh_test".equals(type)) {
+      nodeType = TargetNode.Type.SH_TEST;
     } else {
       nodeType = TargetNode.Type.OTHER;
     }
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/commands/TestCommand.java b/plugin/src/com/facebook/buck/plugin/intellij/commands/TestCommand.java
new file mode 100644
index 0000000..d3a1ef7
--- /dev/null
+++ b/plugin/src/com/facebook/buck/plugin/intellij/commands/TestCommand.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * 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.facebook.buck.plugin.intellij.commands;
+
+import com.facebook.buck.plugin.intellij.BuckTarget;
+import com.google.common.base.Optional;
+import com.intellij.openapi.diagnostic.Logger;
+
+public class TestCommand {
+
+  private static final Logger LOG = Logger.getInstance(TestCommand.class);
+
+  private TestCommand() {}
+
+  public static void runTest(BuckRunner buckRunner, Optional<BuckTarget> target) {
+    String targetName = target.isPresent() ? target.get().getFullName() : "--all";
+    int exitCode = buckRunner.executeAndListenToWebsocket("test", targetName);
+    if (exitCode != 0) {
+      // TODO Show stdout to a console tab
+      LOG.error(buckRunner.getStderr());
+    }
+  }
+}
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.form b/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.form
index bff79b4..fab897f 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.form
+++ b/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.form
@@ -34,6 +34,13 @@
               <text value="Clean"/>
             </properties>
           </component>
+          <component id="2a50e" class="javax.swing.JButton" binding="testAllButton" custom-create="true">
+            <constraints/>
+            <properties>
+              <text value="Test All"/>
+              <toolTipText value="Run all unit tests"/>
+            </properties>
+          </component>
         </children>
       </toolbar>
       <scrollpane id="8bbd6" binding="scrollPane" custom-create="true">
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.java b/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.java
index 8feec54..2480df0 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckTargetsPanel.java
@@ -48,6 +48,7 @@
   private JPanel targetsPanel;
   private JButton refreshTargetsButton;
   private JButton cleanButton;
+  private JButton testAllButton;
   private JTree tree;
   @SuppressWarnings("unused")
   private JScrollPane scrollPane;
@@ -101,7 +102,12 @@
           TargetNode targetNode = (TargetNode) selected.getLastPathComponent();
           BuckTarget target = targetNode.getTarget();
           if (target != null) {
-            component.buildTarget(target);
+            if (targetNode.getType() == TargetNode.Type.JAVA_TEST ||
+                targetNode.getType() == TargetNode.Type.SH_TEST) {
+              component.testTarget(target);
+            } else {
+              component.buildTarget(target);
+            }
           }
         }
       }
@@ -124,6 +130,14 @@
         component.clean();
       }
     });
+
+    testAllButton = createToolbarIcon();
+    testAllButton.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        component.testAllTargets();
+      }
+    });
   }
 
   private JButton createToolbarIcon() {
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/ui/TargetNode.java b/plugin/src/com/facebook/buck/plugin/intellij/ui/TargetNode.java
index 1ea73cf..9d0ffa3 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/ui/TargetNode.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/ui/TargetNode.java
@@ -29,6 +29,7 @@
     JAVA_LIBRARY,
     JAVA_BINARY,
     JAVA_TEST,
+    SH_TEST,
     OTHER
   }