Execution of BoundaryEvents inside Unit Tests

757 views
Skip to first unread message

Qaiser Abbasi

unread,
Jun 29, 2015, 5:27:40 AM6/29/15
to camunda...@googlegroups.com
Hi,

Background

currently I´am developing a possibility to test Camunda BPM processes altogether with a running Java EE infrastructure (namely CDI) without the need of Arquillian (due to the configuration nightmare etc. etc.) as suggested in Testing Guide... I´am applying the testing scope 2.


Concretely I´am using Camunda´s @ProcessEngineRule altogether with Camunda-BPM-Assert API to have a running embbeded Camunda inside the test setup (StandaloneInMemoryProcessEngineConfiguration). On the other hand, I´am using DeltaSpike´s "Test-Control" module for providing a CDI environment (using Weld-SE) during the tests. Finally I´am joining them via a custom ExpressionManager, which resolves for EL expressions the corresponding deployed CDI Beans (using DeltaSpike´s BeanProvider).


Problem statement

How do I trigger BoundaryEvents (Timer-Events) declared inside a ServiceTask inside the "Unit Tests"? I already tried to fetch and execute the BoundaryEvents via the JobQuery API (but the corresponding job is not listed) and to trigger them implicitly via a "timeout" using the ClockUtil (I know nasty idea :])(also not working)



Peace,

Qaiser

thorben.lindhauer

unread,
Jun 29, 2015, 7:22:04 AM6/29/15
to camunda...@googlegroups.com
Hi Qaiser,

You are going in the right direction. Executing jobs in a controlled fashion with ManagementService#executeJob is the way we also take in the engine test suite. The current ClockUtil value should not be relevant for executing the job, it is only used for acquiring jobs when the job executor is active.

To help you with your problem, could you please post your test case or a simplified version of it? You can also have a look at an engine test case for timer boundary events and compare your solution, see [1].

Cheers,
Thorben

[1] https://github.com/camunda/camunda-bpm-platform/blob/master/engine/src/test/java/org/camunda/bpm/engine/test/examples/bpmn/event/timer/BoundaryTimerEventTest.java

Martin Schimak

unread,
Jun 29, 2015, 7:29:51 AM6/29/15
to camunda...@googlegroups.com
Hi all,

are boundary timer events on service tasks even supported? Last time I checked this, they were not… but it’s a while ago. Best practice was to have a short-lived service task which asynchronously triggers an external something. One could then put a boundary timer event on a subsequent receive task.

Martin.
> --
> You received this message because you are subscribed to the Google Groups "camunda BPM platform contributors" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to camunda-bpm-d...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/camunda-bpm-dev/047a9745-82db-4dc8-9a62-87b89861591e%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

thorben.lindhauer

unread,
Jun 29, 2015, 7:34:00 AM6/29/15
to camunda...@googlegroups.com
Hi Martin,

Good point, I missed that aspect. What you write is correct in case you have a synchronous service task. With asynchronous service tasks, even if they are implemented as one activity (as described in [1]), boundary events should work.

Cheers,
Thorben

[1] https://github.com/camunda/camunda-bpm-examples/tree/master/servicetask/service-invocation-asynchronous

Martin Schimak

unread,
Jun 29, 2015, 7:42:37 AM6/29/15
to camunda...@googlegroups.com
Hi Thorben,

that’s a very elegant solution for not showing the often mainly technical aspect of asynchronity in the process diagram. I wanted to try that for a long time, but no concrete need since then. Thanks for the clarification, that even boundary timer events should work with that.

Martin.
> To view this discussion on the web visit https://groups.google.com/d/msgid/camunda-bpm-dev/196d3331-0169-4a78-8e53-d3734ff41634%40googlegroups.com.

Qaiser Abbasi

unread,
Jun 29, 2015, 9:24:50 AM6/29/15
to camunda...@googlegroups.com
Aloha,
so this the "process" (simplified due of NDA issues etc.) I want to test; in particular the "unhappy" aka "reality" path :)

Testcase: Enter ServiceTask A, timeout should occur (simulated), enter state "yolo", fin.


The corresponding JUnit test for the positive path goes as following:


@RunWith(CdiTestRunner.class)
public class Important$Test {

@Rule
public ProcessEngineRule processEngineRule = new ProcessEngineRule();

@Test
@Deployment(resources = "bla.bpmn")
public void should_Successfully_End_In_Green_State() {
ProcessInstance processInstance = processEngine().getRuntimeService()
.startProcessInstanceByKey("bla");

assertThat(processInstance)
.isStarted()
.isWaitingAt(taskA)
.variables()
.containsExactly(
MapEntry.entry("standardTime", "PT10M"),
MapEntry.entry("state", State.GREEN),
MapEntry.entry("timeout", "PT5M"));
execute(job());

assertThat(processInstance).isWaitingAt(taskB);
execute(job());

assertThat(processInstance).isWaitingAt(taskC);
execute(job());

assertThat(processInstance).isWaitingAt(taskD);
execute(job());

assertThat(processInstance)
.isWaitingAt(taskStatusGreen)
.variables().containsEntry(Camunda.STATE, State.GREEN);
execute(job());

assertThat(processInstance)
.isEnded()
.hasPassedInOrder(taskA, taskB, taskC
taskD, taskStatusGreen);
}



Yep, a no brainer.

And now the "unhappy" path


@Test
@Deployment(resources = "bla.bpmn")
public void when_Standard_Timeout_Occurs_Should_End_In_Yellow_State() {
    ProcessInstance processInstance = processEngine().getRuntimeService()
            .startProcessInstanceByKey("bla");

    assertThat(processInstance)
            .isWaitingAt(taskA)

    /** Trying to trigger BoundaryEvent "BoundaryEventA" */

// as stated this will have no effect on triggering of the boundary event
processEngineRule.setCurrentTime(new Date(currentDate + timeout));

// jobQuery also doesn´t work here -> will return null
execute(jobQuery().jobId("BoundaryEventA").singleResult());

// will return exactly one message event and not a timer event
jobQuery().active().list();

// fails
assertThat(processInstance)
.isWaitingAt(taskTimeoutA);

   


}

I read somewhere in the documentation that, in order to have such BoundaryEvents, one also have to provide a job executor, which is of course not provided in the test setup.

I keen to hear from you guys (btw thx for the insane response time :P),
Qaiser

thorben.lindhauer

unread,
Jun 29, 2015, 10:27:05 AM6/29/15
to camunda...@googlegroups.com
Hi Qaiser,

How is service task A implemented? Is service task A asynchronous, i.e. is the attribute camunda:asyncBefore set to true?

On the job executor: The job executor sets up a (or uses an existing) thread pool and regularly polls the database for jobs to execute them. In test cases, we recommend to deactivate it and instead execute jobs via the ManagementService API. This allows controlled job execution.

Cheers,
Thorben

Qaiser Abbasi

unread,
Jun 29, 2015, 10:49:48 AM6/29/15
to camunda...@googlegroups.com
Hi Thorben,

yes, this and the other ServiceTasks are all implemented async.

btw: I´m pondering about a more hackish "solution" aka. workaround. What if I play the role of a JobHandler and reroute the sequence flow in the desired direction? Does this makes any sense?

Peace,
Qaiser

thorben.lindhauer

unread,
Jun 29, 2015, 10:59:21 AM6/29/15
to camunda...@googlegroups.com
Hi Qaiser,

Ok, I understand why there is no job. AsyncBefore means the process engine stops execution before activity A is entered (and creates a job to continue execution at that point). Thus, boundary events cannot be triggered since the activity isn't active yet. Accordingly, no job for the boundary events exist yet.

If you have implemented the service task as a regular java delegate, then once the async continuation is performed, the service task is executed synchronously, meaning in one transaction, the activity is started, the java delegate is invoked, and the activity is left again. For these synchronous implementations, it is not possible to trigger boundary events, because we do not interrupt a running thread. That is also the point Martin Schimak made in his first post.
Now there is one case where you actually can use boundary events with service tasks, which is the asynchronous service task pattern (cf [1]). Although named similarly, this is not the same as setting the asyncBefore flag. The asynchronous service task pattern is a way to have a transaction boundary within the execution of a service task. In that case, boundary events can be triggered because the process engine stops executing when the service task is indeed active (and resumes execution later).

I hope that makes sense.

Qaiser Abbasi

unread,
Jun 29, 2015, 11:13:50 AM6/29/15
to camunda...@googlegroups.com
Hi Thorben,

I got the idea. Frankly speaking, this is something to chew :)

Due to the very fact that the corresponding Service Tasks are actually regular Java Delegates, by nature the service invocation will be performed in a sync. fashion and that´s why we are not able to trigger them, mhm. Alright - that is (at least for me) also a result :)

Peace and many thx
Qaiser
Reply all
Reply to author
Forward
0 new messages