Add actions for comments built from Velocity templates The templates can be given inline in the config file, or stored in a separate file. Change-Id: Ib726529c4e2a849923f8894c2bc0d1cdc15a1c5d
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>