Uploaded image for project: 'Commons JEXL'
  1. Commons JEXL
  2. JEXL-206

testCallableCancel() test hangs sporadically

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 3.0
    • Fix Version/s: 3.1
    • Labels:
      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

        Attachments

          Activity

            People

            • Assignee:
              henrib Henri Biestro
              Reporter:
              dmitri_blinov Dmitri Blinov
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: