Set up test infrastructure

Database is populated in init plugin step. There is no way to use
init step code in plugin test class, because of deep Guice graph.
Instead we create the table manually. This has a drawback that when
the entity class is modified, the test must be adjusted as well.
We don't expect this to happen very frequently, though.

To run the test:

  $ buck test --include verify-status
  [-] TESTING...FINISHED 11.6s (1 PASS/0 FAIL)
  RESULTS FOR ALL TESTS
  PASS     10.6s  1 Passed   0 Skipped   0 Failed
  com.googlesource.gerrit.plugins.verifystatus.VerifyStatusIT
  TESTS PASSED

Change-Id: I36f59810d5a3e74bdc163ba0790cda9d9786ae7e
diff --git a/.buckconfig b/.buckconfig
index 74511c1..0941191 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -1,5 +1,5 @@
 [alias]
-  ci = //:verify-status
+  verify-status = //:verify-status
   plugin = //:verify-status
 
 [java]
diff --git a/.gitignore b/.gitignore
index aa42023..5e2d355 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,5 @@
 /local.properties
 *.pyc
 .buckversion
+.watchmanconfig
 /bucklets
diff --git a/pom.xml b/pom.xml
index 1199a53..239386f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,6 +88,23 @@
           </execution>
         </executions>
       </plugin>
+ 
+ <!--
+ Maven IT tests is failing so commenting out for now.
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <version>2.19.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>integration-test</goal>
+              <goal>verify</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+-->
 
     </plugins>
   </build>
@@ -111,6 +128,24 @@
       <version>2.7.0</version>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.truth</groupId>
+      <artifactId>truth</artifactId>
+      <version>0.27</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.gerrit</groupId>
+      <artifactId>gerrit-acceptance-framework</artifactId>
+      <version>${Gerrit-ApiVersion}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <repositories>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/PostVerification.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/PostVerification.java
index 2c623f0..4cee0af 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/PostVerification.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/PostVerification.java
@@ -201,7 +201,7 @@
    */
   private void checkPermission() throws PermissionDeniedException {
     CapabilityControl ctl = userProvider.get().getCapabilities();
-    if (!ctl.canPerform(pluginName + "-" + SaveReportCapability.ID)) {
+    if (!ctl.canPerform(SaveReportCapability.getName(pluginName))) {
       throw new PermissionDeniedException(String.format(
           "%s does not have \"%s\" capability.",
           userProvider.get().getUserName(),
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/SaveReportCapability.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/SaveReportCapability.java
index 7d94f1a..994c555 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/SaveReportCapability.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/SaveReportCapability.java
@@ -23,4 +23,8 @@
   public String getDescription() {
     return "Save Verification Report";
   }
+
+  public static String getName(String pluginName) {
+    return pluginName + "-" + ID;
+  }
 }
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 59264f2..b3a336a 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -10,7 +10,7 @@
 The standalone build mode is recommended, as this mode doesn't require
 the Gerrit tree to exist locally.
 
-
+### Build standalone
 
 Clone bucklets library:
 
@@ -48,6 +48,13 @@
   buck-out/gen/@PLUGIN@.jar
 ```
 
+To execute the tests run:
+
+```
+  buck test
+```
+
+### Build in Gerrit tree
 
 Clone or link this plugin to the plugins directory of Gerrit's source
 tree, and issue the command:
@@ -68,6 +75,12 @@
   ./tools/eclipse/project.py
 ```
 
+To execute the tests run:
+
+```
+  buck test --include @PLUGIN@
+```
+
 Maven
 -----
 
diff --git a/src/test/java/com/googlesource/gerrit/plugins/verifystatus/VerifyStatusIT.java b/src/test/java/com/googlesource/gerrit/plugins/verifystatus/VerifyStatusIT.java
new file mode 100644
index 0000000..0550ffd
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/verifystatus/VerifyStatusIT.java
@@ -0,0 +1,174 @@
+// Copyright (C) 2016 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.verifystatus;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.PluginDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit.Result;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gson.reflect.TypeToken;
+import com.google.gwtorm.jdbc.SimpleDataSource;
+
+import com.googlesource.gerrit.plugins.verifystatus.common.VerificationInfo;
+import com.googlesource.gerrit.plugins.verifystatus.common.VerifyInput;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public class VerifyStatusIT extends PluginDaemonTest {
+  private final static String TABLE = "PATCH_SET_VERIFICATIONS";
+  private static final String CREATE_TABLE =
+      "CREATE       TABLE IF NOT EXISTS " + TABLE + " (" +
+      "VALUE        SMALLINT DEFAULT 0 NOT NULL," +
+      "GRANTED      TIMESTAMP NOT NULL," +
+      "URL          VARCHAR(255)," +
+      "REPORTER     VARCHAR(255)," +
+      "COMMENT      VARCHAR(255)," +
+      "CATEGORY     VARCHAR(255)," +
+      "DURATION     VARCHAR(255)," +
+      "ABSTAIN      CHAR(1) DEFAULT 'N' NOT NULL," +
+      "NAME         VARCHAR(255)," +
+      "CHANGE_ID    INTEGER DEFAULT 0 NOT NULL," +
+      "PATCH_SET_ID INTEGER DEFAULT 0 NOT NULL," +
+      "JOB_ID       VARCHAR(255) DEFAULT '' NOT NULL)";
+  private static final String DELETE_TABLE =
+      "DELETE FROM " + TABLE;
+
+  @Override
+  protected void beforeTestServerStarts() throws Exception {
+    String url = "jdbc:h2:mem:TestCiDB;DB_CLOSE_DELAY=-1";
+    Properties p = new Properties();
+    p.setProperty("driver", "org.h2.Driver");
+    p.setProperty("url", url);
+    setPluginConfigString("dbType", "h2");
+    setPluginConfigString("dbUrl", url);
+
+    SimpleDataSource sds = new SimpleDataSource(p);
+    try (Connection c = sds.getConnection();
+        Statement s = c.createStatement()) {
+      s.executeUpdate(CREATE_TABLE);
+      // run the tests with the clean database
+      s.execute(DELETE_TABLE);
+    }
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    allowGlobalCapabilities(REGISTERED_USERS,
+        SaveReportCapability.getName(pluginName));
+  }
+
+  @Test
+  public void noVerificationTest() throws Exception {
+    Result c = createChange();
+    Map<String, VerificationInfo> infos = getVerifications(c);
+    assertThat(infos).hasSize(0);
+  }
+
+  @Test
+  public void verificationOneTest() throws Exception {
+    VerifyInput in = new VerifyInput();
+    in.verifications = new HashMap<>();
+    VerificationInfo i = new VerificationInfo();
+    i.name = "job42";
+    i.value = 1;
+    i.reporter = "zuul@openstack.org";
+    i.comment = "Test CI";
+    i.url = "url";
+    i.category = "bar";
+    i.duration = "1h 30min";
+    in.verifications.put("foo", i);
+
+    Result c = createChange();
+    String endPoint = url(c);
+    RestResponse r = adminRestSession.post(endPoint, in);
+    r.assertNoContent();
+
+    Map<String, VerificationInfo> infos = getVerifications(c);
+    assertThat(infos).hasSize(1);
+    assertVerification(Iterables.getOnlyElement(infos.values()), i);
+  }
+
+  @Test
+  public void verificationTwoTest() throws Exception {
+    VerifyInput in = new VerifyInput();
+    in.verifications = new HashMap<>();
+    VerificationInfo i = new VerificationInfo();
+    i.name = "job43";
+    i.value = 1;
+    i.reporter = "zuul@openstack.org";
+    i.comment = "Test CI";
+    i.url = "url";
+    i.category = "bar";
+    i.duration = "1h 30min";
+    in.verifications.put(i.name, i);
+
+    VerificationInfo j = new VerificationInfo();
+    j = new VerificationInfo();
+    j.name = "job44";
+    j.value = -1;
+    j.reporter = "zuul@openstack.org";
+    j.comment = "Test CI";
+    j.url = "url";
+    j.category = "bar";
+    j.duration = "1h 30min";
+    in.verifications.put(j.name, j);
+
+    Result c = createChange();
+    String endPoint = url(c);
+    RestResponse r = adminRestSession.post(endPoint, in);
+    r.assertNoContent();
+
+    Map<String, VerificationInfo> infos = getVerifications(c);
+    assertThat(infos).hasSize(2);
+  }
+
+  private Map<String, VerificationInfo> getVerifications(Result c)
+      throws Exception {
+    String endPoint = url(c);
+    RestResponse r = adminRestSession.get(endPoint);
+    r.assertOK();
+
+    return newGson().fromJson(r.getReader(),
+        new TypeToken<Map<String, VerificationInfo>>() {}.getType());
+  }
+
+  private String url(Result c) throws Exception {
+    return "/changes/" +
+        c.getChangeId() +
+        "/revisions/" +
+        c.getPatchSetId().get() +
+        "/verify-status~verifications";
+  }
+
+  private static void assertVerification(VerificationInfo r,
+      VerificationInfo e) {
+    assertThat(r.value).isEqualTo(e.value);
+    assertThat(r.reporter).isEqualTo(e.reporter);
+    assertThat(r.comment).isEqualTo(e.comment);
+    assertThat(r.url).isEqualTo(e.url);
+    assertThat(r.category).isEqualTo(e.category);
+    assertThat(r.duration).isEqualTo(e.duration);
+  }
+}