package com.sequenceiq.cloudbreak.service.stack;
import static com.sequenceiq.cloudbreak.api.model.Status.AVAILABLE;
import static com.sequenceiq.cloudbreak.api.model.Status.START_FAILED;
import static com.sequenceiq.cloudbreak.api.model.Status.STOPPED;
import static com.sequenceiq.cloudbreak.api.model.Status.STOP_FAILED;
import static com.sequenceiq.cloudbreak.api.model.Status.STOP_IN_PROGRESS;
import static com.sequenceiq.cloudbreak.api.model.Status.STOP_REQUESTED;
import static com.sequenceiq.cloudbreak.api.model.Status.UPDATE_IN_PROGRESS;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import com.sequenceiq.cloudbreak.TestUtil;
import com.sequenceiq.cloudbreak.api.model.DetailedStackStatus;
import com.sequenceiq.cloudbreak.api.model.Status;
import com.sequenceiq.cloudbreak.api.model.StatusRequest;
import com.sequenceiq.cloudbreak.controller.BadRequestException;
import com.sequenceiq.cloudbreak.controller.validation.blueprint.BlueprintValidator;
import com.sequenceiq.cloudbreak.core.flow2.service.ReactorFlowManager;
import com.sequenceiq.cloudbreak.domain.Cluster;
import com.sequenceiq.cloudbreak.domain.Credential;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.domain.StackStatus;
import com.sequenceiq.cloudbreak.repository.ClusterRepository;
import com.sequenceiq.cloudbreak.repository.InstanceMetaDataRepository;
import com.sequenceiq.cloudbreak.repository.StackRepository;
import com.sequenceiq.cloudbreak.repository.StackUpdater;
import com.sequenceiq.cloudbreak.service.events.CloudbreakEventService;
import com.sequenceiq.cloudbreak.service.messages.CloudbreakMessagesService;
@RunWith(MockitoJUnitRunner.class)
public class DefaultStackHostServiceTypeTest {
@InjectMocks
private StackService underTest;
@Mock
private StackRepository stackRepository;
@Mock
private StackUpdater stackUpdater;
@Mock
private ClusterRepository clusterRepository;
@Mock
private InstanceMetaDataRepository instanceMetaDataRepository;
@Mock
private ReactorFlowManager flowManager;
@Mock
private BlueprintValidator blueprintValidator;
@Mock
private CloudbreakMessagesService cloudbreakMessagesService;
@Mock
private CloudbreakEventService eventService;
@Before
public void before() {
doNothing().when(flowManager).triggerStackStop(anyObject());
doNothing().when(flowManager).triggerStackStart(anyObject());
}
@Test
public void updateStatusTestStopWhenClusterStoppedThenStackStopTriggered() {
Stack stack = stack(AVAILABLE, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
verify(flowManager, times(1)).triggerStackStop(anyObject());
}
@Test
public void updateStatusTestStopWhenClusterInStopInProgressThenTriggeredStackStopRequested() {
Stack stack = stack(AVAILABLE, STOP_IN_PROGRESS);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
verify(eventService, times(1)).fireCloudbreakEvent(eq(1L), eq(STOP_REQUESTED.name()), anyString());
}
@Test
public void updateStatusTestStopWhenClusterInStoppedAndStackAvailableThenTriggerStackStop() {
Stack stack = stack(AVAILABLE, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
verify(flowManager, times(1)).triggerStackStop(anyObject());
}
@Test
public void updateStatusTestStopWhenClusterInStoppedAndStackStopFailedThenTriggerStackStop() {
Stack stack = stack(STOP_FAILED, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
verify(flowManager, times(1)).triggerStackStop(anyObject());
}
@Test(expected = BadRequestException.class)
public void updateStatusTestStopWhenClusterInStoppedAndStackUpdateInProgressThenBadRequestExceptionDropping() {
Stack stack = stack(UPDATE_IN_PROGRESS, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
verify(flowManager, times(1)).triggerStackStop(anyObject());
}
@Test(expected = BadRequestException.class)
public void updateStatusTestStopWhenClusterAndStackAvailableThenBadRequestExceptionDropping() {
Stack stack = stack(AVAILABLE, AVAILABLE);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
}
@Test
public void updateStatusTestStartWhenStackStoppedThenStackStartTriggered() {
Stack stack = stack(STOPPED, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STARTED);
verify(flowManager, times(1)).triggerStackStart(anyObject());
}
@Test(expected = BadRequestException.class)
public void updateStatusTestStartWhenClusterInStoppedAndStackStopFailedThenBadRequestExceptionDropping() {
Stack stack = stack(UPDATE_IN_PROGRESS, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STARTED);
}
@Test
public void updateStatusTestStartWhenClusterInStoppedAndStackStartFailedThenTriggerStackStart() {
Stack stack = stack(START_FAILED, STOPPED);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STARTED);
verify(flowManager, times(1)).triggerStackStart(anyObject());
}
@Test(expected = BadRequestException.class)
public void updateStatusTestStartWhenClusterAndStackUpdateInProgressThenBadRequestExceptionDropping() {
Stack stack = stack(UPDATE_IN_PROGRESS, UPDATE_IN_PROGRESS);
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STARTED);
}
@Test(expected = BadRequestException.class)
public void updateStatusTestStopWhenClusterAndStackAvailableAndEphemeralThenBadRequestExceptionDropping() {
Stack stack = TestUtil.setEphemeral(TestUtil.stack(AVAILABLE, TestUtil.awsCredential()));
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
}
@Test(expected = BadRequestException.class)
public void updateStatusTestStopWhenClusterAndStackAvailableAndSpotInstancesThenBadRequestExceptionDropping() {
Stack stack = TestUtil.setSpotInstances(TestUtil.stack(AVAILABLE, TestUtil.awsCredential()));
given(stackRepository.findOneWithLists(anyLong())).willReturn(stack);
given(clusterRepository.findOneWithLists(anyLong())).willReturn(stack.getCluster());
given(stackUpdater.updateStackStatus(anyLong(), any(DetailedStackStatus.class))).willReturn(stack);
underTest.updateStatus(1L, StatusRequest.STOPPED);
}
private Stack stack(Status stackStatus, Status clusterStatus) {
Credential gcpCredential = new Credential();
Stack stack = new Stack();
stack.setStackStatus(new StackStatus(stack, stackStatus, "", DetailedStackStatus.UNKNOWN));
stack.setCredential(gcpCredential);
stack.setId(1L);
Cluster cluster = new Cluster();
cluster.setStatus(clusterStatus);
cluster.setId(1L);
stack.setCluster(cluster);
return stack;
}
}