package io.vivarium.server.workloadmanagement;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.google.common.collect.Lists;
import com.johnuckele.vtest.Tester;
import io.vivarium.persistence.JobModel;
import io.vivarium.persistence.PersistenceModule;
import io.vivarium.persistence.WorkerModel;
import io.vivarium.test.FastTest;
import io.vivarium.test.UnitTest;
import io.vivarium.util.UUID;
public class WorkloadEnforcerTest
{
@Test
@Category({ FastTest.class, UnitTest.class })
public void testBuildDesiredJobAssingmentsWithInfiniteJobs() throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
// Build enforcer and get an accessible handle to the buildDesiredJobAssingments method.
WorkloadEnforcer enforcer = new WorkloadEnforcer(mock(PersistenceModule.class),
mock(JobAssignmentThreadFactory.class));
Method buildDesiredJobAssingments = WorkloadEnforcer.class.getDeclaredMethod("buildDesiredJobAssingments",
Collection.class, List.class);
buildDesiredJobAssingments.setAccessible(true);
// Mock a few workers and put them in a list
WorkerModel worker1 = mock(WorkerModel.class);
when(worker1.getThroughputs()).thenReturn(new long[] { 150, 250, 300, 340, 375, 405, 420 });
when(worker1.getWorkerID()).thenReturn(UUID.randomUUID());
WorkerModel worker2 = mock(WorkerModel.class);
when(worker2.getThroughputs()).thenReturn(new long[] { 500, 600, 750 });
when(worker2.getWorkerID()).thenReturn(UUID.randomUUID());
WorkerModel worker3 = mock(WorkerModel.class);
when(worker3.getThroughputs()).thenReturn(new long[] { 200, 220, 230, 240, 300 });
when(worker3.getWorkerID()).thenReturn(UUID.randomUUID());
Collection<WorkerModel> workers = Lists.newArrayList(worker1, worker2, worker3);
// Build a list of jobs
List<JobModel> jobs = new LinkedList<>();
for (int i = 0; i < 100; i++)
{
JobModel job = mock(JobModel.class);
when(job.getPriority()).thenReturn(1);
jobs.add(job);
}
// Build a job assignments model
JobAssignments jobAssignments = (JobAssignments) buildDesiredJobAssingments.invoke(enforcer, workers, jobs);
// The model should have a score that is the sum of the maximum throughputs of all workers (420 + 750 + 300 =
// 1470)
long score = jobAssignments.getScore();
Tester.equal("Total score should be the sum of the max values for each worker: ", score, 1470);
}
@Test
@Category({ FastTest.class, UnitTest.class })
public void testBuildDesiredJobAssingmentsWithLimitedHighPriorityJobs() throws NoSuchMethodException,
SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
// Build enforcer and get an accessible handle to the buildDesiredJobAssingments method.
WorkloadEnforcer enforcer = new WorkloadEnforcer(mock(PersistenceModule.class),
mock(JobAssignmentThreadFactory.class));
Method buildDesiredJobAssingments = WorkloadEnforcer.class.getDeclaredMethod("buildDesiredJobAssingments",
Collection.class, List.class);
buildDesiredJobAssingments.setAccessible(true);
// Mock a few workers and put them in a list
WorkerModel worker1 = mock(WorkerModel.class);
when(worker1.getThroughputs()).thenReturn(new long[] { 150, 250, 300, 340, 375, 405, 420 });
when(worker1.getWorkerID()).thenReturn(UUID.randomUUID());
WorkerModel worker2 = mock(WorkerModel.class);
when(worker2.getThroughputs()).thenReturn(new long[] { 500, 600, 750 });
when(worker2.getWorkerID()).thenReturn(UUID.randomUUID());
WorkerModel worker3 = mock(WorkerModel.class);
when(worker3.getThroughputs()).thenReturn(new long[] { 200, 220, 230, 240, 300 });
when(worker3.getWorkerID()).thenReturn(UUID.randomUUID());
Collection<WorkerModel> workers = Lists.newArrayList(worker1, worker2, worker3);
// Build a list of jobs, 3 priority 10 jobs and 3 priority 1 jobs
List<JobModel> jobs = new LinkedList<>();
for (int i = 0; i < 3; i++)
{
JobModel job = mock(JobModel.class);
when(job.getPriority()).thenReturn(10);
jobs.add(job);
}
for (int i = 0; i < 3; i++)
{
JobModel job = mock(JobModel.class);
when(job.getPriority()).thenReturn(1);
jobs.add(job);
}
// Build a job assignments model
JobAssignments jobAssignments = (JobAssignments) buildDesiredJobAssingments.invoke(enforcer, workers, jobs);
// The model should assign the priority 10 jobs in this order: worker2 (with a score of 5000), worker3 (with a
// score of 2000), and finally worker1 (with a score of 1500). There are still 3 unassigned jobs. Adding a
// priority 1 job to any of the workers would decrease the score though, so these should not get assigned.
long score = jobAssignments.getScore();
Tester.equal("Total score should be the sum of the firsts slot from each worker: ", score, 8500);
}
}