package com.sequenceiq.cloudbreak.orchestrator.salt.states; import static com.sequenceiq.cloudbreak.orchestrator.salt.client.SaltClientType.LOCAL; import static com.sequenceiq.cloudbreak.orchestrator.salt.client.SaltClientType.LOCAL_ASYNC; import static com.sequenceiq.cloudbreak.orchestrator.salt.client.SaltClientType.RUNNER; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.runners.MockitoJUnitRunner; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Multimap; import com.sequenceiq.cloudbreak.orchestrator.salt.client.SaltActionType; import com.sequenceiq.cloudbreak.orchestrator.salt.client.SaltConnector; import com.sequenceiq.cloudbreak.orchestrator.salt.client.target.Compound; import com.sequenceiq.cloudbreak.orchestrator.salt.client.target.Glob; import com.sequenceiq.cloudbreak.orchestrator.salt.client.target.Target; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.ApplyResponse; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.Minion; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.NetworkInterfaceResponse; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.PingResponse; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.RunningJobsResponse; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.SaltAction; import com.sequenceiq.cloudbreak.orchestrator.salt.domain.StateType; @RunWith(MockitoJUnitRunner.class) public class SaltStatesTest { private SaltConnector saltConnector; private Target<String> target; @Captor private ArgumentCaptor<Set<String>> minionIdsCaptor; @Before public void setUp() { Set<String> targets = new HashSet<>(); targets.add("10-0-0-1.example.com"); targets.add("10-0-0-2.example.com"); targets.add("10-0-0-3.example.com"); target = new Compound(targets); saltConnector = mock(SaltConnector.class); } @Test public void addRoleTest() { String role = "ambari-server"; SaltStates.addGrain(saltConnector, target, "roles", role); verify(saltConnector, times(1)).run(eq(target), eq("grains.append"), eq(LOCAL), eq(ApplyResponse.class), eq("roles"), eq(role)); } @Test public void syncGrainsTest() { SaltStates.syncGrains(saltConnector); verify(saltConnector, times(1)).run(eq(Glob.ALL), eq("saltutil.sync_grains"), eq(LOCAL), eq(ApplyResponse.class)); } @Test public void highstateTest() { String jobId = "1"; ApplyResponse response = new ApplyResponse(); List<Map<String, Object>> result = new ArrayList<>(); Map<String, Object> resultMap = new HashMap<>(); resultMap.put("jid", jobId); result.add(resultMap); response.setResult(result); when(saltConnector.run(any(), eq("state.highstate"), any(), eq(ApplyResponse.class))).thenReturn(response); String jid = SaltStates.highstate(saltConnector); assertEquals(jobId, jid); verify(saltConnector, times(1)).run(eq(Glob.ALL), eq("state.highstate"), eq(LOCAL_ASYNC), eq(ApplyResponse.class)); } @Test public void jidInfoHighTest() throws Exception { String jobId = "2"; InputStream responseStream = SaltStatesTest.class.getResourceAsStream("/jid_response.json"); String response = IOUtils.toString(responseStream); Map responseMap = new ObjectMapper().readValue(response, Map.class); when(saltConnector.run(eq("jobs.lookup_jid"), any(), any(), eq("jid"), any())).thenReturn(responseMap); Multimap<String, String> jidInfo = SaltStates.jidInfo(saltConnector, jobId, target, StateType.HIGH); verify(saltConnector, times(1)).run("jobs.lookup_jid", RUNNER, Map.class, "jid", jobId); assertThat(jidInfo.keySet(), hasSize(1)); assertThat(jidInfo.entries(), hasSize(3)); String hostName = jidInfo.keySet().iterator().next(); Collection<String> hostErrors = jidInfo.get(hostName); assertThat(hostErrors, containsInAnyOrder("Source file salt://ambari/scripts/ambari-server-initttt.sh not found", "Service ambari-server is already enabled, and is dead", "Package haveged is already installed.")); } @Test public void jidInfoSimpleTest() throws Exception { String jobId = "2"; InputStream responseStream = SaltStatesTest.class.getResourceAsStream("/jid_simple_response.json"); String response = IOUtils.toString(responseStream); Map responseMap = new ObjectMapper().readValue(response, Map.class); when(saltConnector.run(eq("jobs.lookup_jid"), any(), any(), eq("jid"), any())).thenReturn(responseMap); Multimap<String, String> jidInfo = SaltStates.jidInfo(saltConnector, jobId, target, StateType.SIMPLE); verify(saltConnector, times(1)).run("jobs.lookup_jid", RUNNER, Map.class, "jid", jobId); assertThat(jidInfo.keySet(), hasSize(1)); assertThat(jidInfo.entries(), hasSize(3)); String hostName = jidInfo.keySet().iterator().next(); Collection<String> hostErrors = jidInfo.get(hostName); assertThat(hostErrors, containsInAnyOrder("Source file salt://ambari/scripts/ambari-server-initttt.sh not found", "Service ambari-server is already enabled, and is dead", "Package haveged is already installed.")); } @Test public void jobIsRunningTest() { String jid = "3"; RunningJobsResponse runningJobsResponse = new RunningJobsResponse(); List<Map<String, Map<String, Object>>> result = new ArrayList<>(); Map<String, Map<String, Object>> resultMap = new HashMap<>(); resultMap.put(jid, new HashMap<>()); result.add(resultMap); runningJobsResponse.setResult(result); when(saltConnector.run(eq("jobs.active"), any(), eq(RunningJobsResponse.class))).thenReturn(runningJobsResponse); boolean running = SaltStates.jobIsRunning(saltConnector, jid); assertEquals(true, running); resultMap.clear(); running = SaltStates.jobIsRunning(saltConnector, jid); assertEquals(false, running); } @Test public void networkInterfaceIPTest() { SaltStates.networkInterfaceIP(saltConnector, target); verify(saltConnector, times(1)).run(any(), eq("network.interface_ip"), eq(LOCAL), eq(NetworkInterfaceResponse.class), eq("eth0")); } @Test public void pingTest() { SaltStates.ping(saltConnector, target); verify(saltConnector, times(1)).run(any(), eq("test.ping"), eq(LOCAL), eq(PingResponse.class)); } @Test public void stopMinionsTest() { Map<String, String> privateIpsByFQDN = new HashMap<>(); privateIpsByFQDN.put("10-0-0-1.example.com", "10.0.0.1"); privateIpsByFQDN.put("10-0-0-2.example.com", "10.0.0.2"); privateIpsByFQDN.put("10-0-0-3.example.com", "10.0.0.3"); SaltStates.stopMinions(saltConnector, privateIpsByFQDN); ArgumentCaptor<SaltAction> saltActionArgumentCaptor = ArgumentCaptor.forClass(SaltAction.class); verify(saltConnector, times(1)).action(saltActionArgumentCaptor.capture()); SaltAction saltAction = saltActionArgumentCaptor.getValue(); assertEquals(SaltActionType.STOP, saltAction.getAction()); assertThat(saltAction.getMinions(), hasSize(3)); Set<String> minionAddresses = saltAction.getMinions().stream().map(Minion::getAddress).collect(Collectors.toSet()); assertThat(minionAddresses, containsInAnyOrder("10.0.0.1", "10.0.0.2", "10.0.0.3")); } }