package com.sequenceiq.cloudbreak.core.flow2;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.ObjectStateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineConfigurationBuilder;
import org.springframework.statemachine.config.builders.StateMachineStateBuilder;
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
import com.sequenceiq.cloudbreak.cloud.event.Payload;
import com.sequenceiq.cloudbreak.cloud.event.Selectable;
import reactor.bus.EventBus;
public class AbstractActionTest {
public static final String FLOW_ID = "flowId";
@InjectMocks
private TestAction underTest;
@Mock
private EventBus eventBus;
@Mock
private FlowRegister runningFlows;
@Mock
private Flow flow;
private StateMachine<State, Event> stateMachine;
@Before
public void setup() throws Exception {
underTest = spy(new TestAction());
underTest.setFailureEvent(Event.FAILURE);
MockitoAnnotations.initMocks(this);
BDDMockito.given(flow.getFlowId()).willReturn(FLOW_ID);
BDDMockito.given(runningFlows.get(anyString())).willReturn(flow);
StateMachineConfigurationBuilder<State, Event> configurationBuilder =
new StateMachineConfigurationBuilder<>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true);
configurationBuilder.setTaskExecutor(new SyncTaskExecutor());
StateMachineStateBuilder<State, Event> stateBuilder =
new StateMachineStateBuilder<>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true);
stateBuilder.withStates().initial(State.INIT).state(State.DOING, underTest, null);
StateMachineTransitionBuilder<State, Event> transitionBuilder =
new StateMachineTransitionBuilder<>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true);
transitionBuilder.withExternal().source(State.INIT).target(State.DOING).event(Event.DOIT);
stateMachine = new ObjectStateMachineFactory<>(configurationBuilder.build(), transitionBuilder.build(), stateBuilder.build()).getStateMachine();
stateMachine.start();
}
@Test
public void testExecute() throws Exception {
stateMachine.sendEvent(new GenericMessage<>(Event.DOIT, Collections.singletonMap(Flow2Handler.FLOW_ID, FLOW_ID)));
verify(underTest, times(1)).createFlowContext(eq(FLOW_ID), any(StateContext.class), any(Payload.class));
verify(underTest, times(1)).doExecute(any(CommonContext.class), any(Payload.class), any(Map.class));
verify(underTest, times(0)).sendEvent(any(CommonContext.class));
verify(underTest, times(0)).sendEvent(anyString(), anyString(), any());
verify(underTest, times(0)).sendEvent(anyString(), any(Selectable.class));
verify(underTest, times(0)).getFailurePayload(any(Payload.class), any(Optional.class), any(RuntimeException.class));
}
@Test
public void testFailedExecute() throws Exception {
RuntimeException exception = new UnsupportedOperationException();
Mockito.doThrow(exception).when(underTest).doExecute(any(CommonContext.class), any(Payload.class), any(Map.class));
stateMachine.sendEvent(new GenericMessage<>(Event.DOIT, Collections.singletonMap(Flow2Handler.FLOW_ID, FLOW_ID)));
verify(underTest, times(1)).createFlowContext(eq(FLOW_ID), any(StateContext.class), any(Payload.class));
verify(underTest, times(1)).doExecute(any(CommonContext.class), any(Payload.class), any(Map.class));
verify(underTest, times(1)).getFailurePayload(any(Payload.class), any(Optional.class), eq(exception));
verify(underTest, times(1)).sendEvent(eq(FLOW_ID), eq(Event.FAILURE.name()), eq(Collections.emptyMap()));
}
enum State implements FlowState {
INIT, DOING;
@Override
public Class<? extends AbstractAction> action() {
return TestAction.class;
}
}
enum Event implements FlowEvent {
DOIT, FAILURE;
public String event() {
return name();
}
}
class TestAction extends AbstractAction<State, Event, CommonContext, Payload> {
protected TestAction() {
super(Payload.class);
}
@Override
public CommonContext createFlowContext(String flowId, StateContext<State, Event> stateContext, Payload payload) {
return new CommonContext(FLOW_ID);
}
@Override
public void doExecute(CommonContext context, Payload payload, Map<Object, Object> variables) throws Exception {
}
@Override
protected Selectable createRequest(CommonContext context) {
return null;
}
@Override
public Object getFailurePayload(Payload payload, Optional<CommonContext> flowContext, Exception ex) {
return Collections.emptyMap();
}
}
}