package com.sequenceiq.cloudbreak.core.flow2;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.sequenceiq.cloudbreak.cloud.event.Payload;
import com.sequenceiq.cloudbreak.core.flow2.chain.FlowChains;
import com.sequenceiq.cloudbreak.core.flow2.config.FlowConfiguration;
import com.sequenceiq.cloudbreak.repository.FlowLogRepository;
import com.sequenceiq.cloudbreak.service.flowlog.FlowLogService;
import reactor.bus.Event;
public class Flow2HandlerTest {
public static final String FLOW_ID = "flowId";
public static final String FLOW_CHAIN_ID = "flowChainId";
@InjectMocks
private Flow2Handler underTest;
@Mock
private FlowLogService flowLogService;
@Mock
private FlowLogRepository flowLogRepository;
@Mock
private Map<String, FlowConfiguration<?>> flowConfigurationMap;
@Mock
private FlowRegister runningFlows;
@Mock
private FlowConfiguration flowConfig;
@Mock
private FlowChains flowChains;
@Mock
private FlowTriggerCondition flowTriggerCondition;
@Mock
private Flow flow;
private FlowState flowState;
private Event<? extends Payload> dummyEvent;
private Payload payload = () -> 1L;
@Before
public void setUp() {
underTest = new Flow2Handler();
MockitoAnnotations.initMocks(this);
Map<String, Object> headers = new HashMap<>();
headers.put(Flow2Handler.FLOW_ID, FLOW_ID);
dummyEvent = new Event<>(new Event.Headers(headers), payload);
flowState = new OwnFlowState();
}
@Test
public void testNewFlow() {
BDDMockito.<FlowConfiguration>given(flowConfigurationMap.get(any())).willReturn(flowConfig);
given(flowConfig.createFlow(anyString())).willReturn(flow);
given(flowConfig.getFlowTriggerCondition()).willReturn(flowTriggerCondition);
given(flowTriggerCondition.isFlowTriggerable(anyLong())).willReturn(true);
given(flow.getCurrentState()).willReturn(flowState);
Event<Payload> event = new Event<>(payload);
event.setKey("KEY");
underTest.accept(event);
verify(flowConfigurationMap, times(1)).get(anyString());
verify(runningFlows, times(1)).put(eq(flow), isNull(String.class));
verify(flowLogService, times(1)).save(anyString(), anyString(), eq("KEY"), any(Payload.class), anyMap(), eq(flowConfig.getClass()), eq(flowState));
verify(flow, times(1)).sendEvent(anyString(), any());
}
@Test
public void testNewFlowButNotHandled() {
Event<Payload> event = new Event<>(payload);
event.setKey("KEY");
underTest.accept(event);
verify(flowConfigurationMap, times(1)).get(anyString());
verify(runningFlows, times(0)).put(any(Flow.class), isNull(String.class));
verify(flowLogService, times(0)).save(anyString(), anyString(), anyString(), any(Payload.class), anyMap(), Matchers.<Class>any(), any(FlowState.class));
}
@Test
public void testExistingFlow() {
BDDMockito.<FlowConfiguration>given(flowConfigurationMap.get(any())).willReturn(flowConfig);
given(runningFlows.get(anyString())).willReturn(flow);
given(flow.getCurrentState()).willReturn(flowState);
dummyEvent.setKey("KEY");
underTest.accept(dummyEvent);
verify(flowLogService, times(1)).save(eq(FLOW_ID), anyString(), eq("KEY"), any(Payload.class), anyMap(), any(Class.class), eq(flowState));
verify(flow, times(1)).sendEvent(eq("KEY"), any());
}
@Test
public void testExistingFlowNotFound() {
BDDMockito.<FlowConfiguration>given(flowConfigurationMap.get(any())).willReturn(flowConfig);
dummyEvent.setKey("KEY");
underTest.accept(dummyEvent);
verify(flowLogService, times(0)).save(anyString(), anyString(), anyString(), any(Payload.class), anyMap(), Matchers.<Class>any(), any(FlowState.class));
verify(flow, times(0)).sendEvent(anyString(), any());
}
@Test
public void testFlowFinalFlowNotChained() {
given(runningFlows.remove(FLOW_ID)).willReturn(flow);
dummyEvent.setKey(Flow2Handler.FLOW_FINAL);
underTest.accept(dummyEvent);
verify(flowLogService, times(1)).close(anyLong(), eq(FLOW_ID));
verify(runningFlows, times(1)).remove(eq(FLOW_ID));
verify(runningFlows, times(0)).get(eq(FLOW_ID));
verify(runningFlows, times(0)).put(any(Flow.class), isNull(String.class));
verify(flowChains, times(0)).removeFlowChain(anyString());
verify(flowChains, times(0)).triggerNextFlow(anyString());
}
@Test
public void testFlowFinalFlowChained() {
given(runningFlows.remove(FLOW_ID)).willReturn(flow);
dummyEvent.setKey(Flow2Handler.FLOW_FINAL);
dummyEvent.getHeaders().set(Flow2Handler.FLOW_CHAIN_ID, FLOW_CHAIN_ID);
underTest.accept(dummyEvent);
verify(flowLogService, times(1)).close(anyLong(), eq(FLOW_ID));
verify(runningFlows, times(1)).remove(eq(FLOW_ID));
verify(runningFlows, times(0)).get(eq(FLOW_ID));
verify(runningFlows, times(0)).put(any(Flow.class), isNull(String.class));
verify(flowChains, times(0)).removeFlowChain(anyString());
verify(flowChains, times(1)).triggerNextFlow(eq(FLOW_CHAIN_ID));
}
@Test
public void testFlowFinalFlowFailedNoChain() {
given(flow.isFlowFailed()).willReturn(Boolean.TRUE);
given(runningFlows.remove(FLOW_ID)).willReturn(flow);
dummyEvent.setKey(Flow2Handler.FLOW_FINAL);
given(runningFlows.remove(anyString())).willReturn(flow);
underTest.accept(dummyEvent);
verify(flowLogService, times(1)).close(anyLong(), eq(FLOW_ID));
verify(runningFlows, times(1)).remove(eq(FLOW_ID));
verify(runningFlows, times(0)).get(eq(FLOW_ID));
verify(runningFlows, times(0)).put(any(Flow.class), isNull(String.class));
verify(flowChains, times(0)).removeFullFlowChain(anyString());
verify(flowChains, times(0)).triggerNextFlow(anyString());
}
@Test
public void testFlowFinalFlowFailedWithChain() {
given(flow.isFlowFailed()).willReturn(Boolean.TRUE);
given(runningFlows.remove(FLOW_ID)).willReturn(flow);
dummyEvent.setKey(Flow2Handler.FLOW_FINAL);
dummyEvent.getHeaders().set(Flow2Handler.FLOW_CHAIN_ID, "FLOW_CHAIN_ID");
given(runningFlows.remove(anyString())).willReturn(flow);
underTest.accept(dummyEvent);
verify(flowLogService, times(1)).close(anyLong(), eq(FLOW_ID));
verify(runningFlows, times(1)).remove(eq(FLOW_ID));
verify(runningFlows, times(0)).get(eq(FLOW_ID));
verify(runningFlows, times(0)).put(any(Flow.class), isNull(String.class));
verify(flowChains, times(1)).removeFullFlowChain(anyString());
verify(flowChains, times(0)).triggerNextFlow(anyString());
}
@Test
public void testCancelRunningFlows() {
given(flowLogRepository.findAllRunningNonTerminationFlowIdsByStackId(anyLong())).willReturn(Collections.singleton(FLOW_ID));
given(runningFlows.remove(FLOW_ID)).willReturn(flow);
given(runningFlows.getFlowChainId(eq(FLOW_ID))).willReturn(FLOW_CHAIN_ID);
dummyEvent.setKey(Flow2Handler.FLOW_CANCEL);
underTest.accept(dummyEvent);
verify(flowLogService, times(1)).cancel(anyLong(), eq(FLOW_ID));
verify(flowChains, times(1)).removeFullFlowChain(eq(FLOW_CHAIN_ID));
}
private static class OwnFlowState implements FlowState {
@Override
public Class<? extends AbstractAction> action() {
return null;
}
@Override
public String name() {
return null;
}
}
}