Hi, trying to set up unit tests for a given set of workflows that use mostly external tasks. The aim is testing the workflows’ principal function and error behaviour, in a completely mocked in-memory environment.
To emulate the external task client, I use a separate thread polling for tasks like this:
Here’s the complete, simplified code with a small model of three steps, two synchronous service tasks and one external task in between:
With no external tasks (ie, if you comment out line 38) everything runs fine and the process instance ends (line 60).
With the external task, the process instance does not end:
INFO [pool-1-thread-1 ] MockWorker polling ...
INFO [main ] In SignalListener: received start
INFO [main ] In Step1, trace=initial
INFO [pool-1-thread-1 ] MockWorker polling ...
INFO [pool-1-thread-1 ] In MockWorker Step2, trace=initial -> Step1
INFO [pool-1-thread-1 ] In Step3, trace=initial -> Step1 -> Step2
INFO [pool-1-thread-1 ] In SignalListener: received end
INFO [pool-1-thread-1 ] MockWorker polling ...
INFO [pool-1-thread-1 ] MockWorker polling ...
INFO [main ] ExecutorService shut down
INFO [pool-1-thread-1 ] MockWorker caught java.lang.InterruptedException
INFO [pool-1-thread-1 ] Exiting MockWorker
org.opentest4j.AssertionFailedError:
Expected :true
Actual :false
I also notice that all steps after the external task are running in the second thread, not in the main thread which makes me wonder:
Is this the right pattern? Is it allowed and safe to do this kind of multi-threaded access to the engine?
Why is it that the process instance is not ended after Step3 is executed?
Extra question: Is there a way to get notified by the engine when a process ends without explicitly modelling the end event?
Also, the last service exection from the external task client can inform you about this. As externalTaskService.complete() runs synchronus until new the process state is saved in the database, the process instance is ended when the call returns.
java.lang.IllegalArgumentException: Illegal call of complete(task = 'null', variables = '{approved=true, documentId=5}') - both must not be null!
at org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.complete(BpmnAwareTests.java:883)
at SampleProcessTest.start_and_finish_process_external(SampleProcessTest.java:55)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at org.camunda.bpm.engine.test.ProcessEngineRule$1.evaluate(ProcessEngineRule.java:172)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.camunda.bpm.spring.boot.starter.test.helper.ProcessEngineRuleRunner.run(ProcessEngineRuleRunner.java:54)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
What am I doing wrong? I suppose I defined the external Task incorrectly…didn’t I?
Many thanks in advance for your help!
Best regards,
Fabio
the external tasks are supported since camunda-bpm-assert became part of the Camunda product and no community extension anymore. The maven groupId and version have changed.