Last active
January 3, 2024 16:12
-
-
Save chaserb/a319a994eb6ebb8c936206e3122fdf96 to your computer and use it in GitHub Desktop.
Test Various ISO-8601 Duration Strings in Flowable Engine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> | |
<bean id="dataSource" class="org.flowable.common.engine.impl.test.ClosingDataSource"> | |
<constructor-arg> | |
<bean class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"> | |
<constructor-arg> | |
<bean class="com.zaxxer.hikari.HikariConfig"> | |
<property name="minimumIdle" value="0" /> | |
<property name="jdbcUrl" value="${jdbc.url:jdbc:h2:mem:flowable;DB_CLOSE_DELAY=1000}"/> | |
<property name="driverClassName" value="${jdbc.driver:org.h2.Driver}"/> | |
<property name="username" value="${jdbc.username:sa}"/> | |
<property name="password" value="${jdbc.password:}"/> | |
</bean> | |
</constructor-arg> | |
</bean> | |
</constructor-arg> | |
</bean> | |
<bean id="processEngineConfiguration" class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration"> | |
<property name="asyncExecutorActivate" value="false" /> | |
<property name="asyncFailedJobWaitTime" value="1" /> | |
<property name="asyncHistoryEnabled" value="false" /> | |
<property name="clock"> | |
<bean class="org.flowable.common.engine.impl.util.TestClockImpl" /> | |
</property> | |
<property name="dataSource" ref="dataSource"/> | |
<property name="databaseSchemaUpdate" value="drop-create" /> | |
<property name="enableHistoricTaskLogging" value="true"/> | |
<property name="enableProcessDefinitionHistoryLevel" value="true" /> | |
<property name="enableProcessDefinitionInfoCache" value="true" /> | |
<property name="history" value="full" /> | |
</bean> | |
</beans> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:flowable="http://flowable.org/bpmn" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef" exporter="Flowable Open Source Modeler" exporterVersion="6.8.0"> | |
<process id="waitTask" name="Wait" isExecutable="true"> | |
<startEvent id="wait-start" name="Start" flowable:formFieldValidation="true"></startEvent> | |
<intermediateCatchEvent id="wait-wait" name="Wait"> | |
<timerEventDefinition> | |
<timeDuration>${waitTaskWaitTime}</timeDuration> | |
</timerEventDefinition> | |
</intermediateCatchEvent> | |
<endEvent id="wait-end" name="End"></endEvent> | |
<sequenceFlow id="wait-flow1" sourceRef="wait-start" targetRef="wait-wait"></sequenceFlow> | |
<sequenceFlow id="wait-flow2" sourceRef="wait-wait" targetRef="wait-end"></sequenceFlow> | |
</process> | |
</definitions> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.test; | |
import org.assertj.core.data.Offset; | |
import org.flowable.common.engine.impl.runtime.Clock; | |
import org.flowable.common.engine.impl.util.DefaultClockImpl; | |
import org.flowable.engine.HistoryService; | |
import org.flowable.engine.ManagementService; | |
import org.flowable.engine.ProcessEngineConfiguration; | |
import org.flowable.engine.RuntimeService; | |
import org.flowable.engine.impl.test.JobTestHelper; | |
import org.flowable.engine.test.Deployment; | |
import org.flowable.engine.test.FlowableTest; | |
import org.junit.jupiter.api.BeforeEach; | |
import org.junit.jupiter.params.ParameterizedTest; | |
import org.junit.jupiter.params.provider.ValueSource; | |
import java.time.Duration; | |
import java.time.Instant; | |
import java.time.Period; | |
import java.time.ZoneId; | |
import java.time.ZonedDateTime; | |
import java.util.Date; | |
import java.util.GregorianCalendar; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.TimeZone; | |
import static org.assertj.core.api.Assertions.assertThat; | |
@FlowableTest | |
public class WaitTaskTest { | |
private ProcessEngineConfiguration processEngineConfiguration; | |
private RuntimeService runtimeService; | |
private HistoryService historyService; | |
private ManagementService managementService; | |
private static final TimeZone UTC = TimeZone.getTimeZone(ZoneId.of("UTC")); | |
private final Clock testClock = new DefaultClockImpl(UTC); | |
private final Map<String, Object> input = new HashMap<>(); | |
@BeforeEach | |
protected void setUpInput(ProcessEngineConfiguration processEngineConfiguration, RuntimeService runtimeService, | |
HistoryService historyService, ManagementService managementService) { | |
this.processEngineConfiguration = processEngineConfiguration; | |
this.runtimeService = runtimeService; | |
this.historyService = historyService; | |
this.managementService = managementService; | |
TimeZone.setDefault(UTC); | |
processEngineConfiguration.setClock(testClock); | |
testClock.setCurrentTime(new Date()); | |
input.clear(); | |
} | |
@ParameterizedTest | |
@ValueSource(strings = {"PT10S", "P2D", "P4DT12H30M10S"}) | |
@Deployment(resources = {"processes/process-waitTask.bpmn20.xml"}) | |
public void testWaitWithDuration(String durationString) { | |
// Set up a clock we can manually forward for testing | |
Duration totalDuration = Duration.parse(durationString); | |
Instant currentInstant = Instant.now(); | |
Instant halfInterval = currentInstant.plus(totalDuration.dividedBy(2)); | |
Instant fullInterval = halfInterval.plus(totalDuration.dividedBy(2)); | |
input.put("waitTaskWaitTime", durationString); | |
testInterval(halfInterval, fullInterval, testClock, totalDuration.toMillis()); | |
} | |
@ParameterizedTest | |
@ValueSource(strings = {"P5Y", "P4M", "P3W", "P2D"}) | |
@Deployment(resources = {"processes/process-waitTask.bpmn20.xml"}) | |
public void testWaitWithPeriod(String durationString) { | |
// Set up a clock we can manually forward for testing | |
Period totalPeriod = Period.parse(durationString); | |
ZonedDateTime currentTime = ZonedDateTime.now(); | |
ZonedDateTime fullInterval = currentTime.plus(totalPeriod); | |
long periodInSeconds = fullInterval.toEpochSecond() - currentTime.toEpochSecond(); | |
ZonedDateTime halfInterval = currentTime.plusSeconds(periodInSeconds / 2); | |
input.put("waitTaskWaitTime", durationString); | |
testInterval(halfInterval.toInstant(), fullInterval.toInstant(), testClock, periodInSeconds * 1000); | |
} | |
private void testInterval(final Instant halfInterval, final Instant fullInterval, final Clock testClock, final long intervalMillis) { | |
// Configure the wait time | |
runtimeService.startProcessInstanceByKey("waitTask", input); | |
waitForJobsAndTimers(); | |
// Forward the clock half of the total wait time | |
testClock.setCurrentCalendar(GregorianCalendar.from(ZonedDateTime.ofInstant(halfInterval, UTC.toZoneId()))); | |
waitForJobsAndTimers(); | |
// Ensure that our workflow is still running (ie the `wait-end` activity has not been executed) | |
assertThat(historyService.createHistoricActivityInstanceQuery().activityId("wait-end").singleResult()).isNull(); | |
// Forward the clock another half-interval (thus we've awaited the whole interval) | |
testClock.setCurrentCalendar(GregorianCalendar.from(ZonedDateTime.ofInstant(fullInterval, UTC.toZoneId()))); | |
waitForJobsAndTimers(); | |
// Ensure that our task is finished | |
assertThat(historyService.createHistoricActivityInstanceQuery().activityId("wait-end").singleResult()).isNotNull(); | |
// Ensure that our wait task has an execution duration that matches our input | |
assertThat(historyService.createHistoricActivityInstanceQuery().activityId("wait-wait").singleResult().getDurationInMillis()).isCloseTo(intervalMillis, Offset.offset(100L)); | |
} | |
protected void waitForJobsAndTimers() { | |
JobTestHelper.waitForJobExecutorToProcessAllJobs(processEngineConfiguration, | |
managementService, 10_000L, 100L); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note, the "P3W" input on the
testWaitWithPeriod()
test fails with Flowable 7.0.0