Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
3.0
-
None
Description
I'm struggling with strange behaviour of the building process, it seems that time after time the process hangs somewhere in the middle of the tests stage. First I thought it was somehow related to memory problems so I changed fork mode of the test plugin by adding <forkMode>pertest</forkMode> to maven-surefire-plugin configuration. But that helped for a couple of times to cleanly build jexl and run all tests successfully. The other times it simply hanged on test stage. I have managed to detect that it is the testCallableCancel() test that hangs. One of its worker threads has a stack trace as follows:
org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:893) org.apache.commons.jexl3.parser.ASTWhileStatement.jjtAccept(ASTWhileStatement.java:18) org.apache.commons.jexl3.internal.Interpreter.visit(Interpreter.java:1119) org.apache.commons.jexl3.parser.ASTJexlScript.jjtAccept(ASTJexlScript.java:55) org.apache.commons.jexl3.internal.Interpreter.interpret(Interpreter.java:210) org.apache.commons.jexl3.internal.Script$Callable.interpret(Script.java:364) org.apache.commons.jexl3.internal.Script$Callable.call(Script.java:372) - locked org.apache.commons.jexl3.internal.Script$Callable@18399f62 java.util.concurrent.FutureTask.run(FutureTask.java:262) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) java.lang.Thread.run(Thread.java:745)
I have adjusted the test code with prinln() to dig further what is going on:
@Test public void testCallableCancel() throws Exception { System.out.println("testCallableCancel(): started"); JexlScript e = JEXL.createScript("while(true);"); final Script.Callable c = (Script.Callable) e.callable(null); Object t = 42; Callable<Object> kc = new Callable<Object>() { @Override public Object call() throws Exception { System.out.println("testCallableCancel(): cancel() is called"); return c.cancel(); } }; Callable<Object> xkc = new Callable<Object>() { @Override public Object call() throws Exception { System.out.println("testCallableCancel(): run() is called"); return c.call(); } }; ExecutorService executor = Executors.newFixedThreadPool(2); Future<?> future = executor.submit(xkc); Future<?> kfc = executor.submit(kc); try { Assert.assertTrue((Boolean) kfc.get()); System.out.println("testCallableCancel(): canceled()"); t = future.get(); Assert.fail("should have been cancelled"); } catch (ExecutionException xexec) { // ok, ignore Assert.assertTrue(xexec.getCause() instanceof JexlException.Cancel); } finally { executor.shutdown(); } Assert.assertTrue(c.isCancelled()); System.out.println("testCallableCancel(): finished"); }
If the test hangs it prints the following:
testCallableCancel(): started
testCallableCancel(): run() is called
testCallableCancel(): cancel() is called
testCallableCancel(): canceled()
If the test runs as normal and does not hang it prints the following:
testCallableCancel(): started
testCallableCancel(): run() is called
testCallableCancel(): cancel() is called
testCallableCancel(): canceled()
testCallableCancel(): finished