package org.apache.mesos.hbase; import com.google.common.collect.Lists; import org.apache.hadoop.conf.Configuration; import org.apache.mesos.Protos; import org.apache.mesos.SchedulerDriver; import org.apache.mesos.hbase.scheduler.HBaseScheduler; import org.apache.mesos.hbase.state.AcquisitionPhase; import org.apache.mesos.hbase.state.LiveState; import org.apache.mesos.hbase.state.IPersistentStateStore; import org.apache.mesos.hbase.util.DnsResolver; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.HashMap; import org.apache.mesos.hbase.config.HBaseFrameworkConfig; import org.apache.mesos.hbase.util.HBaseConstants; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; @SuppressWarnings("unchecked") public class TestScheduler { private final HBaseFrameworkConfig hdfsFrameworkConfig = new HBaseFrameworkConfig( new Configuration()); @Mock SchedulerDriver driver; @Mock IPersistentStateStore persistenceStore; @Mock LiveState liveState; @Mock DnsResolver dnsResolver; @Captor ArgumentCaptor<Collection<Protos.TaskInfo>> taskInfosCapture; HBaseScheduler scheduler; @Test public void statusUpdateWasStagingNowRunning() { when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.START_MASTER_NODES); Protos.TaskID taskId = createTaskId("1"); scheduler.statusUpdate(driver, createTaskStatus(taskId, Protos.TaskState.TASK_RUNNING)); verify(liveState).removeStagingTask(taskId); } @Test public void statusUpdateTransitionFromStartingPrimaryNodesToSlaveNodes() { Protos.TaskID taskId = createTaskId(HBaseConstants.MASTER_NODE_TASKID + "1"); Protos.SlaveID slaveId = createSlaveId("1"); when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.START_MASTER_NODES); when(liveState.getMasterNodeSize()).thenReturn(2); scheduler.statusUpdate(driver, createTaskStatus(taskId, Protos.TaskState.TASK_RUNNING)); verify(liveState).transitionTo(AcquisitionPhase.SLAVE_NODES); } @Test public void statusUpdateAquiringDataNodesJustStays() { Protos.TaskID taskId = createTaskId("1"); when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.SLAVE_NODES); scheduler.statusUpdate(driver, createTaskStatus(taskId, Protos.TaskState.TASK_RUNNING)); verify(liveState, never()).transitionTo(any(AcquisitionPhase.class)); } @Test public void launchesMasterNodeWhenInMasternode1Phase() { when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.START_MASTER_NODES); when(persistenceStore.getPrimaryNodeTaskNames()).thenReturn(new HashMap<String, String>()); scheduler.resourceOffers(driver, Lists.newArrayList(createTestOffer(0))); verify(driver, times(1)).launchTasks(anyList(), taskInfosCapture.capture()); assertTrue(taskInfosCapture.getValue().size() == 1); Iterator<Protos.TaskInfo> taskInfoIterator = taskInfosCapture.getValue().iterator(); String firstTask = taskInfoIterator.next().getName(); } @Test public void declinesAnyOffersPastWhatItNeeds() { when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.SLAVE_NODES); scheduler.resourceOffers(driver, Lists.newArrayList( createTestOffer(0), createTestOffer(1), createTestOffer(2), createTestOffer(3) )); verify(driver, times(3)).declineOffer(any(Protos.OfferID.class)); } @Test public void launchesDataNodesWhenInDatanodesPhase() { when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.SLAVE_NODES); scheduler.resourceOffers(driver, Lists.newArrayList( createTestOffer(0) ) ); verify(driver, times(1)).launchTasks(anyList(), taskInfosCapture.capture()); Protos.TaskInfo taskInfo = taskInfosCapture.getValue().iterator().next(); assertTrue(taskInfo.getName().contains(HBaseConstants.SLAVE_NODE_ID)); } @Test public void removesTerminalTasksFromLiveState() { when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.SLAVE_NODES); scheduler.statusUpdate(driver, createTaskStatus(createTaskId("0"), Protos.TaskState.TASK_FAILED)); scheduler.statusUpdate(driver, createTaskStatus(createTaskId("1"), Protos.TaskState.TASK_FINISHED)); scheduler.statusUpdate(driver, createTaskStatus(createTaskId("2"), Protos.TaskState.TASK_KILLED)); scheduler.statusUpdate(driver, createTaskStatus(createTaskId("3"), Protos.TaskState.TASK_LOST)); verify(liveState, times(4)).removeStagingTask(any(Protos.TaskID.class)); verify(liveState, times(4)).removeRunningTask(any(Protos.TaskID.class)); } @Test public void declinesOffersWithNotEnoughResources() { when(liveState.getCurrentAcquisitionPhase()).thenReturn(AcquisitionPhase.SLAVE_NODES); Protos.Offer offer = createTestOfferWithResources(0, 0.1, 64); scheduler.resourceOffers(driver, Lists.newArrayList(offer)); verify(driver, times(1)).declineOffer(offer.getId()); } @Before public void setup() { MockitoAnnotations.initMocks(this); this.scheduler = new HBaseScheduler(hdfsFrameworkConfig, liveState, persistenceStore); } private Protos.TaskID createTaskId(String id) { return Protos.TaskID.newBuilder().setValue(id).build(); } private Protos.OfferID createTestOfferId(int instanceNumber) { return Protos.OfferID.newBuilder().setValue("offer" + instanceNumber).build(); } private Protos.SlaveID createSlaveId(String slaveId) { return Protos.SlaveID.newBuilder().setValue(slaveId).build(); } private Protos.ExecutorID createExecutorId(String executorId) { return Protos.ExecutorID.newBuilder().setValue(executorId).build(); } private Protos.Offer createTestOffer(int instanceNumber) { return Protos.Offer.newBuilder() .setId(createTestOfferId(instanceNumber)) .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("framework1").build()) .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave" + instanceNumber).build()) .setHostname("host" + instanceNumber) .build(); } private Protos.Offer createTestOfferWithResources(int instanceNumber, double cpus, int mem) { return Protos.Offer.newBuilder() .setId(createTestOfferId(instanceNumber)) .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("framework1").build()) .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave" + instanceNumber).build()) .setHostname("host" + instanceNumber) .addAllResources(Arrays.asList( Protos.Resource.newBuilder() .setName("cpus") .setType(Protos.Value.Type.SCALAR) .setScalar(Protos.Value.Scalar.newBuilder() .setValue(cpus).build()) .setRole("*") .build(), Protos.Resource.newBuilder() .setName("mem") .setType(Protos.Value.Type.SCALAR) .setScalar(Protos.Value.Scalar.newBuilder() .setValue(mem).build()) .setRole("*") .build())) .build(); } private Protos.TaskStatus createTaskStatus(Protos.TaskID taskID, Protos.TaskState state) { return Protos.TaskStatus.newBuilder() .setTaskId(taskID) .setState(state) .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave").build()) .setMessage("From Test") .build(); } }