package com.sequenceiq.cloudbreak.orchestrator.salt.poller;
import static org.hamcrest.Matchers.both;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.sequenceiq.cloudbreak.orchestrator.exception.CloudbreakOrchestratorFailedException;
import com.sequenceiq.cloudbreak.orchestrator.salt.client.SaltConnector;
import com.sequenceiq.cloudbreak.orchestrator.salt.client.target.Target;
import com.sequenceiq.cloudbreak.orchestrator.salt.domain.JobId;
import com.sequenceiq.cloudbreak.orchestrator.salt.domain.JobState;
import com.sequenceiq.cloudbreak.orchestrator.salt.states.SaltStates;
@RunWith(PowerMockRunner.class)
@PrepareForTest(SaltStates.class)
public class SaltJobIdTrackerTest {
@Captor
private ArgumentCaptor<Target<String>> targetCaptor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void callWithNotStarted() throws Exception {
String jobId = "1";
SaltConnector saltConnector = Mockito.mock(SaltConnector.class);
SaltJobRunner saltJobRunner = Mockito.mock(SaltJobRunner.class);
PowerMockito.mockStatic(SaltStates.class);
PowerMockito.when(SaltStates.jobIsRunning(any(), any())).thenReturn(true);
Set<String> targets = new HashSet<>();
targets.add("10.0.0.1");
targets.add("10.0.0.2");
targets.add("10.0.0.3");
when(saltJobRunner.getTarget()).thenReturn(targets);
when(saltJobRunner.getJid()).thenReturn(JobId.jobId(jobId));
when(saltJobRunner.getJobState()).thenReturn(JobState.NOT_STARTED, JobState.IN_PROGRESS);
when(saltJobRunner.submit(any(SaltConnector.class))).thenReturn(jobId);
SaltJobIdTracker saltJobIdTracker = new SaltJobIdTracker(saltConnector, saltJobRunner);
try {
saltJobIdTracker.call();
fail("should throw exception");
} catch (CloudbreakOrchestratorFailedException e) {
assertThat(e.getMessage(), both(containsString("jobId='" + jobId + "'")).and(containsString("is running")));
}
PowerMockito.verifyStatic();
SaltStates.jobIsRunning(any(), eq(jobId));
checkTargets(targets, targetCaptor.getAllValues());
verify(saltJobRunner, times(2)).getJobState();
}
@Test
public void callWithFailed() throws Exception {
String jobId = "1";
SaltConnector saltConnector = Mockito.mock(SaltConnector.class);
PowerMockito.mockStatic(SaltStates.class);
PowerMockito.when(SaltStates.jobIsRunning(any(), any())).thenReturn(true);
SaltJobRunner saltJobRunner = Mockito.mock(BaseSaltJobRunner.class);
when(saltJobRunner.getJid()).thenReturn(JobId.jobId(jobId));
when(saltJobRunner.getJobState()).thenCallRealMethod();
doCallRealMethod().when(saltJobRunner).setJobState(any());
when(saltJobRunner.submit(any(SaltConnector.class))).thenReturn(jobId);
saltJobRunner.setJobState(JobState.FAILED);
SaltJobIdTracker saltJobIdTracker = new SaltJobIdTracker(saltConnector, saltJobRunner);
try {
saltJobIdTracker.call();
fail("should throw exception");
} catch (CloudbreakOrchestratorFailedException e) {
assertThat(e.getMessage(), both(containsString("jobId='" + jobId + "'")).and(containsString("is running")));
}
PowerMockito.verifyStatic();
SaltStates.jobIsRunning(any(), eq(jobId));
}
private void checkTargets(Set<String> targets, List<Target<String>> allValues) {
for (Target<String> allValue : allValues) {
for (String target : targets) {
assertThat(allValue.getTarget(), containsString(target));
}
}
}
@Test
public void callWithInProgressAndJobIsRunning() throws Exception {
String jobId = "1";
SaltConnector saltConnector = Mockito.mock(SaltConnector.class);
SaltJobRunner saltJobRunner = Mockito.mock(BaseSaltJobRunner.class);
when(saltJobRunner.getJid()).thenReturn(JobId.jobId(jobId));
when(saltJobRunner.getJobState()).thenCallRealMethod();
doCallRealMethod().when(saltJobRunner).setJobState(any());
when(saltJobRunner.submit(any(SaltConnector.class))).thenReturn(jobId);
saltJobRunner.setJobState(JobState.IN_PROGRESS);
Set<String> targets = new HashSet<>();
targets.add("10.0.0.1");
targets.add("10.0.0.2");
targets.add("10.0.0.3");
when(saltJobRunner.getTarget()).thenReturn(targets);
PowerMockito.mockStatic(SaltStates.class);
PowerMockito.when(SaltStates.jobIsRunning(any(), any())).thenReturn(true);
SaltJobIdTracker saltJobIdTracker = new SaltJobIdTracker(saltConnector, saltJobRunner);
try {
saltJobIdTracker.call();
} catch (CloudbreakOrchestratorFailedException e) {
assertThat(e.getMessage(), both(containsString("jobId='" + jobId + "'")).and(containsString("is running")));
}
PowerMockito.verifyStatic();
SaltStates.jobIsRunning(any(), eq(jobId));
checkTargets(targets, targetCaptor.getAllValues());
}
@Test
public void callWithInProgressAndJobIsFinished() throws Exception {
String jobId = "1";
SaltConnector saltConnector = Mockito.mock(SaltConnector.class);
SaltJobRunner saltJobRunner = Mockito.mock(BaseSaltJobRunner.class);
when(saltJobRunner.getJid()).thenReturn(JobId.jobId(jobId));
when(saltJobRunner.getJobState()).thenCallRealMethod();
doCallRealMethod().when(saltJobRunner).setJobState(any());
when(saltJobRunner.submit(any(SaltConnector.class))).thenReturn(jobId);
saltJobRunner.setJobState(JobState.IN_PROGRESS);
Set<String> targets = new HashSet<>();
targets.add("10.0.0.1");
targets.add("10.0.0.2");
targets.add("10.0.0.3");
when(saltJobRunner.getTarget()).thenReturn(targets);
PowerMockito.mockStatic(SaltStates.class);
PowerMockito.when(SaltStates.jobIsRunning(any(), any())).thenReturn(false);
Multimap<String, String> missingNodesWithReason = ArrayListMultimap.create();
PowerMockito.when(SaltStates.jidInfo(any(), any(), any(), any())).thenReturn(missingNodesWithReason);
SaltJobIdTracker saltJobIdTracker = new SaltJobIdTracker(saltConnector, saltJobRunner);
assertTrue(saltJobIdTracker.call());
assertEquals(JobState.FINISHED, saltJobRunner.getJobState());
PowerMockito.verifyStatic();
SaltStates.jobIsRunning(any(), eq(jobId));
checkTargets(targets, targetCaptor.getAllValues());
}
@Test
public void callWithInProgressAndMissingNodes() throws Exception {
String jobId = "1";
SaltConnector saltConnector = Mockito.mock(SaltConnector.class);
SaltJobRunner saltJobRunner = Mockito.mock(BaseSaltJobRunner.class);
when(saltJobRunner.getJid()).thenReturn(JobId.jobId(jobId));
when(saltJobRunner.getJobState()).thenCallRealMethod();
doCallRealMethod().when(saltJobRunner).setJobState(any());
when(saltJobRunner.submit(any(SaltConnector.class))).thenReturn(jobId);
saltJobRunner.setJobState(JobState.IN_PROGRESS);
Set<String> targets = new HashSet<>();
targets.add("10.0.0.1");
targets.add("10.0.0.2");
targets.add("10.0.0.3");
when(saltJobRunner.getTarget()).thenReturn(targets);
PowerMockito.mockStatic(SaltStates.class);
PowerMockito.when(SaltStates.jobIsRunning(any(), any())).thenReturn(false);
Multimap<String, String> missingNodesWithReason = ArrayListMultimap.create();
String missingMachine = "10.0.0.1";
String errorMessage = "error happened";
missingNodesWithReason.put(missingMachine, errorMessage);
when(saltJobRunner.getNodesWithError()).thenReturn(missingNodesWithReason);
SaltJobIdTracker saltJobIdTracker = new SaltJobIdTracker(saltConnector, saltJobRunner);
try {
saltJobIdTracker.call();
fail("should throw exception");
} catch (CloudbreakOrchestratorFailedException e) {
assertThat(e.getMessage(), both(containsString(missingMachine)).and(containsString(errorMessage)));
}
PowerMockito.verifyStatic();
SaltStates.jobIsRunning(any(), eq(jobId));
checkTargets(targets, targetCaptor.getAllValues());
}
}