camunda-community-hub / camunda-platform-scenario

Easily execute Camunda process scenarios and verify your expectations with Given/Then/When style tests.
Apache License 2.0
66 stars 15 forks source link

defer() does not trigger bounded timer event in parallel call activity with more than one instance #91

Open ykoitzsch opened 2 years ago

ykoitzsch commented 2 years ago

Process: A call activity runs multiple instances of a sub-process with a bounded timer event.

process_with_callactivity

What works: If only a single instance (loop cardinality = 1) is used, the timer works as intended (defer() time > timer) and the process enters the "inform boss" branch

What does not work: If 2 instances (loop cardinality = 2) are used, the timer does not trigger on a defer() that "takes too long" and the process never enters the "inform boss" branch

Doing the same with a) embedded subprocesses does work or b) doing it with "plain" camunda-bpmn-assert.

See attached project for tests: ProcessEngineTest & ProcessScenarioTest, they are more or less identical, once written using platform-scenario, once written use camunda bpmn assert only.

process_with_subprocess

Is defer() used wrong here or is there same issue with the timer?

timed-camunda-scenario-issue.zip

rweisleder commented 2 years ago

The essence of this issue is that in the test code the following construct is used:

ProcessScenario scenario = mock(ProcessScenario.class);
ProcessScenario subScenario = mock(ProcessScenario.class);
when(scenario.runsCallActivity("CallWork")).thenReturn(Scenario.use(subScenario));

This means that the same scenario (as in "same Java object") is returned each time the call activity is called. In this example, the call activity is called twice. Due to the parallel execution, both instances will get mixed up.

To fix the issue, you need to change the construct to:

ProcessScenario scenario = mock(ProcessScenario.class);
ProcessScenario subScenario = mock(ProcessScenario.class);
when(scenario.runsCallActivity("CallWork")).thenAnswer(invocation -> Scenario.use(subScenario));

See also #92