diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/HistoricTaskInstanceTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/HistoricTaskInstanceTest.java index 5b3c489c861..01bb56bf936 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/HistoricTaskInstanceTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/HistoricTaskInstanceTest.java @@ -24,14 +24,15 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableIllegalArgumentException; import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.engine.impl.test.PluggableFlowableTestCase; -import org.flowable.engine.runtime.ActivityInstance; import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.test.Deployment; @@ -990,4 +991,115 @@ public void testQueryByParentScopeId() { ); } + @Test + @Deployment(resources = { + "org/flowable/engine/test/api/oneTaskProcess.bpmn20.xml" + }) + public void testQueryByVariousTimeConstraints() { + + // Test for https://github.com/flowable/flowable-engine/issues/3827 + + Date testStartTime = new Date(); + processEngineConfiguration.getClock().setCurrentTime(testStartTime); + + Set processInstanceIds = new HashSet<>(); + for (int i = 0; i < 4; i++){ + processInstanceIds.add(runtimeService.startProcessInstanceByKey("oneTaskProcess").getId()); + } + + Date afterInstancesStartedTime = new Date(testStartTime.getTime() + 10_000); + processEngineConfiguration.getClock().setCurrentTime(afterInstancesStartedTime); + + for (String processInstanceId : processInstanceIds) { + + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)).count()).isOne(); + + // Start time + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskCreatedAfter(new Date(testStartTime.getTime() - 10_000)).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskCreatedBefore(new Date(afterInstancesStartedTime.getTime())).count()).isOne(); + + // Claim --> change state + taskService.claim(taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult().getId(), "johnDoe"); + } + + Date afterClaimTime = new Date(afterInstancesStartedTime.getTime() + 10_000); + processEngineConfiguration.getClock().setCurrentTime(afterClaimTime); + + for (String processInstanceId : processInstanceIds) { + // State + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskState(Task.CLAIMED).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskClaimedBy("johnDoe").count()).isOne(); + + // Claim time + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskClaimedAfter(new Date(afterInstancesStartedTime.getTime() - 10_000)).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskClaimedBefore(new Date(afterClaimTime.getTime())).count()).isOne(); + + // Make tasks in progress + taskService.startProgress(taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult().getId(), "johnDoe"); + } + + Date afterInProgressTime = new Date(afterClaimTime.getTime() + 10_000); + processEngineConfiguration.getClock().setCurrentTime(afterInProgressTime); + + for (String processInstanceId : processInstanceIds) { + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskState(Task.IN_PROGRESS).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskInProgressStartedBy("johnDoe").count()).isOne(); + + // In progress time + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskInProgressStartTimeAfter(new Date(afterClaimTime.getTime() - 10_000)).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskInProgressStartTimeBefore(new Date(afterInProgressTime.getTime())).count()).isOne(); + + // Suspend the tasks + taskService.suspendTask(taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult().getId(), "johnDoe"); + } + + Date afterSuspendTime = new Date(afterInProgressTime.getTime() + 10_000); + processEngineConfiguration.getClock().setCurrentTime(afterSuspendTime); + + for (String processInstanceId : processInstanceIds) { + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskState(Task.SUSPENDED).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskSuspendedBy("johnDoe").count()).isOne(); + + // Suspend time + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskSuspendedAfter(new Date(afterInProgressTime.getTime() - 10_000)).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskSuspendedBefore(new Date(afterSuspendTime.getTime())).count()).isOne(); + + // Complete the tasks + taskService.activateTask(taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult().getId(), "johnDoe"); + taskService.complete(taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult().getId(), "johnDoe"); + } + + Date afterCompleteTime = new Date(afterSuspendTime.getTime() + 10_000); + processEngineConfiguration.getClock().setCurrentTime(afterSuspendTime); + + for (String processInstanceId : processInstanceIds) { + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskState(Task.COMPLETED).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskCompletedBy("johnDoe").count()).isOne(); + + // Completion time + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskCompletedAfter(new Date(afterSuspendTime.getTime() - 10_000)).count()).isOne(); + assertThat(historyService.createHistoricTaskInstanceQuery().processInstanceIdIn(Collections.singletonList(processInstanceId)) + .taskCompletedBefore(new Date(afterCompleteTime.getTime())).count()).isOne(); + } + + } + } diff --git a/modules/flowable-task-service-api/src/main/java/org/flowable/task/api/history/HistoricTaskInstanceQuery.java b/modules/flowable-task-service-api/src/main/java/org/flowable/task/api/history/HistoricTaskInstanceQuery.java index 8431a2173fc..c9b275c7ff2 100644 --- a/modules/flowable-task-service-api/src/main/java/org/flowable/task/api/history/HistoricTaskInstanceQuery.java +++ b/modules/flowable-task-service-api/src/main/java/org/flowable/task/api/history/HistoricTaskInstanceQuery.java @@ -58,20 +58,25 @@ public interface HistoricTaskInstanceQuery extends TaskInfoQuery - or ${queryTablePrefix}STATE_ = #{state} + and ${queryTablePrefix}STATE_ = #{state} - or ${queryTablePrefix}START_TIME_ = #{createTime} + and ${queryTablePrefix}START_TIME_ = #{createTime} - or ${queryTablePrefix}START_TIME_ < #{createTimeBefore} + and ${queryTablePrefix}START_TIME_ < #{createTimeBefore} - or ${queryTablePrefix}START_TIME_ > #{createTimeAfter} + and ${queryTablePrefix}START_TIME_ > #{createTimeAfter} - or ${queryTablePrefix}IN_PROGRESS_TIME_ = #{inProgressStartTime} + and ${queryTablePrefix}IN_PROGRESS_TIME_ = #{inProgressStartTime} - or ${queryTablePrefix}IN_PROGRESS_TIME_ < #{inProgressStartTimeBefore} + and ${queryTablePrefix}IN_PROGRESS_TIME_ < #{inProgressStartTimeBefore} - or ${queryTablePrefix}IN_PROGRESS_TIME_ > #{inProgressStartTimeAfter} + and ${queryTablePrefix}IN_PROGRESS_TIME_ > #{inProgressStartTimeAfter} - or ${queryTablePrefix}IN_PROGRESS_STARTED_BY = #{inProgressStartedBy} + and ${queryTablePrefix}IN_PROGRESS_STARTED_BY_ = #{inProgressStartedBy} - or ${queryTablePrefix}CLAIM_TIME_ = #{claimTime} + and ${queryTablePrefix}CLAIM_TIME_ = #{claimTime} - or ${queryTablePrefix}CLAIM_TIME_ < #{claimTimeBefore} + and ${queryTablePrefix}CLAIM_TIME_ < #{claimTimeBefore} - or ${queryTablePrefix}CLAIM_TIME_ > #{claimTimeAfter} + and ${queryTablePrefix}CLAIM_TIME_ > #{claimTimeAfter} - or ${queryTablePrefix}CLAIMED_BY = #{claimedBy} + and ${queryTablePrefix}CLAIMED_BY_ = #{claimedBy} - or ${queryTablePrefix}SUSPENDED_TIME_ = #{suspendedTime} + and ${queryTablePrefix}SUSPENDED_TIME_ = #{suspendedTime} - or ${queryTablePrefix}SUSPENDED_TIME_ < #{suspendedTimeBefore} + and ${queryTablePrefix}SUSPENDED_TIME_ < #{suspendedTimeBefore} - or ${queryTablePrefix}SUSPENDED_TIME_ > #{suspendedTimeAfter} + and ${queryTablePrefix}SUSPENDED_TIME_ > #{suspendedTimeAfter} - or ${queryTablePrefix}SUSPENDED_BY = #{suspendedBy} + and ${queryTablePrefix}SUSPENDED_BY_ = #{suspendedBy} - or ${queryTablePrefix}END_TIME_ = #{completedTime} + and ${queryTablePrefix}END_TIME_ = #{completedTime} - or ${queryTablePrefix}END_TIME_ < #{completedTimeBefore} + and ${queryTablePrefix}END_TIME_ < #{completedTimeBefore} - or ${queryTablePrefix}END_TIME_ > #{completedTimeAfter} + and ${queryTablePrefix}END_TIME_ > #{completedTimeAfter} - or ${queryTablePrefix}COMPLETED_BY = #{completedBy} + and ${queryTablePrefix}COMPLETED_BY_ = #{completedBy} - or ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ = #{inProgressStartDueDate} + and ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ = #{inProgressStartDueDate} - or ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ < #{inProgressStartDueBefore} + and ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ < #{inProgressStartDueBefore} - or ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ > #{inProgressStartDueAfter} + and ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ > #{inProgressStartDueAfter} and ${queryTablePrefix}DUE_DATE_ = #{dueDate} @@ -1705,7 +1705,7 @@ or ${queryTablePrefix}IN_PROGRESS_TIME_ > #{orQueryObject.inProgressStartTimeAfter} - or ${queryTablePrefix}IN_PROGRESS_STARTED_BY = #{orQueryObject.inProgressStartedBy} + or ${queryTablePrefix}IN_PROGRESS_STARTED_BY_ = #{orQueryObject.inProgressStartedBy} or ${queryTablePrefix}CLAIM_TIME_ = #{orQueryObject.claimTime} @@ -1717,7 +1717,7 @@ or ${queryTablePrefix}CLAIM_TIME_ > #{orQueryObject.claimTimeAfter} - or ${queryTablePrefix}CLAIMED_BY = #{orQueryObject.claimedBy} + or ${queryTablePrefix}CLAIMED_BY_ = #{orQueryObject.claimedBy} or ${queryTablePrefix}SUSPENDED_TIME_ = #{orQueryObject.suspendedTime} @@ -1729,7 +1729,7 @@ or ${queryTablePrefix}SUSPENDED_TIME_ > #{orQueryObject.suspendedTimeAfter} - or ${queryTablePrefix}SUSPENDED_BY = #{orQueryObject.suspendedBy} + or ${queryTablePrefix}SUSPENDED_BY_ = #{orQueryObject.suspendedBy} or ${queryTablePrefix}END_TIME_ = #{orQueryObject.completedTime} @@ -1741,7 +1741,7 @@ or ${queryTablePrefix}END_TIME_ > #{orQueryObject.completedTimeAfter} - or ${queryTablePrefix}COMPLETED_BY = #{orQueryObject.completedBy} + or ${queryTablePrefix}COMPLETED_BY_ = #{orQueryObject.completedBy} or ${queryTablePrefix}IN_PROGRESS_DUE_DATE_ = #{orQueryObject.inProgressStartDueDate}