package com.sequenceiq.cloudbreak.service.stack.repair;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import com.sequenceiq.cloudbreak.api.model.Status;
import com.sequenceiq.cloudbreak.core.flow2.stack.FlowMessageService;
import com.sequenceiq.cloudbreak.core.flow2.stack.Msg;
import com.sequenceiq.cloudbreak.domain.Cluster;
import com.sequenceiq.cloudbreak.domain.HostGroup;
import com.sequenceiq.cloudbreak.domain.HostMetadata;
import com.sequenceiq.cloudbreak.domain.InstanceMetaData;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.repository.HostMetadataRepository;
import com.sequenceiq.cloudbreak.repository.InstanceMetaDataRepository;
@RunWith(MockitoJUnitRunner.class)
public class StackRepairServiceTest {
@Mock
private InstanceMetaDataRepository instanceMetaDataRepository;
@Mock
private HostMetadataRepository hostMetadataRepository;
@Mock
private ExecutorService executorService;
@Mock
private FlowMessageService flowMessageService;
@InjectMocks
private StackRepairService underTest;
private Stack stack;
private Cluster cluster;
@Before
public void setUp() {
stack = mock(Stack.class);
when(stack.getId()).thenReturn(1L);
cluster = mock(Cluster.class);
when(stack.getCluster()).thenReturn(cluster);
when(cluster.getId()).thenReturn(2L);
}
@Test
public void shouldIgnoreIfNoInstancesToRepair() {
underTest.add(stack, Collections.EMPTY_SET);
verifyZeroInteractions(executorService);
verify(flowMessageService).fireEventAndLog(stack.getId(), Msg.STACK_REPAIR_COMPLETE_CLEAN, Status.AVAILABLE.name());
}
@Test
public void shouldGroupUnhealthyInstancesByHostGroup() {
String instanceId1 = "i-0f1e0605506aaaaaa";
String instanceId2 = "i-0f1e0605506bbbbbb";
String instanceId3 = "i-0f1e0605506cccccc";
String privateIp1 = "ip-10-0-0-1.ec2.internal";
String privateIp2 = "ip-10-0-0-2.ec2.internal";
String privateIp3 = "ip-10-0-0-3.ec2.internal";
setupInstanceMetadata(stack.getId(), instanceId1, privateIp1);
setupInstanceMetadata(stack.getId(), instanceId2, privateIp2);
setupInstanceMetadata(stack.getId(), instanceId3, privateIp3);
String slaveGroup1 = "slave_group1";
String slaveGroup2 = "slave_group2";
setupHostMetadata(cluster.getId(), privateIp1, slaveGroup1);
setupHostMetadata(cluster.getId(), privateIp2, slaveGroup2);
setupHostMetadata(cluster.getId(), privateIp3, slaveGroup2);
Set<String> instanceIds = new HashSet<>();
instanceIds.add(instanceId1);
instanceIds.add(instanceId2);
instanceIds.add(instanceId3);
underTest.add(stack, instanceIds);
UnhealthyInstances expectedUnhealthyInstances = new UnhealthyInstances();
expectedUnhealthyInstances.addInstance(instanceId1, slaveGroup1);
expectedUnhealthyInstances.addInstance(instanceId2, slaveGroup2);
expectedUnhealthyInstances.addInstance(instanceId3, slaveGroup2);
verify(executorService).submit(argThat(new StackRepairFlowSubmitterMatcher(stack.getId(), expectedUnhealthyInstances)));
verify(flowMessageService).fireEventAndLog(stack.getId(), Msg.STACK_REPAIR_ATTEMPTING, Status.UPDATE_IN_PROGRESS.name());
}
private void setupHostMetadata(Long clusterId, String privateIp, String hostGroupName) {
HostMetadata hmd1 = mock(HostMetadata.class);
HostGroup hg1 = mock(HostGroup.class);
when(hg1.getName()).thenReturn(hostGroupName);
when(hmd1.getHostGroup()).thenReturn(hg1);
when(hostMetadataRepository.findHostInClusterByName(clusterId, privateIp)).thenReturn(hmd1);
}
private void setupInstanceMetadata(Long stackId, String instanceId, String privateIp) {
InstanceMetaData imd1 = mock(InstanceMetaData.class);
when(imd1.getDiscoveryFQDN()).thenReturn(privateIp);
when(instanceMetaDataRepository.findByInstanceId(stackId, instanceId)).thenReturn(imd1);
}
private class StackRepairFlowSubmitterMatcher extends ArgumentMatcher<StackRepairService.StackRepairFlowSubmitter> {
private final Long expectedStackId;
private final UnhealthyInstances expectedInstances;
StackRepairFlowSubmitterMatcher(Long expectedStackId, UnhealthyInstances expectedInstances) {
this.expectedStackId = expectedStackId;
this.expectedInstances = expectedInstances;
}
@Override
public boolean matches(Object argument) {
StackRepairService.StackRepairFlowSubmitter stackRepairFlowSubmitter = (StackRepairService.StackRepairFlowSubmitter) argument;
return stackRepairFlowSubmitter.getStackId().equals(expectedStackId) && expectedInstances.equals(stackRepairFlowSubmitter.getUnhealthyInstances());
}
}
}