Executor should poll until the queue is empty

- Default state machine executor: queue polling defect proof test.
- Default state machine executor: queue polling fixed.
- Backport #520
- Relates #496
This commit is contained in:
Nadim Benabdenbi
2018-03-03 00:21:22 +01:00
committed by Janne Valkealahti
parent dd8c4ea665
commit 45b6b2e5ae
2 changed files with 62 additions and 0 deletions

View File

@@ -378,6 +378,7 @@ public class DefaultStateMachineExecutor<S, E> extends LifecycleObjectSupport im
}
}
}
return true;
}
return false;
}

View File

@@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.statemachine.StateContext;
@@ -254,6 +255,66 @@ public class DefaultStateMachineExecutorTests {
assertThat(transit.transitions.size(), is(2));
}
@SuppressWarnings("unchecked")
@Test
public void testEventPolling() throws Exception {
// event polling should continue even if an event is no more relevant.
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
final CountDownLatch latch = new CountDownLatch(1);
EventTrigger<String, String> triggerE1 = new EventTrigger<String, String>("E1");
State<String, String> stateS1 = mock(State.class);
when(stateS1.getId()).thenReturn("S1");
when(stateS1.getIds()).thenReturn(Arrays.asList("S1"));
State<String, String> stateS2 = mock(State.class);
when(stateS2.getId()).thenReturn("S2");
when(stateS2.getIds()).thenReturn(Arrays.asList("S2"));
StateMachine<String, String> stateMachine = mock(StateMachine.class);
when(stateMachine.getState()).thenReturn(stateS1);
Transition<String, String> transitionS1S2 = mock(Transition.class);
when(transitionS1S2.getSource()).thenReturn(stateS1);
when(transitionS1S2.getTarget()).thenReturn(stateS2);
when(transitionS1S2.getTrigger()).thenReturn(triggerE1);
when(transitionS1S2.transit(any())).thenAnswer(x -> {
when(stateMachine.getState()).thenReturn(stateS2);
return true;
});
Collection<Transition<String, String>> transitions = new ArrayList<>();
transitions.add(transitionS1S2);
Map<Trigger<String, String>, Transition<String, String>> triggerToTransitionMap = new HashMap<>();
triggerToTransitionMap.put(triggerE1, transitionS1S2);
List<Transition<String, String>> triggerlessTransitions = new ArrayList<>();
Transition<String, String> initialTransition = mock(Transition.class);
Message<String> initialEvent = null;
DefaultStateMachineExecutor<String, String> executor = new DefaultStateMachineExecutor<>(
stateMachine,
stateMachine,
transitions,
triggerToTransitionMap,
triggerlessTransitions,
initialTransition,
initialEvent,
null);
executor.setTaskExecutor(taskExecutor);
executor.setStateMachineExecutorTransit((x, y, z) -> latch.countDown());
executor.start();
//E2 should not stuck the event polling as it is not relevant.
executor.queueEvent(new GenericMessage<>("E2"));
executor.queueEvent(new GenericMessage<>("E1"));
executor.execute();
latch.await(1, TimeUnit.SECONDS);
assertThat(stateMachine.getState().getId(), is(stateS2.getId()));
}
private static class TestStateMachineExecutorTransit implements StateMachineExecutorTransit<String, String> {
ArrayList<Transition<String, String>> transitions = new ArrayList<>();