Test Receive Task with Timer Boundary Event

Hi Guys. My test was passing when i was using only a receive task waiting for a specific message, after i add a Timer Boundary to this task it starts to present the following message:

Expecting ProcessInstance {xpto} to be unfinished, but found that it already finished!

It throws on this assert

assertThat(processInstance)             
      .isWaitingAt("wait_finished_transaction_event")

which message belongs to my Received Task.

Probably i forgot to do something about the boundary i’ve added, but i don’t know why. I appreciate any help or hint.

Below a print of tis flow
image

Hello my friend! Welcome to community \o/

Probably what is happening is that you added a timer to your receive task…

When your processInstance arrives at this receive task, it waits to receive a message to continue with the flow, or waits for the timer to fire (whichever happens first).

I imagine that, at the moment a message is sent to Camunda, your instance has already been “diverted” from the path by TIMER, and followed the flow, finishing the process before the message can arrive.

In this case, in your process logs you would probably receive a “mismatchingCorrelationException” as well.

William Robert Alves

Thanks for the Welcome William!
In my case i’m not taking the “mismatchingCorrelationException” unless it’s hidden elsewhere.
On Received Task i correlate it as the code below

assertThat(processInstance)
     .isWaitingAt("wait_finished_transaction_event")

  val currentTransactionId =
      getVariableAsString(processInstance, "current_transaction_id")
  val currentIdempotencyKey =
      getVariableAsString(processInstance, "current_transaction_idempotency_key")

// TODO remove this correlation and send a message to kafka instead
runtimeService.createMessageCorrelation("waitFinishedTransactionEvent")
    .processInstanceVariableEquals(
        RecurrenceVariables.CURRENT_TRANSACTION_ID,
        currentTransactionId,
    )
    .setVariable("current_transaction_status", "SUCCEEDED")
    .setVariable("current_transaction_amount", mapOf("scale" to 2, "value" to 100))
    .correlate()

and Error

java.lang.AssertionError: Expecting ProcessInstance {id='ea1b5b94-9f52-11ee-952d-5e3512726fda', processDefinitionId='client_recurrence:1:d866bb9c-9f52-11ee-952d-5e3512726fda', businessKey='fd39b095-5bac-45eb-bc59-9602c0df5296'} to be unfinished, but found that it already finished!
	at org.camunda.bpm.engine.test.assertions.bpmn.AbstractProcessAssert.getExistingCurrent(AbstractProcessAssert.java:80)
	at org.camunda.bpm.engine.test.assertions.bpmn.ProcessInstanceAssert.isWaitingAt(ProcessInstanceAssert.java:124)
	at org.camunda.bpm.engine.test.assertions.bpmn.ProcessInstanceAssert.isWaitingAt(ProcessInstanceAssert.java:96)

Perhaps in test scenarios this mismatching error will not appear this way, as the exceptions are “assert” exceptions.

But in your case, it seems to be exactly that, in your test you are trying to correlate a message to an instance that apparently was finished, before receiving the message.

Your test is checking if the instance is waiting at the wait_finished_transaction_event point, which is probably your receive task, right?

But from what I understand, the timer is being triggered before the message is correlated.

William Robert Alves

Perhaps try putting a break-point on the assert
That should allow you to examine the variables within the Unit Test at that point and determine exactly what state your process is in at the same time.

Can you post the BPMN that you are using for testing?
It could be something as simple as the Timer in the Interrupting Boundary Timer having a very short window, causing it to interrupt the task before the assert happens. If that’s the case, the assert will fail (the process is NOT waiting at the receive task) and the test program will not even try to send the message.

The breakpoint on the assert didn’t say much. The activity for example is on the first service after start, but it’s the same for those ok tests as well.
This is my subprocess on our bpmn.

right. I’m thinking that the timer would be attached when the instance arrived on the Received Task and then trigger the duration. It strange it passes without attach the timer

I realized during debug that i got my “actual” but when it tries to getCurrent() returns null. if i removed the timer everything goes fine.

Its not respecting the duration from the boundary on received task. It goes above instead of wait to correlate it

Please post the actual BPMN file, not an image of it.
We can’t look at the details of the configuration in the image.

It could also be something with the test engine – that it might not be honoring timer in order to allow the tests to run in a quick time frame.

client_recurrence.bpmn (72.3 KB)
there we go

I think there is a hint in the actual BPMN that wasn’t obvious from the image…

Try unit testing JUST the subprocess, not the overall process, since you are doing a parallel multi-instance process. It’s possible that whatever is calling your correlation from the other side is getting matched on all instances, so your subprocess isn’t waiting at the receive anymore.

Almost quitting, in tests boundary timer is not working at all but when i do a local dry run it works as expected. Seems that time duration from the timer is not getting by the test. i’ve tried everything. setting job and hasDueDate onto waiting received task, passing duration variable through init process instance. test with another boundaries which works fine, the only problem is boundary timer.

Hi @Paulo_Leite,

usually in a JUnit test, the job executor is disabled.

Then you have to write execute(job()) from the bpm-assert library to execute the job: Assert Examples | docs.camunda.org

With this, you don’t have to wait until the due date is reached, and you can test timers that will become due in two weeks.

Hope this helps, Ingo

@Ingo_Richtsmeier That’s actually the opposite issue being reported here… @Paulo_Leite is finding that with a boundary timer the JUnit test is NOT waiting for the timer to go off.

Right. It should waiting on Received Task and attach the boundary timer to the instance when arrive, but it’s trigger the boundary immediately when try to waiting on Received Task activity the processInstance is gone.

Hi @Paulo_Leite,

I tried to test your process by myself and found that you checked the receive task with async before.

This is not required for a receive task as it is already a wait state.

With executing two jobs, first to enter the receive task and the second to fire the boundary timer event, my example tests with the plain JUnit tests went green.

Here is my test class:

package com.camunda.consulting.simple_spring_boot_process_app;

import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*;
import static org.assertj.core.api.Assertions.*;

import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.test.Deployment;
import org.camunda.bpm.engine.test.mock.Mocks;
import org.camunda.community.process_test_coverage.junit5.platform7.ProcessEngineCoverageExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(ProcessEngineCoverageExtension.class)
public class ProcessJUnitTestClientRecurrence {

  @Test
  @Deployment(resources = "client_recurrence.bpmn")
  public void testBoundaryTimer() {
    Mocks.register("recurrenceOrderStatusUpdateDelegate", new LoggerDelegate());

    ProcessInstance processInstance =
        runtimeService().createProcessInstanceByKey("client_recurrence")
            .startBeforeActivity("wait_finished_transaction_event")
            .setVariable("transaction_information", new TransactionInformation("transaction_id"))
            .execute();

    assertThat(processInstance).isWaitingAt("wait_finished_transaction_event");

    execute(job());
    execute(job());

    assertThat(processInstance).isWaitingAt("notify_expired_transaction_recurrence_manager");
  }

  @Test
  @Deployment(resources = "client_recurrence.bpmn")
  public void testMessageCorrelation() {
    ProcessInstance processInstance =
        runtimeService().createProcessInstanceByKey("client_recurrence")
            .startBeforeActivity("wait_finished_transaction_event")
            .setVariable("transaction_information", new TransactionInformation("transaction_id"))
            .execute();

    assertThat(processInstance).isWaitingAt("wait_finished_transaction_event");
    
    execute(job());
    assertThat(processInstance).isWaitingAt("wait_finished_transaction_event");
    
    runtimeService().createMessageCorrelation("waitFinishedTransactionEvent").correlate();
    
    assertThat(processInstance).isWaitingAt("get_transaction");
  }
}

When I remove the async before from the receive task, I have to remove one of the execute(job()) statements.

Hope this helps, Ingo

Thanks folks, many hints here, helped me to understand a little bit more a bout the jobs. one of our problems were a generic loop to execute jobs until some waiting, we had to change it to execute job and exclude some if required. that works