Merge branch 'stable-2.15'

* stable-2.15:
  Cross out gerrit_api_maven_local in WORKSPACE

Change-Id: Ifff4b675547450346f923cff55736b378ca0c268
diff --git a/WORKSPACE b/WORKSPACE
index c8cbd68..5591045 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,24 +3,24 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "cbddbc2b9571b1d692fb823ba8791ccd60b52421",
+    commit = "42bffc66c0e92753133e4cea2debe65abc359c4d",
     # local_path = "/home/<user>/projects/bazlets",
 )
 
 # Snapshot Plugin API
-#load(
-#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-#    "gerrit_api_maven_local",
-#)
-
-# Release Plugin API
 load(
-    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
-    "gerrit_api",
+    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+    "gerrit_api_maven_local",
 )
 
+# Release Plugin API
+#load(
+#    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
+#    "gerrit_api",
+#)
+
 # Load release Plugin API
-gerrit_api()
+#gerrit_api()
 
 # Load snapshot Plugin API
-# gerrit_api_maven_local()
+gerrit_api_maven_local()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java
index 91b26a0..37b2fc6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java
@@ -33,7 +33,6 @@
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddSoyComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddStandardComment;
-import com.googlesource.gerrit.plugins.its.base.workflow.action.AddVelocityComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.LogEvent;
 
 public class ItsHookModule extends FactoryModule {
@@ -61,7 +60,6 @@
     factory(AddComment.Factory.class);
     factory(AddSoyComment.Factory.class);
     factory(AddStandardComment.Factory.class);
-    factory(AddVelocityComment.Factory.class);
     factory(LogEvent.Factory.class);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java
index 546e6c7..2809a83 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java
@@ -3,9 +3,13 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.RevisionInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.OrmException;
+import com.google.inject.ImplementedBy;
 import com.google.inject.Inject;
 
 import com.googlesource.gerrit.plugins.its.base.its.ItsConfig;
@@ -14,6 +18,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.EnumSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
@@ -24,13 +29,45 @@
       IssueExtractor.class);
 
   private final CommitMessageFetcher commitMessageFetcher;
-  private final ReviewDb db;
+  private final PatchSetDb db;
   private final ItsConfig itsConfig;
 
+  @ImplementedBy(PatchSetDbImpl.class)
+  public interface PatchSetDb {
+    public String getRevision(PatchSet.Id patchSetId);
+  }
+
+  public static class PatchSetDbImpl implements PatchSetDb {
+    private final GerritApi gApi;
+
+    @Inject
+    public PatchSetDbImpl(GerritApi gApi) {
+      this.gApi = gApi;
+    }
+
+    @Override
+    public String getRevision(PatchSet.Id patchSetId) {
+      try {
+        ChangeInfo info =
+            gApi.changes()
+                .id(patchSetId.getParentKey().get())
+                .get(EnumSet.of(ListChangesOption.ALL_REVISIONS));
+        for (Map.Entry<String, RevisionInfo> e : info.revisions.entrySet()) {
+          if (e.getValue()._number == patchSetId.get()) {
+            return e.getKey();
+          }
+        }
+        return null;
+      } catch (RestApiException e) {
+        // previous is still empty to indicate that there was no previous
+        // accessible patch set. We treat every occurrence as added.
+      }
+      return null;
+    }
+  }
+
   @Inject
-  IssueExtractor(ItsConfig itsConfig,
-      CommitMessageFetcher commitMessageFetcher,
-      ReviewDb db) {
+  IssueExtractor(ItsConfig itsConfig, CommitMessageFetcher commitMessageFetcher, PatchSetDb db) {
     this.commitMessageFetcher = commitMessageFetcher;
     this.db = db;
     this.itsConfig = itsConfig;
@@ -188,23 +225,15 @@
    *    "subject". Issues in the last block get tagged with "footer". Issues
    *    occurring between "subject" and "footer" get tagged with "body".
    */
-  public Map<String,Set<String>> getIssueIds(String projectName,
-      String commitId, PatchSet.Id patchSetId) {
-    Map<String,Set<String>> current = getIssueIds(projectName, commitId);
+  public Map<String, Set<String>> getIssueIds(String projectName, String commitId, PatchSet.Id patchSetId) {
+    Map<String, Set<String>> current = getIssueIds(projectName, commitId);
     if (patchSetId != null) {
-      Map<String,Set<String>> previous = Maps.newHashMap();
+      Map<String, Set<String>> previous = Maps.newHashMap();
       if (patchSetId.get() != 1) {
-        PatchSet.Id previousPatchSetId = new PatchSet.Id(
-            patchSetId.getParentKey(), patchSetId.get() - 1);
-        try {
-          PatchSet previousPatchSet = db.patchSets().get(previousPatchSetId);
-          if (previousPatchSet != null) {
-            previous = getIssueIds(projectName,
-                previousPatchSet.getRevision().get());
-          }
-        } catch (OrmException e) {
-          // previous is still empty to indicate that there was no previous
-          // accessible patch set. We treat every occurrence as added.
+        PatchSet.Id previousPatchSetId = new PatchSet.Id(patchSetId.getParentKey(), patchSetId.get() - 1);
+        String previousPatchSet = db.getRevision(previousPatchSetId);
+        if (previousPatchSet != null) {
+          previous = getIssueIds(projectName, previousPatchSet);
         }
       }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
index 0e31b93..c3e0421 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
@@ -20,7 +20,6 @@
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddSoyComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddStandardComment;
-import com.googlesource.gerrit.plugins.its.base.workflow.action.AddVelocityComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.LogEvent;
 import java.io.IOException;
 import java.util.Set;
@@ -34,7 +33,6 @@
   private final ItsFacade its;
   private final AddComment.Factory addCommentFactory;
   private final AddStandardComment.Factory addStandardCommentFactory;
-  private final AddVelocityComment.Factory addVelocityCommentFactory;
   private final AddSoyComment.Factory addSoyCommentFactory;
   private final LogEvent.Factory logEventFactory;
 
@@ -43,13 +41,11 @@
       ItsFacade its,
       AddComment.Factory addCommentFactory,
       AddStandardComment.Factory addStandardCommentFactory,
-      AddVelocityComment.Factory addVelocityCommentFactory,
       AddSoyComment.Factory addSoyCommentFactory,
       LogEvent.Factory logEventFactory) {
     this.its = its;
     this.addCommentFactory = addCommentFactory;
     this.addStandardCommentFactory = addStandardCommentFactory;
-    this.addVelocityCommentFactory = addVelocityCommentFactory;
     this.addSoyCommentFactory = addSoyCommentFactory;
     this.logEventFactory = logEventFactory;
   }
@@ -62,8 +58,6 @@
         action = addCommentFactory.create();
       } else if ("add-standard-comment".equals(name)) {
         action = addStandardCommentFactory.create();
-      } else if ("add-velocity-comment".equals(name)) {
-        action = addVelocityCommentFactory.create();
       } else if ("add-soy-comment".equals(name)) {
         action = addSoyCommentFactory.create();
       } else if ("log-event".equals(name)) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/action/AddVelocityComment.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/action/AddVelocityComment.java
deleted file mode 100644
index f3a1cc2..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/action/AddVelocityComment.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.its.base.workflow.action;
-
-import com.google.common.base.Strings;
-import com.google.gerrit.server.config.SitePath;
-import com.google.inject.Inject;
-
-import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
-import com.googlesource.gerrit.plugins.its.base.workflow.ActionRequest;
-import com.googlesource.gerrit.plugins.its.base.workflow.Property;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.runtime.RuntimeInstance;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Set;
-
-/**
- * Adds a short predefined comments to an issue.
- *
- * Comments are added for merging, abandoning, restoring of changes and adding
- * of patch sets.
- */
-public class AddVelocityComment implements Action {
-  private static final Logger log = LoggerFactory.getLogger(
-      AddVelocityComment.class);
-
-  public interface Factory {
-    AddVelocityComment create();
-  }
-
-  /**
-   * Directory (relative to site) to search templates in
-   */
-  private static final String ITS_TEMPLATE_DIR = "etc" + File.separator +
-      "its" + File.separator + "templates";
-
-  private final ItsFacade its;
-  private final Path sitePath;
-  private final RuntimeInstance velocityRuntime;
-
-  @Inject
-  public AddVelocityComment(RuntimeInstance velocityRuntime, @SitePath Path sitePath, ItsFacade its) {
-    this.velocityRuntime = velocityRuntime;
-    this.sitePath = sitePath;
-    this.its = its;
-  }
-
-  private VelocityContext getVelocityContext(Set<Property> properties) {
-    VelocityContext velocityContext = new VelocityContext();
-    for (Property property : properties) {
-      String key = property.getKey();
-      if (!Strings.isNullOrEmpty(key)) {
-        String value = property.getValue();
-        if (!Strings.isNullOrEmpty(value)) {
-          velocityContext.put(key, value);
-        }
-      }
-    }
-
-    velocityContext.put("its",  new VelocityAdapterItsFacade(its));
-
-    return velocityContext;
-  }
-
-  private String velocify(String template, Set<Property> properties) {
-    VelocityContext context = getVelocityContext(properties);
-    StringWriter w = new StringWriter();
-    velocityRuntime.evaluate(context, w, "ItsComment", template);
-    return w.toString();
-  }
-
-  @Override
-  public void execute(String issue, ActionRequest actionRequest,
-      Set<Property> properties) throws IOException {
-    String template = null;
-    String templateName = actionRequest.getParameter(1);
-    if ("inline".equals(templateName)) {
-      String[] allParameters = actionRequest.getParameters();
-      String[] templateParameters =
-          Arrays.copyOfRange(allParameters, 1, allParameters.length);
-      template = StringUtils.join(templateParameters, " ");
-    } else {
-      if (templateName.isEmpty()) {
-        log.error("No template name given in " + actionRequest);
-      } else {
-        Path templateDir = sitePath.resolve(ITS_TEMPLATE_DIR);
-        Path templatePath = templateDir.resolve(templateName + ".vm");
-        if (Files.isReadable(templatePath)) {
-          template = new String(Files.readAllBytes(templatePath));
-        } else {
-          log.error("Cannot read template " + templatePath);
-        }
-      }
-    }
-    if (!Strings.isNullOrEmpty(template)) {
-      String comment = velocify(template, properties);
-      its.addComment(issue, comment);
-    }
-  }
-
-  /**
-   * Adapter for ItsFacade to be used through Velocity
-   */
-  // Although we'd prefer to keep this class private, Velocity will only pick
-  // it up, if it is public.
-  public class VelocityAdapterItsFacade {
-
-    private final ItsFacade facade;
-
-    private VelocityAdapterItsFacade(ItsFacade facade) {
-      this.facade = facade;
-    }
-
-    /**
-     * Format a link to a URL in the used Its' syntax.
-     *
-     * @param url URL to link to
-     * @param caption Text used to represent the link
-     * @return Link to the given URL in the used Its' syntax.
-     */
-    public String formatLink(String url, String caption) {
-      return facade.createLinkForWebui(url, caption);
-    }
-
-    /**
-     * Format a link to an URL.
-     * <p>
-     * The provided URL is used as caption for the formatted link.
-     *
-     * @param url URL to link to
-     * @return Link to the given URL in the used Its' syntax.
-     */
-    public String formatLink(String url) {
-      return facade.createLinkForWebui(url, url);
-    }
-  }
-}
diff --git a/src/main/resources/Documentation/config-rulebase-common.md b/src/main/resources/Documentation/config-rulebase-common.md
index 16f2de5..3426e4a 100644
--- a/src/main/resources/Documentation/config-rulebase-common.md
+++ b/src/main/resources/Documentation/config-rulebase-common.md
@@ -175,50 +175,50 @@
 values are:
 
 `somewhere`
-:   issue id occurs somewhere in the commit message of the change/the
-    most recent patch set.
+:	issue id occurs somewhere in the commit message of the change/the
+	most recent patch set.
 
 `subject`
-:   issue id occurs in the first line of the commit message of the
-    change/the most recent patch set.
+:	issue id occurs in the first line of the commit message of the
+	change/the most recent patch set.
 
 `body`
-:   issue id occurs after the subject but before the footer of the
-    commit message of the change/the most recent patch set.
+:	issue id occurs after the subject but before the footer of the
+	commit message of the change/the most recent patch set.
 
 `footer`
-:   issue id occurs in the last paragraph after the subject of the
-    commit message of the change/the most recent patch set
+:	issue id occurs in the last paragraph after the subject of the
+	commit message of the change/the most recent patch set
 
 `footer-<Key>`
-:   issue id occurs in the footer of the commit message of the
-    change/the most recent patch set, and is in a line with a key
-    (part before the colon).
+:	issue id occurs in the footer of the commit message of the
+	change/the most recent patch set, and is in a line with a key
+	(part before the colon).
 
-    So for example, if the footer would contain a line
+	So for example, if the footer would contain a line
 
-    ```
+	```
 Fixes-Issue: issue 4711
 ```
 
-    then a property `association` with value `footer-Fixes-Issue`
-    would get added to the event for issue “4711”.
+	then a property `association` with value `footer-Fixes-Issue`
+	would get added to the event for issue “4711”.
 
 `added@<Association-Value>`
-:   (only for events that allow to determine the patch set number.
-    So for example, this `association` property is not set for
-    RevUpdatedEvents)
+:	(only for events that allow to determine the patch set number.
+	So for example, this `association` property is not set for
+	RevUpdatedEvents)
 
-    issue id occurs at `<Association-Value>` in the most recent
-    patch set of the change, and either the event is for patch set
-    1 or the issue id does not occur at `<Association-Value>` in
-    the previous patch set.
+	issue id occurs at `<Association-Value>` in the most recent
+	patch set of the change, and either the event is for patch set
+	1 or the issue id does not occur at `<Association-Value>` in
+	the previous patch set.
 
-    So for example if issue “4711” occurs in the subject of patch
-    set 3 (the most recent patch set) of a change, but not in
-    patch set 2.  When adding a comment to this change, the event
-    for issue “4711” would get a property 'association' with value
-    `added@subject`.
+	So for example if issue “4711” occurs in the subject of patch
+	set 3 (the most recent patch set) of a change, but not in
+	patch set 2.  When adding a comment to this change, the event
+	for issue “4711” would get a property 'association' with value
+	`added@subject`.
 
 [event-properties-ChangeAbandonedEvent]: #event-properties-ChangeAbandonedEvent
 ### <a name="event-properties-ChangeAbandonedEvent">ChangeAbandonedEvent</a>
@@ -523,67 +523,6 @@
 (abandoner, merger, ...), the change's subject, a reason (if one has
 been given), and a link to the change.
 
-[action-add-velocity-comment]: #action-add-velocity-comment
-### <a name="action-add-velocity-comment">Action: add-velocity-comment</a>
-
-The `add-velocity-comment` action renders a Velocity template for the
-event and adds the output as comment to any associated issue.
-
-So for example
-
-```
-  action = add-velocity-comment TemplateName
-```
-
-would render the template `etc/its/templates/TemplateName.vm` add the
-output as comment to associated issues.
-
-If 'TemplateName' is `inline`, the Velocity template to render is not
-loaded from a file, but the template is built by joining the remaining
-parameters. So for example
-
-```
-  action = add-velocity-comment inline Sample template using $subject property.
-```
-
-would render “Sample template using $subject property.” as Velocity
-template.
-
-If 'TemplateName' is not `inline`, further parameters get ignored.
-
-Any [property][event-properties] of the event may be used from
-templates. So for example `$subject` in the above example refers to
-the event's subject property, and `$changeNumber` would refer to the
-change's number.
-
-Additionally, the context's `its` property provides an object that
-allows to format links using the its' syntax:
-
-`formatLink( url )`
-:   Formats a link to a url.
-
-    So for example upon adding a comment to a change, the
-    following rule formats a link to the change:
-
-    ```
-[rule "formatLinkSampleRule"]
-  event-type = comment-added
-  action = add-velocity-comment inline Comment for change $change-number added. See ${its.formatLink($changeUrl)}
-```
-
-`formatLink( url, caption )`
-:   Formats a link to a url using 'caption' to represent the url.
-
-    So for example upon adding a comment to a change, the following rule
-    formats a link to the change using the change number as link
-    capition:
-
-    ```
-[rule "formatLinkSampleRule"]
-  event-type = comment-added
-  action = add-velocity-comment inline Comment for change ${its.formatLink($changeUrl, $changeNumber)} added.
-```
-
 [action-add-soy-comment]: #action-add-soy-comment
 ### <a name="action-add-soy-comment">Action: add-soy-comment</a>
 
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java
index b79e764..3e8721d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java
@@ -21,14 +21,13 @@
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.RevId;
-import com.google.gerrit.reviewdb.server.PatchSetAccess;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gwtorm.server.OrmException;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
 import com.googlesource.gerrit.plugins.its.base.its.ItsConfig;
 import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase;
+import com.googlesource.gerrit.plugins.its.base.util.IssueExtractor.PatchSetDb;
 
 import org.junit.runner.RunWith;
 import org.powermock.core.classloader.annotations.PrepareForTest;
@@ -46,7 +45,7 @@
   private Injector injector;
   private ItsConfig itsConfig;
   private CommitMessageFetcher commitMessageFetcher;
-  private ReviewDb db;
+  private PatchSetDb db;
 
   public void testIssueIdsNullPattern() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
@@ -806,8 +805,7 @@
     assertLogMessageContains("Matching");
   }
 
-  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondEmpty()
-      throws OrmException {
+  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondEmpty() {
     expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)"))
         .atLeastOnce();
     expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
@@ -823,15 +821,7 @@
 
     // Call for previous patch set
     PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    RevId previousRevId = createMock(RevId.class);
-    expect(previousRevId.get())
-        .andReturn("9876543211987654321298765432139876543214").anyTimes();
-
-    PatchSet previousPatchSet = createMock(PatchSet.class);
-    expect(previousPatchSet.getRevision()).andReturn(previousRevId).anyTimes();
-
-    PatchSetAccess patchSetAccess = createMock(PatchSetAccess.class);
-    expect(patchSetAccess.get(previousPatchSetId)).andReturn(previousPatchSet);
+    expect(db.getRevision(previousPatchSetId)).andReturn("9876543211987654321298765432139876543214");
 
     expect(commitMessageFetcher.fetchGuarded("testProject",
         "9876543211987654321298765432139876543214")).andReturn(
@@ -839,8 +829,6 @@
             "\n" +
             "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.patchSets()).andReturn(patchSetAccess);
-
     PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
     expect(currentPatchSetId.get()).andReturn(2).anyTimes();
     expect(currentPatchSetId.getParentKey()).andReturn(changeId)
@@ -869,8 +857,7 @@
     assertLogMessageContains("Matching");
   }
 
-  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondSame()
-      throws OrmException {
+  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondSame() {
     expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)"))
         .atLeastOnce();
     expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
@@ -886,23 +873,13 @@
 
     // Call for previous patch set
     PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    RevId previousRevId = createMock(RevId.class);
-    expect(previousRevId.get())
-        .andReturn("9876543211987654321298765432139876543214").anyTimes();
-
-    PatchSet previousPatchSet = createMock(PatchSet.class);
-    expect(previousPatchSet.getRevision()).andReturn(previousRevId).anyTimes();
-
-    PatchSetAccess patchSetAccess = createMock(PatchSetAccess.class);
-    expect(patchSetAccess.get(previousPatchSetId)).andReturn(previousPatchSet);
-
     expect(commitMessageFetcher.fetchGuarded("testProject",
         "9876543211987654321298765432139876543214")).andReturn(
             "bug#42\n" +
             "\n" +
             "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.patchSets()).andReturn(patchSetAccess);
+    expect(db.getRevision(previousPatchSetId)).andReturn("9876543211987654321298765432139876543214");
 
     PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
     expect(currentPatchSetId.get()).andReturn(2).anyTimes();
@@ -931,8 +908,7 @@
     assertLogMessageContains("Matching");
   }
 
-  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondBody()
-      throws OrmException {
+  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondBody() {
     expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)"))
         .atLeastOnce();
     expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
@@ -948,16 +924,6 @@
 
     // Call for previous patch set
     PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    RevId previousRevId = createMock(RevId.class);
-    expect(previousRevId.get())
-        .andReturn("9876543211987654321298765432139876543214").anyTimes();
-
-    PatchSet previousPatchSet = createMock(PatchSet.class);
-    expect(previousPatchSet.getRevision()).andReturn(previousRevId).anyTimes();
-
-    PatchSetAccess patchSetAccess = createMock(PatchSetAccess.class);
-    expect(patchSetAccess.get(previousPatchSetId)).andReturn(previousPatchSet);
-
     expect(commitMessageFetcher.fetchGuarded("testProject",
         "9876543211987654321298765432139876543214")).andReturn(
             "subject\n" +
@@ -965,7 +931,7 @@
             "\n" +
             "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.patchSets()).andReturn(patchSetAccess);
+    expect(db.getRevision(previousPatchSetId)).andReturn("9876543211987654321298765432139876543214");
 
     PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
     expect(currentPatchSetId.get()).andReturn(2).anyTimes();
@@ -994,8 +960,7 @@
     assertLogMessageContains("Matching");
   }
 
-  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondFooter()
-      throws OrmException {
+  public void testIssueIdsCommitWAddedSingleSubjectIssueSecondFooter() {
     expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)"))
         .atLeastOnce();
     expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
@@ -1012,23 +977,13 @@
 
     // Call for previous patch set
     PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    RevId previousRevId = createMock(RevId.class);
-    expect(previousRevId.get())
-        .andReturn("9876543211987654321298765432139876543214").anyTimes();
-
-    PatchSet previousPatchSet = createMock(PatchSet.class);
-    expect(previousPatchSet.getRevision()).andReturn(previousRevId).anyTimes();
-
-    PatchSetAccess patchSetAccess = createMock(PatchSetAccess.class);
-    expect(patchSetAccess.get(previousPatchSetId)).andReturn(previousPatchSet);
-
     expect(commitMessageFetcher.fetchGuarded("testProject",
         "9876543211987654321298765432139876543214")).andReturn(
             "bug#42\n" +
             "\n" +
             "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.patchSets()).andReturn(patchSetAccess);
+    expect(db.getRevision(previousPatchSetId)).andReturn("9876543211987654321298765432139876543214");
 
     PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
     expect(currentPatchSetId.get()).andReturn(2).anyTimes();
@@ -1059,8 +1014,7 @@
     assertLogMessageContains("Matching");
   }
 
-  public void testIssueIdsCommitWAddedSubjectFooter()
-      throws OrmException {
+  public void testIssueIdsCommitWAddedSubjectFooter() {
     expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)"))
         .atLeastOnce();
     expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
@@ -1079,16 +1033,6 @@
 
     // Call for previous patch set
     PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    RevId previousRevId = createMock(RevId.class);
-    expect(previousRevId.get())
-        .andReturn("9876543211987654321298765432139876543214").anyTimes();
-
-    PatchSet previousPatchSet = createMock(PatchSet.class);
-    expect(previousPatchSet.getRevision()).andReturn(previousRevId).anyTimes();
-
-    PatchSetAccess patchSetAccess = createMock(PatchSetAccess.class);
-    expect(patchSetAccess.get(previousPatchSetId)).andReturn(previousPatchSet);
-
     expect(commitMessageFetcher.fetchGuarded("testProject",
         "9876543211987654321298765432139876543214")).andReturn(
             "subject\n" +
@@ -1096,7 +1040,7 @@
             "\n" +
             "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.patchSets()).andReturn(patchSetAccess);
+    expect(db.getRevision(previousPatchSetId)).andReturn("9876543211987654321298765432139876543214");
 
     PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
     expect(currentPatchSetId.get()).andReturn(2).anyTimes();
@@ -1128,8 +1072,7 @@
     assertLogMessageContains("Matching");
   }
 
-  public void testIssueIdsCommitWAddedMultiple()
-      throws OrmException {
+  public void testIssueIdsCommitWAddedMultiple() {
     expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)"))
         .atLeastOnce();
     expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
@@ -1148,16 +1091,6 @@
 
     // Call for previous patch set
     PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    RevId previousRevId = createMock(RevId.class);
-    expect(previousRevId.get())
-        .andReturn("9876543211987654321298765432139876543214").anyTimes();
-
-    PatchSet previousPatchSet = createMock(PatchSet.class);
-    expect(previousPatchSet.getRevision()).andReturn(previousRevId).anyTimes();
-
-    PatchSetAccess patchSetAccess = createMock(PatchSetAccess.class);
-    expect(patchSetAccess.get(previousPatchSetId)).andReturn(previousPatchSet);
-
     expect(commitMessageFetcher.fetchGuarded("testProject",
         "9876543211987654321298765432139876543214")).andReturn(
             "subject\n" +
@@ -1166,7 +1099,7 @@
             "Bug: bug#16\n" +
             "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.patchSets()).andReturn(patchSetAccess);
+    expect(db.getRevision(previousPatchSetId)).andReturn("9876543211987654321298765432139876543214");
 
     PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
     expect(currentPatchSetId.get()).andReturn(2).anyTimes();
@@ -1216,8 +1149,8 @@
       commitMessageFetcher = createMock(CommitMessageFetcher.class);
       bind(CommitMessageFetcher.class).toInstance(commitMessageFetcher);
 
-      db = createMock(ReviewDb.class);
-      bind(ReviewDb.class).toInstance(db);
+      db = createMock(PatchSetDb.class);
+      bind(PatchSetDb.class).toInstance(db);
     }
   }
 }
\ No newline at end of file
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
index f3f5916..8cab7a4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
@@ -26,7 +26,6 @@
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddSoyComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.AddStandardComment;
-import com.googlesource.gerrit.plugins.its.base.workflow.action.AddVelocityComment;
 import com.googlesource.gerrit.plugins.its.base.workflow.action.LogEvent;
 
 import java.io.IOException;
@@ -39,7 +38,6 @@
   private ItsFacade its;
   private AddComment.Factory addCommentFactory;
   private AddStandardComment.Factory addStandardCommentFactory;
-  private AddVelocityComment.Factory addVelocityCommentFactory;
   private AddSoyComment.Factory addSoyCommentFactory;
   private LogEvent.Factory logEventFactory;
 
@@ -181,24 +179,6 @@
     actionExecutor.execute("4711", actionRequest, properties);
   }
 
-  public void testAddVelocityCommentDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("add-velocity-comment");
-
-    Set<Property> properties = Collections.emptySet();
-
-    AddVelocityComment addVelocityComment =
-        createMock(AddVelocityComment.class);
-    expect(addVelocityCommentFactory.create()).andReturn(addVelocityComment);
-
-    addVelocityComment.execute("4711", actionRequest, properties);
-
-    replayMocks();
-
-    ActionExecutor actionExecutor = createActionExecutor();
-    actionExecutor.execute("4711", actionRequest, properties);
-  }
-
   public void testLogEventDelegation() throws IOException {
     ActionRequest actionRequest = createMock(ActionRequest.class);
     expect(actionRequest.getName()).andReturn("log-event");
@@ -243,10 +223,6 @@
       bind(AddStandardComment.Factory.class).toInstance(
           addStandardCommentFactory);
 
-      addVelocityCommentFactory = createMock(AddVelocityComment.Factory.class);
-      bind(AddVelocityComment.Factory.class).toInstance(
-          addVelocityCommentFactory);
-
       logEventFactory = createMock(LogEvent.Factory.class);
       bind(LogEvent.Factory.class).toInstance(logEventFactory);
     }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/action/AddVelocityCommentTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/action/AddVelocityCommentTest.java
deleted file mode 100644
index 5a33db6..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/action/AddVelocityCommentTest.java
+++ /dev/null
@@ -1,429 +0,0 @@
-// 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.its.base.workflow.action;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-
-import com.google.common.collect.Sets;
-import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.server.config.SitePath;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
-import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
-import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase;
-import com.googlesource.gerrit.plugins.its.base.workflow.ActionRequest;
-import com.googlesource.gerrit.plugins.its.base.workflow.Property;
-import com.googlesource.gerrit.plugins.its.base.workflow.action.AddVelocityComment.VelocityAdapterItsFacade;
-
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.runtime.RuntimeInstance;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.eclipse.jgit.util.FileUtils;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-public class AddVelocityCommentTest extends LoggingMockingTestCase {
-  private Injector injector;
-
-  private Path sitePath;
-  private ItsFacade its;
-  private RuntimeInstance velocityRuntime;
-
-  private boolean cleanupSitePath;
-
-  public void testWarnNoTemplateNameGiven() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("");
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
-
-    assertLogMessageContains("No template name");
-  }
-
-  public void testInlinePlain() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "Simple-text"});
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Simple-text");
-    expect(velocityRuntime.evaluate((VelocityContext)anyObject(),
-        (Writer)anyObject(), (String)anyObject(), eq("Simple-text")))
-        .andAnswer(answer);
-
-    its.addComment("4711", "Simple-text");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
-  }
-
-  public void testInlineWithMultipleParameters() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "Param2", "Param3"});
-
-    Set<Property> properties = Sets.newHashSet();
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Param2 Param3");
-    expect(velocityRuntime.evaluate((VelocityContext)anyObject(),
-        (Writer)anyObject(), (String)anyObject(), eq("Param2 Param3")))
-        .andAnswer(answer);
-
-    its.addComment("4711", "Param2 Param3");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, properties);
-  }
-
-  public void testInlineWithSingleProperty() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "${subject}"});
-
-    Set<Property> properties = Sets.newHashSet();
-
-    Property propertySubject = createMock(Property.class);
-    expect(propertySubject.getKey()).andReturn("subject").anyTimes();
-    expect(propertySubject.getValue()).andReturn("Rosebud").anyTimes();
-    properties.add(propertySubject);
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Rosebud");
-    Capture<VelocityContext> contextCapture = createCapture();
-    expect(velocityRuntime.evaluate(capture(contextCapture),
-        (Writer)anyObject(), (String)anyObject(), eq("${subject}")))
-        .andAnswer(answer);
-
-    its.addComment("4711", "Rosebud");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, properties);
-
-    VelocityContext context = contextCapture.getValue();
-    assertEquals("Subject property of context did not match", "Rosebud",
-        context.get("subject"));
-  }
-
-  public void testInlineWithUnusedProperty() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "Test"});
-
-    Set<Property> properties = Sets.newHashSet();
-
-    Property propertySubject = createMock(Property.class);
-    expect(propertySubject.getKey()).andReturn("subject").anyTimes();
-    expect(propertySubject.getValue()).andReturn("Rosebud").anyTimes();
-    properties.add(propertySubject);
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Test");
-    expect(velocityRuntime.evaluate((VelocityContext)anyObject(),
-        (Writer)anyObject(), (String)anyObject(), eq("Test")))
-        .andAnswer(answer);
-
-    its.addComment("4711", "Test");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, properties);
-  }
-
-  public void testInlineWithMultipleProperties() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "${subject}", "${reason}", "${subject}"});
-
-    Set<Property> properties = Sets.newHashSet();
-
-    Property propertySubject = createMock(Property.class);
-    expect(propertySubject.getKey()).andReturn("subject").anyTimes();
-    expect(propertySubject.getValue()).andReturn("Rosebud").anyTimes();
-    properties.add(propertySubject);
-
-    Property propertyReason = createMock(Property.class);
-    expect(propertyReason.getKey()).andReturn("reason").anyTimes();
-    expect(propertyReason.getValue()).andReturn("Life").anyTimes();
-    properties.add(propertyReason);
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Rosebud Life Rosebud");
-    Capture<VelocityContext> contextCapture = createCapture();
-    expect(velocityRuntime.evaluate(capture(contextCapture),
-        (Writer)anyObject(), (String)anyObject(),
-        eq("${subject} ${reason} ${subject}"))).andAnswer(answer);
-
-    its.addComment("4711", "Rosebud Life Rosebud");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, properties);
-
-    VelocityContext context = contextCapture.getValue();
-    assertEquals("Subject property of context did not match", "Rosebud",
-        context.get("subject"));
-    assertEquals("Reason property of context did not match", "Life",
-        context.get("reason"));
-  }
-
-  public void testItsWrapperFormatLink1Parameter() throws IOException,
-      SecurityException, IllegalArgumentException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "Simple-Text"});
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Simple-Text");
-    Capture<VelocityContext> contextCapture = createCapture();
-    expect(velocityRuntime.evaluate(capture(contextCapture),
-        (Writer)anyObject(), (String)anyObject(), eq("Simple-Text")))
-        .andAnswer(answer);
-
-    its.addComment("4711", "Simple-Text");
-
-    expect(its.createLinkForWebui("http://www.example.org/",
-        "http://www.example.org/")) .andReturn("Formatted Link");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
-
-    VelocityContext context = contextCapture.getValue();
-    Object itsAdapterObj = context.get("its");
-    assertNotNull("its property is null", itsAdapterObj);
-    assertTrue("Its is not a VelocityAdapterItsFacade instance",
-        itsAdapterObj instanceof VelocityAdapterItsFacade);
-    VelocityAdapterItsFacade itsAdapter =
-        (VelocityAdapterItsFacade) itsAdapterObj;
-    String formattedLink = itsAdapter.formatLink("http://www.example.org/");
-    assertEquals("Result of formatLink does not match", "Formatted Link",
-        formattedLink);
-  }
-
-  public void testItsWrapperFormatLink2Parameters() throws IOException,
-      SecurityException, IllegalArgumentException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("inline");
-    expect(actionRequest.getParameters()).andReturn(
-        new String[] {"inline", "Simple-Text"});
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Simple-Text");
-    Capture<VelocityContext> contextCapture = createCapture();
-    expect(velocityRuntime.evaluate(capture(contextCapture),
-        (Writer)anyObject(), (String)anyObject(), eq("Simple-Text")))
-        .andAnswer(answer);
-
-    its.addComment("4711", "Simple-Text");
-
-    expect(its.createLinkForWebui("http://www.example.org/", "Caption"))
-        .andReturn("Formatted Link");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
-
-    VelocityContext context = contextCapture.getValue();
-    Object itsAdapterObj = context.get("its");
-    assertNotNull("its property is null", itsAdapterObj);
-    assertTrue("Its is not a VelocityAdapterItsFacade instance",
-        itsAdapterObj instanceof VelocityAdapterItsFacade);
-    VelocityAdapterItsFacade itsAdapter =
-        (VelocityAdapterItsFacade) itsAdapterObj;
-    String formattedLink = itsAdapter.formatLink("http://www.example.org/",
-        "Caption");
-    assertEquals("Result of formatLink does not match", "Formatted Link",
-        formattedLink);
-  }
-
-  public void testWarnTemplateNotFound() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("non-existing-template");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
-
-    assertLogMessageContains("non-existing-template");
-  }
-
-  public void testTemplateSimple() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("test-template");
-
-    injectTestTemplate("Simple Test Template");
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller("Simple Test Template");
-    expect(velocityRuntime.evaluate((VelocityContext)anyObject(),
-        (Writer)anyObject(), (String)anyObject(),
-        eq("Simple Test Template"))).andAnswer(answer);
-
-    its.addComment("4711", "Simple Test Template");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
-  }
-
-  public void testTemplateMultipleParametersAndProperties() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("test-template");
-
-    Set<Property> properties = Sets.newHashSet();
-
-    Property propertySubject = createMock(Property.class);
-    expect(propertySubject.getKey()).andReturn("subject").anyTimes();
-    expect(propertySubject.getValue()).andReturn("Rosebud").anyTimes();
-    properties.add(propertySubject);
-
-    Property propertyReason = createMock(Property.class);
-    expect(propertyReason.getKey()).andReturn("reason").anyTimes();
-    expect(propertyReason.getValue()).andReturn("Life").anyTimes();
-    properties.add(propertyReason);
-
-    injectTestTemplate("Test Template with subject: ${subject}.\n" +
-        "${reason} is the reason for ${subject}.");
-
-    IAnswer<Boolean> answer = new VelocityWriterFiller(
-        "Test Template with subject: Rosebud.\n" +
-        "Life is the reason for Rosebud.");
-    Capture<VelocityContext> contextCapture = createCapture();
-    expect(velocityRuntime.evaluate(capture(contextCapture),
-        (Writer)anyObject(), (String)anyObject(),
-        eq("Test Template with subject: ${subject}.\n" +
-            "${reason} is the reason for ${subject}."))).andAnswer(answer);
-
-    its.addComment("4711", "Test Template with subject: Rosebud.\n" +
-        "Life is the reason for Rosebud.");
-
-    replayMocks();
-
-    AddVelocityComment addVelocityComment = createAddVelocityComment();
-    addVelocityComment.execute("4711", actionRequest, properties);
-
-    VelocityContext context = contextCapture.getValue();
-    assertEquals("Subject property of context did not match", "Rosebud",
-        context.get("subject"));
-    assertEquals("Reason property of context did not match", "Life",
-        context.get("reason"));
-  }
-
-  private AddVelocityComment createAddVelocityComment() {
-    return injector.getInstance(AddVelocityComment.class);
-  }
-
-  private void injectTestTemplate(String template) throws IOException {
-    File templateParentFile = new File(sitePath.toFile(), "etc" +
-        File.separatorChar + "its" + File.separator + "templates");
-    assertTrue("Failed to create parent (" + templateParentFile + ") for " +
-        "rule base", templateParentFile.mkdirs());
-    File templateFile = new File(templateParentFile, "test-template.vm");
-
-    try (FileWriter unbufferedWriter = new FileWriter(templateFile);
-        BufferedWriter writer = new BufferedWriter(unbufferedWriter)) {
-      writer.write(template);
-    }
-  }
-
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
-    cleanupSitePath = false;
-    injector = Guice.createInjector(new TestModule());
-  }
-
-  @Override
-  public void tearDown() throws Exception {
-    if (cleanupSitePath) {
-      if (Files.exists(sitePath)) {
-        FileUtils.delete(sitePath.toFile(), FileUtils.RECURSIVE);
-      }
-    }
-    super.tearDown();
-  }
-
-  private Path randomTargetPath() {
-    return Paths.get("target", "random-name-" + UUID.randomUUID().toString());
-  }
-
-  private class TestModule extends FactoryModule {
-    @Override
-    protected void configure() {
-      sitePath = randomTargetPath();
-      assertFalse("sitePath already (" + sitePath + ") already exists",
-          Files.exists(sitePath));
-      cleanupSitePath = true;
-
-      bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
-
-      its = createMock(ItsFacade.class);
-      bind(ItsFacade.class).toInstance(its);
-
-      velocityRuntime = createMock(RuntimeInstance.class);
-      bind(RuntimeInstance.class).toInstance(velocityRuntime);
-    }
-  }
-
-  private class VelocityWriterFiller implements IAnswer<Boolean> {
-    private final String fill;
-    private final boolean returnValue;
-
-    private VelocityWriterFiller(String fill, boolean returnValue) {
-      this.fill = fill;
-      this.returnValue = returnValue;
-    }
-
-    private VelocityWriterFiller(String fill) {
-      this(fill, true);
-    }
-
-    @Override
-    public Boolean answer() throws Throwable {
-      Object[] arguments = EasyMock.getCurrentArguments();
-      Writer writer = (Writer) arguments[1];
-      writer.write(fill);
-      return returnValue;
-    }
-  }
-}
\ No newline at end of file