You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/10/03 19:31:46 UTC
[3/6] incubator-freemarker git commit: Fixed template interruption
test (could hang if the template fails for some reason).
Fixed template interruption test (could hang if the template fails for some reason).
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/c01f1a22
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/c01f1a22
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/c01f1a22
Branch: refs/heads/2.3
Commit: c01f1a223a04dcff27eb3b71bbbdc759c1628384
Parents: 1375060
Author: ddekany <dd...@apache.org>
Authored: Tue Oct 3 19:50:40 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Oct 3 19:54:13 2017 +0200
----------------------------------------------------------------------
.../core/TheadInterruptingSupportTest.java | 162 ----------------
.../core/ThreadInterruptingSupportTest.java | 184 +++++++++++++++++++
2 files changed, 184 insertions(+), 162 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c01f1a22/src/test/java/freemarker/core/TheadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/TheadInterruptingSupportTest.java b/src/test/java/freemarker/core/TheadInterruptingSupportTest.java
deleted file mode 100644
index cbba0c3..0000000
--- a/src/test/java/freemarker/core/TheadInterruptingSupportTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 freemarker.core;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateDirectiveBody;
-import freemarker.template.TemplateDirectiveModel;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateModel;
-import freemarker.template.utility.NullWriter;
-
-public class TheadInterruptingSupportTest {
-
- private static final Logger LOG = LoggerFactory.getLogger(TheadInterruptingSupportTest.class);
-
- private static final int TEMPLATE_INTERRUPTION_TIMEOUT = 5000;
- private final Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
-
- @Test
- public void test() throws IOException, InterruptedException {
- assertCanBeInterrupted("<#list 1.. as x></#list>");
- assertCanBeInterrupted("<#list 1.. as x>${x}</#list>");
- assertCanBeInterrupted("<#list 1.. as x>t${x}</#list>");
- assertCanBeInterrupted("<#list 1.. as x><#list 1.. as y>${y}</#list></#list>");
- assertCanBeInterrupted("<#list 1.. as x>${x}<#else>nope</#list>");
- assertCanBeInterrupted("<#list 1..>[<#items as x>${x}</#items>]<#else>nope</#list>");
- assertCanBeInterrupted("<@customLoopDirective />");
- assertCanBeInterrupted("<@customLoopDirective>x</@>");
- assertCanBeInterrupted("<@customLoopDirective><#if true>x</#if></@>");
- assertCanBeInterrupted("<#macro selfCalling><@sleepDirective/><@selfCalling /></#macro><@selfCalling />");
- assertCanBeInterrupted("<#function selfCalling><@sleepDirective/>${selfCalling()}</#function>${selfCalling()}");
- assertCanBeInterrupted("<#list 1.. as _><#attempt><@sleepDirective/><#recover>suppress</#attempt></#list>");
- assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
- }
-
- private void assertCanBeInterrupted(final String templateSourceCode) throws IOException, InterruptedException {
- TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
- trt.start();
- synchronized (trt) {
- while (!trt.isStarted()) {
- trt.wait();
- }
- }
- Thread.sleep(50); // Just to ensure (hope...) that the template execution reaches "deep" enough
- trt.interrupt();
- trt.join(TEMPLATE_INTERRUPTION_TIMEOUT);
- assertTrue(trt.isTemplateProcessingInterrupted());
- }
-
- public class TemplateRunnerThread extends Thread {
-
- private final Template template;
- private boolean started;
- private boolean templateProcessingInterrupted;
-
- public TemplateRunnerThread(String templateSourceCode) throws IOException {
- template = new Template(null, "<@startedDirective/>" + templateSourceCode, cfg);
- _CoreAPI.addThreadInterruptedChecks(template);
- }
-
- @Override
- public void run() {
- try {
- template.process(this, NullWriter.INSTANCE);
- } catch (TemplateProcessingThreadInterruptedException e) {
- //LOG.debug("Template processing interrupted", e);
- synchronized (this) {
- templateProcessingInterrupted = true;
- }
- } catch (Throwable e) {
- LOG.error("Template processing failed", e);
- }
- }
-
- public synchronized boolean isTemplateProcessingInterrupted() {
- return templateProcessingInterrupted;
- }
-
- public synchronized boolean isStarted() {
- return started;
- }
-
- public TemplateDirectiveModel getStartedDirective() {
- return new StartedDirective();
- }
-
- public TemplateDirectiveModel getCustomLoopDirective() {
- return new CustomLoopDirective();
- }
-
- public TemplateDirectiveModel getSleepDirective() {
- return new SleepDirective();
- }
-
- public class StartedDirective implements TemplateDirectiveModel {
-
- public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
- throws TemplateException, IOException {
- synchronized (TemplateRunnerThread.this) {
- started = true;
- TemplateRunnerThread.this.notifyAll();
- }
- }
-
- }
-
- public class CustomLoopDirective implements TemplateDirectiveModel {
-
- public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
- throws TemplateException, IOException {
- while (true) {
- body.render(NullWriter.INSTANCE);
- }
- }
-
- }
-
- public class SleepDirective implements TemplateDirectiveModel {
-
- public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
- throws TemplateException, IOException {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // Thread.sleep has reset the interrupted flag (because it has thrown InterruptedException).
- Thread.currentThread().interrupt();
- }
- }
-
- }
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c01f1a22/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java b/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java
new file mode 100644
index 0000000..6b9d86a
--- /dev/null
+++ b/src/test/java/freemarker/core/ThreadInterruptingSupportTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 freemarker.core;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateDirectiveModel;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModel;
+import freemarker.template.utility.NullWriter;
+
+public class ThreadInterruptingSupportTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ThreadInterruptingSupportTest.class);
+
+ private static final int TEMPLATE_INTERRUPTION_TIMEOUT = 5000;
+ private final Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
+
+ @Test
+ public void test() throws IOException, InterruptedException, TemplateException {
+ assertCanBeInterrupted("<#list 1.. as x></#list>");
+ assertCanBeInterrupted("<#list 1.. as x>${x}</#list>");
+ assertCanBeInterrupted("<#list 1.. as x>t${x}</#list>");
+ assertCanBeInterrupted("<#list 1.. as x><#list 1.. as y>${y}</#list></#list>");
+ assertCanBeInterrupted("<#list 1.. as x>${x}<#else>nope</#list>");
+ assertCanBeInterrupted("<#list 1..>[<#items as x>${x}</#items>]<#else>nope</#list>");
+ assertCanBeInterrupted("<@customLoopDirective />");
+ assertCanBeInterrupted("<@customLoopDirective>x</@>");
+ assertCanBeInterrupted("<@customLoopDirective><#if true>x</#if></@>");
+ assertCanBeInterrupted("<#macro selfCalling><@sleepDirective/><@selfCalling /></#macro><@selfCalling />");
+ assertCanBeInterrupted("<#function selfCalling><@sleepDirective/>${selfCalling()}</#function>${selfCalling()}");
+ assertCanBeInterrupted("<#list 1.. as _><#attempt><@sleepDirective/><#recover>suppress</#attempt></#list>");
+ assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
+ }
+
+ private void assertCanBeInterrupted(final String templateSourceCode)
+ throws IOException, InterruptedException, TemplateException {
+ TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
+ trt.start();
+ synchronized (trt) {
+ while (!trt.isStartedOrFailed()) {
+ trt.wait();
+ }
+ }
+ if (trt.failedWith != null) {
+ if (trt.failedWith instanceof TemplateException) {
+ throw (TemplateException) trt.failedWith;
+ } else if (trt.failedWith instanceof IOException) {
+ throw (IOException) trt.failedWith;
+ } else {
+ throw new RuntimeException("Template processing has failed", trt.failedWith);
+ }
+ }
+ Thread.sleep(50); // Just to ensure (hope...) that the template execution reaches "deep" enough
+ trt.interrupt();
+ trt.join(TEMPLATE_INTERRUPTION_TIMEOUT);
+ assertTrue(trt.isTemplateProcessingInterrupted());
+ }
+
+ public class TemplateRunnerThread extends Thread {
+
+ private final Template template;
+ private boolean started;
+ private Throwable failedWith;
+ private boolean templateProcessingInterrupted;
+
+ public TemplateRunnerThread(String templateSourceCode) throws IOException {
+ template = new Template(null, "<@startedDirective/>" + templateSourceCode, cfg);
+ _CoreAPI.addThreadInterruptedChecks(template);
+ }
+
+ @Override
+ public void run() {
+ try {
+ template.process(this, NullWriter.INSTANCE);
+ } catch (TemplateProcessingThreadInterruptedException e) {
+ //LOG.debug("Template processing interrupted", e);
+ synchronized (this) {
+ templateProcessingInterrupted = true;
+ }
+ } catch (Throwable e) {
+ LOG.error("Template processing failed", e);
+ synchronized (TemplateRunnerThread.this) {
+ failedWith = e;
+ TemplateRunnerThread.this.notifyAll();
+ }
+ } finally {
+ synchronized (TemplateRunnerThread.this) {
+ if (!started && failedWith == null) {
+ failedWith = new IllegalStateException("Start directive was never called");
+ TemplateRunnerThread.this.notifyAll();
+ }
+ }
+ }
+ }
+
+ public synchronized boolean isTemplateProcessingInterrupted() {
+ return templateProcessingInterrupted;
+ }
+
+ public synchronized boolean isStartedOrFailed() {
+ return started || failedWith != null;
+ }
+
+ public TemplateDirectiveModel getStartedDirective() {
+ return new StartedDirective();
+ }
+
+ public TemplateDirectiveModel getCustomLoopDirective() {
+ return new CustomLoopDirective();
+ }
+
+ public TemplateDirectiveModel getSleepDirective() {
+ return new SleepDirective();
+ }
+
+ public class StartedDirective implements TemplateDirectiveModel {
+
+ public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+ throws TemplateException, IOException {
+ synchronized (TemplateRunnerThread.this) {
+ started = true;
+ TemplateRunnerThread.this.notifyAll();
+ }
+ }
+
+ }
+
+ public class CustomLoopDirective implements TemplateDirectiveModel {
+
+ public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+ throws TemplateException, IOException {
+ while (true) {
+ body.render(NullWriter.INSTANCE);
+ }
+ }
+
+ }
+
+ public class SleepDirective implements TemplateDirectiveModel {
+
+ public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+ throws TemplateException, IOException {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // Thread.sleep has reset the interrupted flag (because it has thrown InterruptedException).
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ }
+
+ }
+
+}