Merge "Add actions for comments built from Velocity templates"
diff --git a/hooks-its/pom.xml b/hooks-its/pom.xml
index 576530a..12c259b 100644
--- a/hooks-its/pom.xml
+++ b/hooks-its/pom.xml
@@ -37,6 +37,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ <version>${velocityVersion}</version>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4jVersion}</version>
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java
index 9e18eef..16acf53 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java
@@ -30,6 +30,7 @@
import com.googlesource.gerrit.plugins.hooks.workflow.Property;
import com.googlesource.gerrit.plugins.hooks.workflow.Rule;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddStandardComment;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment;
public class ItsHookModule extends FactoryModule {
@@ -59,5 +60,6 @@
factory(Condition.Factory.class);
factory(Rule.Factory.class);
factory(AddStandardComment.Factory.class);
+ factory(AddVelocityComment.Factory.class);
}
}
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 4e99423..64fd014 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
@@ -24,6 +24,7 @@
import com.googlesource.gerrit.plugins.hooks.its.ItsFacade;
import com.googlesource.gerrit.plugins.hooks.workflow.action.Action;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddStandardComment;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment;
/**
* Executes an {@link ActionRequest}
@@ -34,12 +35,15 @@
private final ItsFacade its;
private final AddStandardComment.Factory addStandardCommentFactory;
+ private final AddVelocityComment.Factory addVelocityCommentFactory;
@Inject
public ActionExecutor(ItsFacade its,
- AddStandardComment.Factory addStandardCommentFactory) {
+ AddStandardComment.Factory addStandardCommentFactory,
+ AddVelocityComment.Factory addVelocityCommentFactory) {
this.its = its;
this.addStandardCommentFactory = addStandardCommentFactory;
+ this.addVelocityCommentFactory = addVelocityCommentFactory;
}
public void execute(String issue, ActionRequest actionRequest,
@@ -49,6 +53,8 @@
Action action = null;
if ("add-standard-comment".equals(name)) {
action = addStandardCommentFactory.create();
+ } else if ("add-velocity-comment".equals(name)) {
+ action = addVelocityCommentFactory.create();
}
if (action == null) {
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 cb3e5f3..c829569 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
@@ -14,6 +14,8 @@
package com.googlesource.gerrit.plugins.hooks.workflow;
+import java.util.Arrays;
+
import javax.annotation.Nullable;
import com.google.inject.Inject;
@@ -58,6 +60,30 @@
}
/**
+ * Gets the name of the requested action.
+ *
+ * @param i The number of the parameter to extract. 1 is the first parameter.
+ * @return The name of the requested parameter, if the requested parameter
+ * exists. "" otherwise.
+ */
+ public String getParameter(int i) {
+ String ret = "";
+ if (chopped.length > i) {
+ ret = chopped[i];
+ }
+ return ret;
+ }
+
+ /**
+ * Gets the parameters of the requested action.
+ *
+ * @return The parameters of the requested action.
+ */
+ public String[] getParameters() {
+ return Arrays.copyOfRange(chopped, 1, chopped.length);
+ }
+
+ /**
* Gets the unparsed specification of this action request.
*
* @return The unparsed action request.
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java
new file mode 100644
index 0000000..45afb65
--- /dev/null
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java
@@ -0,0 +1,117 @@
+// 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.action;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.runtime.RuntimeInstance;
+import org.parboiled.common.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.server.config.SitePath;
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.hooks.its.ItsFacade;
+import com.googlesource.gerrit.plugins.hooks.workflow.ActionRequest;
+import com.googlesource.gerrit.plugins.hooks.workflow.Property;
+
+/**
+ * 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 File sitePath;
+ private final RuntimeInstance velocityRuntime;
+
+ @Inject
+ public AddVelocityComment(RuntimeInstance velocityRuntime, @SitePath File 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);
+ }
+ }
+ }
+ return velocityContext;
+ }
+
+ private String velocify(String template, Set<Property> properties) throws IOException {
+ 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 {
+ File templateFile = new File(sitePath, ITS_TEMPLATE_DIR +
+ File.separator + templateName + ".vm");
+ if (templateFile.canRead()) {
+ template = FileUtils.readAllText(templateFile);
+ } else {
+ log.error("Cannot read template " + templateFile);
+ }
+ }
+ }
+ if (!Strings.isNullOrEmpty(template)) {
+ String comment = velocify(template, properties);
+ its.addComment(issue, comment);
+ }
+ }
+}
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
index a243812..9974967 100644
--- 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
@@ -27,12 +27,14 @@
import com.googlesource.gerrit.plugins.hooks.its.ItsFacade;
import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddStandardComment;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment;
public class ActionExecutorTest extends LoggingMockingTestCase {
private Injector injector;
private ItsFacade its;
private AddStandardComment.Factory addStandardCommentFactory;
+ private AddVelocityComment.Factory addVelocityCommentFactory;
public void testExecuteItem() throws IOException {
ActionRequest actionRequest = createMock(ActionRequest.class);
@@ -119,6 +121,42 @@
assertLogThrowableMessageContains("injected exception 3");
}
+ public void testAddStandardCommentDelegation() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getName()).andReturn("add-standard-comment");
+
+ Set<Property> properties = Collections.emptySet();
+
+ AddStandardComment addStandardComment =
+ createMock(AddStandardComment.class);
+ expect(addStandardCommentFactory.create()).andReturn(addStandardComment);
+
+ addStandardComment.execute("4711", actionRequest, properties);
+
+ replayMocks();
+
+ ActionExecutor actionExecutor = createActionExecutor();
+ 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);
+ }
+
private ActionExecutor createActionExecutor() {
return injector.getInstance(ActionExecutor.class);
}
@@ -137,6 +175,10 @@
addStandardCommentFactory = createMock(AddStandardComment.Factory.class);
bind(AddStandardComment.Factory.class).toInstance(
addStandardCommentFactory);
+
+ addVelocityCommentFactory = createMock(AddVelocityComment.Factory.class);
+ bind(AddVelocityComment.Factory.class).toInstance(
+ addVelocityCommentFactory);
}
}
}
\ 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
index 415a4ec..f7b160d 100644
--- 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
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.hooks.workflow;
import java.io.IOException;
+import java.util.Arrays;
import com.google.gerrit.server.config.FactoryModule;
import com.google.inject.Guice;
@@ -87,6 +88,129 @@
actionRequest.getName());
}
+ public void testParameter1Parameterless() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action");
+ assertEquals("Unparsed string does not match", "",
+ actionRequest.getParameter(1));
+ }
+
+ public void testParameter1Null() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest(null);
+ assertEquals("Unparsed string does not match", "",
+ actionRequest.getParameter(1));
+ }
+
+ public void testParameter1SingleParameter() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param");
+ assertEquals("Unparsed string does not match", "param",
+ actionRequest.getParameter(1));
+ }
+
+ public void testParemeter1MultipleParameters() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param1 param2");
+ assertEquals("Unparsed string does not match", "param1",
+ actionRequest.getParameter(1));
+ }
+
+ public void testParameter3Parameterless() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action");
+ assertEquals("Unparsed string does not match", "",
+ actionRequest.getParameter(3));
+ }
+
+ public void testParameter3Null() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest(null);
+ assertEquals("Unparsed string does not match", "",
+ actionRequest.getParameter(3));
+ }
+
+ public void testParameter3SingleParameter() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param");
+ assertEquals("Unparsed string does not match", "",
+ actionRequest.getParameter(3));
+ }
+
+ public void testParemeter3With2Parameters() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param1 param2");
+ assertEquals("Unparsed string does not match", "",
+ actionRequest.getParameter(3));
+ }
+
+ public void testParemeter3With3Parameters() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param1 param2 " +
+ "param3");
+ assertEquals("Unparsed string does not match", "param3",
+ actionRequest.getParameter(3));
+ }
+
+ public void testParemeter3With4Parameters() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param1 param2 " +
+ "param3 param4");
+ assertEquals("Unparsed string does not match", "param3",
+ actionRequest.getParameter(3));
+ }
+
+ public void testParametersParameterless() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action");
+
+ String[] expected = new String[0];
+ assertEquals("Parameters do not match", Arrays.asList(expected),
+ Arrays.asList(actionRequest.getParameters()));
+ }
+
+ public void testParametersNull() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest(null);
+
+ String[] expected = new String[0];
+ assertEquals("Parameters do not match", Arrays.asList(expected),
+ Arrays.asList(actionRequest.getParameters()));
+ }
+
+ public void testParametersSingleParameter() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param");
+
+ String[] expected = new String[] { "param" };
+ assertEquals("Parameters do not match", Arrays.asList(expected),
+ Arrays.asList(actionRequest.getParameters()));
+ }
+
+ public void testParameters3Parameter() throws IOException {
+ replayMocks();
+
+ ActionRequest actionRequest = createActionRequest("action param1 param2 " +
+ "param3");
+
+ String[] expected = new String[] { "param1", "param2", "param3" };
+ assertEquals("Parameters do not match", Arrays.asList(expected),
+ Arrays.asList(actionRequest.getParameters()));
+ }
+
private ActionRequest createActionRequest(String specification) {
ActionRequest.Factory factory = injector.getInstance(
ActionRequest.Factory.class);
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java
new file mode 100644
index 0000000..5d6b71c
--- /dev/null
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java
@@ -0,0 +1,353 @@
+// 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.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 java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+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 com.google.common.collect.Sets;
+import com.google.gerrit.server.config.FactoryModule;
+import com.google.gerrit.server.config.SitePath;
+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;
+import com.googlesource.gerrit.plugins.hooks.workflow.ActionRequest;
+import com.googlesource.gerrit.plugins.hooks.workflow.Property;
+
+public class AddVelocityCommentTest extends LoggingMockingTestCase {
+ private Injector injector;
+
+ private File 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 = new Capture<VelocityContext>();
+ 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 = new Capture<VelocityContext>();
+ 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 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 = new Capture<VelocityContext>();
+ 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, "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");
+
+ FileWriter unbufferedWriter = new FileWriter(templateFile);
+ BufferedWriter writer = new BufferedWriter(unbufferedWriter);
+ writer.write(template);
+ writer.close();
+ unbufferedWriter.close();
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+ cleanupSitePath = false;
+ injector = Guice.createInjector(new TestModule());
+ }
+
+ public void tearDown() throws Exception {
+ if (cleanupSitePath) {
+ if (sitePath.exists()) {
+ FileUtils.delete(sitePath, FileUtils.RECURSIVE);
+ }
+ }
+ super.tearDown();
+ }
+
+ private File randomTargetFile() {
+ final File t = new File("target");
+ return new File(t, "random-name-" + UUID.randomUUID().toString());
+ }
+
+ private class TestModule extends FactoryModule {
+ @Override
+ protected void configure() {
+ sitePath = randomTargetFile();
+ assertFalse("sitePath already (" + sitePath + ") already exists",
+ sitePath.exists());
+ cleanupSitePath = true;
+
+ bind(File.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
diff --git a/pom.xml b/pom.xml
index a1ee2c9..bdd790e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,7 @@
<easymockVersion>3.0</easymockVersion>
<powermockVersion>1.5</powermockVersion>
<slf4jVersion>1.6.2</slf4jVersion>
+ <velocityVersion>1.6.4</velocityVersion>
</properties>
<modules>