/*
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.fenzo;
import com.netflix.fenzo.functions.Action1;
import com.netflix.fenzo.functions.Func1;
import com.netflix.fenzo.plugins.BalancedHostAttrConstraint;
import com.netflix.fenzo.plugins.BinPackingFitnessCalculators;
import com.netflix.fenzo.plugins.ExclusiveHostConstraint;
import com.netflix.fenzo.plugins.HostAttrValueConstraint;
import com.netflix.fenzo.plugins.UniqueHostAttrConstraint;
import org.junit.Assert;
import org.apache.mesos.Protos;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
public class ConstraintsTests {
private final static String zoneAttrName="Zone";
private final int numZones=3;
Map<String, Protos.Attribute> attributesA = new HashMap<>();
Map<String, Protos.Attribute> attributesB = new HashMap<>();
Map<String, Protos.Attribute> attributesC = new HashMap<>();
@Before
public void setUp() throws Exception {
Protos.Attribute attributeA = Protos.Attribute.newBuilder().setName(zoneAttrName)
.setType(Protos.Value.Type.TEXT)
.setText(Protos.Value.Text.newBuilder().setValue("zoneA")).build();
attributesA.put(zoneAttrName, attributeA);
Protos.Attribute attributeB = Protos.Attribute.newBuilder().setName(zoneAttrName)
.setType(Protos.Value.Type.TEXT)
.setText(Protos.Value.Text.newBuilder().setValue("zoneB")).build();
attributesB.put(zoneAttrName, attributeB);
Protos.Attribute attributeC = Protos.Attribute.newBuilder().setName(zoneAttrName)
.setType(Protos.Value.Type.TEXT)
.setText(Protos.Value.Text.newBuilder().setValue("zoneC")).build();
attributesC.put(zoneAttrName, attributeC);
}
private TaskScheduler getTaskScheduler() {
return getTaskScheduler(true);
}
private TaskScheduler getTaskScheduler(boolean useBinPacking) {
TaskScheduler.Builder builder = new TaskScheduler.Builder()
.withLeaseOfferExpirySecs(1000000)
.withLeaseRejectAction(new Action1<VirtualMachineLease>() {
@Override
public void call(VirtualMachineLease virtualMachineLease) {
System.out.println("Rejecting offer on host " + virtualMachineLease.hostname());
Assert.fail();
}
})
.withFitnessGoodEnoughFunction(new Func1<Double, Boolean>() {
@Override
public Boolean call(Double aDouble) {
return aDouble > 1.0;
}
});
if(useBinPacking)
builder = builder
.withFitnessCalculator(BinPackingFitnessCalculators.cpuMemBinPacker);
return builder.build();
}
@After
public void tearDown() throws Exception {
}
// Test that hard constraint setup for one task per zone is honored by scheduling three tasks using three hosts.
// All three tasks and three hosts are scheduled in one iteration. Each host could hold all three tasks if the constraint
// isn't evaluated, which fail this test.
@Test
public void testHardConstraint1() throws Exception {
Map<String, TaskRequest> taskMap = new HashMap<>();
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
ConstraintEvaluator zoneConstraint = new UniqueHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
}, zoneAttrName);
List<TaskRequest> tasks = getThreeTasks(taskMap, taskToCoTasksMap, zoneConstraint, null);
List<VirtualMachineLease> leases = getThreeVMs();
TaskScheduler taskScheduler = getTaskScheduler();
SchedulingResult schedulingResult = taskScheduler.scheduleOnce(tasks, leases);
Assert.assertEquals(numZones, schedulingResult.getResultMap().size());
}
// Test that a hard constraint setup for one task per zone is honored by scheduling one task per iteration. First,
// test that without using the constraint three tasks land on the same host. Then, test with three other tasks with
// the constraint and ensure they land on different hosts, one per zone.
@Test
public void testHardConstraint2() throws Exception {
// first, make sure that when not using zone constraint, 3 tasks land on the same zone
Set<String> zonesUsed = getZonesUsed(new HashMap<String, TaskRequest>(), new HashMap<String, Set<String>>(), null, null);
Assert.assertEquals("Without zone constraints expecting 3 tasks to land on same zone", 1, zonesUsed.size());
// now test with zone constraint and make sure they go on to one zone each
Map<String, TaskRequest> taskMap = new HashMap<>();
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
ConstraintEvaluator zoneConstraint = new UniqueHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
}, zoneAttrName);
zonesUsed = getZonesUsed(taskMap, taskToCoTasksMap, zoneConstraint, null);
Assert.assertEquals("With zone constraint, expecting 3 tasks to land on 3 zones", 3, zonesUsed.size());
}
// Test that using soft constraints also lands three tasks on three different hosts like in hard constraints case.
@Test
public void testSoftConstraint1() throws Exception {
Map<String, TaskRequest> taskMap = new HashMap<>();
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
UniqueHostAttrConstraint zoneConstraint = new UniqueHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
}, zoneAttrName);
Set<String> zonesUsed = getZonesUsed(taskMap, taskToCoTasksMap, null, AsSoftConstraint.get(zoneConstraint));
Assert.assertEquals(3, zonesUsed.size());
}
// test that when using a soft constraint, tasks get assigned even if constraint were to fail. We submit three tasks
// with a soft constraint of wanting to land on different zones. But, provide only two hosts. All three tasks should
// get assigned on the two hosts, not just one host.
@Test
public void testSoftConstraint2() throws Exception {
Map<String, TaskRequest> taskMap = new HashMap<>();
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
UniqueHostAttrConstraint zoneConstraint = new UniqueHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
}, zoneAttrName);
List<TaskRequest> threeTasks = getThreeTasks(taskMap, taskToCoTasksMap, null, AsSoftConstraint.get(zoneConstraint));
List<VirtualMachineLease> twoVMs = getThreeVMs().subList(0, 2);
TaskScheduler taskScheduler = getTaskScheduler();
Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(threeTasks, twoVMs).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(twoVMs.size(), resultMap.size());
int tasksAssigned=0;
Set<String> zonesUsed = new HashSet<>();
for(VMAssignmentResult r: resultMap.values()) {
Assert.assertEquals(1, r.getLeasesUsed().size());
VirtualMachineLease lease = r.getLeasesUsed().get(0);
zonesUsed.add(lease.getAttributeMap().get(zoneAttrName).getText().getValue());
tasksAssigned += r.getTasksAssigned().size();
}
Assert.assertEquals(twoVMs.size(), zonesUsed.size());
Assert.assertEquals(3, tasksAssigned);
}
@Test
public void testBalancedHostAttrSoftConstraint() throws Exception {
Map<String, TaskRequest> taskMap = new HashMap<>();
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
BalancedHostAttrConstraint constraint = new BalancedHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
}, zoneAttrName, 3);
List<TaskRequest> sixTasks = getThreeTasks(taskMap, taskToCoTasksMap, null, constraint.asSoftConstraint());
sixTasks.addAll(getThreeTasks(taskMap, taskToCoTasksMap, null, constraint.asSoftConstraint()));
final List<VirtualMachineLease> threeVMs = getThreeVMs();
final TaskScheduler taskScheduler = getTaskScheduler();
final Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(sixTasks, threeVMs).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(3, resultMap.size());
for(VMAssignmentResult r: resultMap.values()) {
Assert.assertEquals(2, r.getTasksAssigned().size());
}
}
@Test
public void testBalancedHostAttrHardConstraint() throws Exception {
Map<String, TaskRequest> taskMap = new HashMap<>();
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
BalancedHostAttrConstraint constraint = new BalancedHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
}, zoneAttrName, 3);
List<TaskRequest> sixTasks = getThreeTasks(taskMap, taskToCoTasksMap, constraint, null);
sixTasks.addAll(getThreeTasks(taskMap, taskToCoTasksMap, constraint, null));
final List<VirtualMachineLease> threeVMs = getThreeVMs();
final TaskScheduler taskScheduler = getTaskScheduler();
final Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(sixTasks, threeVMs).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(3, resultMap.size());
for(VMAssignmentResult r: resultMap.values()) {
Assert.assertEquals(2, r.getTasksAssigned().size());
}
}
// test that tasks that specify unique hosts land on separate hosts
@Test
public void testUniqueHostConstraint() throws Exception {
final Map<String, Set<String>> taskToCoTasksMap = new HashMap<>();
UniqueHostAttrConstraint uniqueHostConstraint = new UniqueHostAttrConstraint(new Func1<String, Set<String>>() {
@Override
public Set<String> call(String s) {
return taskToCoTasksMap.get(s);
}
});
List<TaskRequest> tasks = new ArrayList<>();
// First, create 5 tasks without unique host constraint
for(int i=0; i<5; i++)
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
TaskScheduler taskScheduler = getTaskScheduler();
List<VirtualMachineLease> leases = LeaseProvider.getLeases(5, 8, 8000, 1, 10);
Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
leases.clear();
Assert.assertNotNull(resultMap);
Assert.assertEquals("Tasks without unique host constraints should've landed on one host", 1, resultMap.size());
int numAssigned=0;
for(VMAssignmentResult r: resultMap.values()) {
numAssigned += r.getTasksAssigned().size();
double usedCpus=0.0;
double usedMemory=0.0;
List<Integer> usedPorts = new ArrayList<>();
for(TaskAssignmentResult a: r.getTasksAssigned()) {
taskScheduler.getTaskAssigner().call(a.getRequest(), r.getHostname());
usedCpus += a.getRequest().getCPUs();
usedMemory += a.getRequest().getMemory();
usedPorts.addAll(a.getAssignedPorts());
}
leases.add(LeaseProvider.getConsumedLease(r.getLeasesUsed().get(0), usedCpus, usedMemory, usedPorts));
}
Assert.assertEquals("Tasks without unique host constraints should've gotten assigned", tasks.size(), numAssigned);
// now test with tasks with unique host constraint
tasks.clear();
for(int i=0; i<5; i++)
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1, Arrays.asList(uniqueHostConstraint), null));
for(TaskRequest r: tasks) {
taskToCoTasksMap.put(r.getId(), new HashSet<String>());
for(TaskRequest rr: tasks)
if(!rr.getId().equals(r.getId()))
taskToCoTasksMap.get(r.getId()).add(rr.getId());
}
resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(tasks.size(), resultMap.size());
}
// tests that a task with exclusive host constraint gets assigned a host that has no other tasks on it
@Test
public void testExclusiveHostConstraint() throws Exception {
List<TaskRequest> tasks = new ArrayList<>();
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
List<VirtualMachineLease> leases = LeaseProvider.getLeases(2, 8, 8000, 1, 10);
TaskScheduler taskScheduler = getTaskScheduler();
Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(1, resultMap.size());
VMAssignmentResult vmAssignmentResult = resultMap.values().iterator().next();
String usedHostname = vmAssignmentResult.getHostname();
Assert.assertEquals(1, vmAssignmentResult.getTasksAssigned().size());
TaskAssignmentResult taskAssigned = vmAssignmentResult.getTasksAssigned().iterator().next();
leases.clear();
leases.add(LeaseProvider.getConsumedLease(vmAssignmentResult.getLeasesUsed().get(0),
taskAssigned.getRequest().getCPUs(), taskAssigned.getRequest().getMemory(),
taskAssigned.getAssignedPorts()));
// now submit two tasks, one of them with exclusive host constraint. The one with the constraint should land
// on a host that is not the usedHostname, and the other task should land on usedHostname
tasks.clear();
TaskRequest noCtask = TaskRequestProvider.getTaskRequest(1, 1000, 1);
tasks.add(noCtask);
TaskRequest yesCTask = TaskRequestProvider.getTaskRequest(1, 1000, 1, Arrays.asList(new ExclusiveHostConstraint()), null);
tasks.add(yesCTask);
resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
Assert.assertEquals(2, resultMap.size());
for(VMAssignmentResult result: resultMap.values()) {
Assert.assertEquals(1, result.getTasksAssigned().size());
TaskAssignmentResult tResult = result.getTasksAssigned().iterator().next();
if(tResult.getRequest().getId().equals(noCtask.getId()))
Assert.assertEquals("Task with no constraint should've landed on the already used host", usedHostname, result.getHostname());
else
Assert.assertFalse(usedHostname.equals(result.getHostname()));
}
}
// Test that a host that already has a task with an exclusive host constraint isn't picked for a new task
@Test
public void testExclusiveHostOnExistingTask() throws Exception {
List<TaskRequest> tasks = new ArrayList<>();
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1, Arrays.asList(new ExclusiveHostConstraint()), null));
List<VirtualMachineLease> leases = new ArrayList<>();
leases.add(LeaseProvider.getLeaseOffer("hostA", 8, 8000, 1, 10));
TaskScheduler taskScheduler = getTaskScheduler();
Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(1, resultMap.size());
taskScheduler.getTaskAssigner().call(tasks.get(0), "hostA");
tasks.clear();
leases.clear();
leases.add(LeaseProvider.getConsumedLease(resultMap.values().iterator().next()));
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals("New task shouldn't have been assigned a host with a task that has exclusiveHost constraint", 0, resultMap.size());
leases.clear();
leases.add(LeaseProvider.getLeaseOffer("hostB", 8, 8000, 1, 10));
resultMap = taskScheduler.scheduleOnce(tasks, leases).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(1, resultMap.size());
Assert.assertEquals("hostB", resultMap.values().iterator().next().getHostname());
}
// Tests that a task gets assigned a host that has the zone attribute that the task asked for
@Test
public void testHostAttrValueConstraint() throws Exception {
List<VirtualMachineLease> threeVMs = getThreeVMs();
final String[] zones = new String[threeVMs.size()];
int i=0;
for(VirtualMachineLease l: threeVMs)
zones[i++] = l.getAttributeMap().get(zoneAttrName).getText().getValue();
// first submit two tasks and ensure they land on same machine, should be the case since we use bin packing
List<TaskRequest> tasks = new ArrayList<>();
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
TaskScheduler taskScheduler = getTaskScheduler();
Map<String, VMAssignmentResult> resultMap = taskScheduler.scheduleOnce(tasks, threeVMs).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(1, resultMap.size());
VMAssignmentResult onlyResult = resultMap.values().iterator().next();
List<VirtualMachineLease> remainingLeases = Arrays.asList(LeaseProvider.getConsumedLease(onlyResult));
String usedZone = onlyResult.getLeasesUsed().iterator().next().getAttributeMap().get(zoneAttrName).getText().getValue();
final int useZoneIndex = usedZone.equals(zones[0])? 1 : 0; // pick a zone other than used
HostAttrValueConstraint c = new HostAttrValueConstraint(zoneAttrName, new Func1<String, String>() {
@Override
public String call(String s) {
return zones[useZoneIndex];
}
});
tasks.clear();
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
// now add task with host attr value constraint
TaskRequest tForPickedZone = TaskRequestProvider.getTaskRequest(1, 1000, 1, Arrays.asList(c), null);
tasks.add(tForPickedZone);
resultMap = taskScheduler.scheduleOnce(tasks, remainingLeases).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertTrue("Couldn't confirm test, all tasks landed on same machine", resultMap.size() > 1);
boolean found=false;
for(VMAssignmentResult result: resultMap.values()) {
for(TaskAssignmentResult assigned: result.getTasksAssigned()) {
if(assigned.getRequest().getId().equals(tForPickedZone.getId())) {
Assert.assertEquals(zones[useZoneIndex],
result.getLeasesUsed().iterator().next().getAttributeMap().get(zoneAttrName).getText().getValue());
found = true;
}
}
}
Assert.assertTrue(found);
}
@Test
public void testHostnameValueConstraint() throws Exception {
final List<VirtualMachineLease> threeVMs = getThreeVMs();
List<TaskRequest> tasks = new ArrayList<>();
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
HostAttrValueConstraint c1 = new HostAttrValueConstraint(null, new Func1<String, String>() {
@Override
public String call(String s) {
return threeVMs.get(0).hostname();
}
});
HostAttrValueConstraint c2 = new HostAttrValueConstraint(null, new Func1<String, String>() {
@Override
public String call(String s) {
return threeVMs.get(1).hostname();
}
});
TaskRequest t1 = TaskRequestProvider.getTaskRequest(1, 1000, 1, Arrays.asList(c1), null);
TaskRequest t2 = TaskRequestProvider.getTaskRequest(1, 1000, 1, Arrays.asList(c2), null);
tasks.add(t1);
tasks.add(t2);
Map<String, VMAssignmentResult> resultMap = getTaskScheduler().scheduleOnce(tasks, threeVMs.subList(0,2)).getResultMap();
Assert.assertNotNull(resultMap);
Assert.assertEquals(2, resultMap.size());
for(VMAssignmentResult result: resultMap.values()) {
for(TaskAssignmentResult r: result.getTasksAssigned()) {
if(r.getRequest().getId().equals(t1.getId()))
Assert.assertEquals(threeVMs.get(0).hostname(), result.getHostname());
else if(r.getRequest().getId().equals(t2.getId()))
Assert.assertEquals(threeVMs.get(1).hostname(), result.getHostname());
}
}
}
private Set<String> getZonesUsed(Map<String, TaskRequest> taskMap, Map<String, Set<String>> taskToCoTasksMap,
ConstraintEvaluator hardConstraint, VMTaskFitnessCalculator softConstraint) {
List<TaskRequest> tasks1 = getThreeTasks(taskMap, taskToCoTasksMap, hardConstraint, softConstraint);
List<VirtualMachineLease> leases1 = getThreeVMs();
TaskScheduler taskScheduler1 = getTaskScheduler();
Set<String> zonesUsed1 = new HashSet<>();
for(int i=0; i<tasks1.size(); i++) {
Map<String, VMAssignmentResult> resultMap = taskScheduler1.scheduleOnce(tasks1.subList(i, i + 1), leases1).getResultMap();
leases1.clear();
Assert.assertNotNull(resultMap);
Assert.assertEquals(1, resultMap.size());
VMAssignmentResult result = resultMap.values().iterator().next();
VirtualMachineLease lease = result.getLeasesUsed().get(0);
zonesUsed1.add(lease.getAttributeMap().get(zoneAttrName).getText().getValue());
Assert.assertEquals(1, result.getTasksAssigned().size());
TaskAssignmentResult aResult = result.getTasksAssigned().iterator().next();
TaskRequest request = aResult.getRequest();
taskScheduler1.getTaskAssigner().call(request, lease.hostname());
VirtualMachineLease unUsedLease = LeaseProvider.getConsumedLease(lease, request.getCPUs(), request.getMemory(), aResult.getAssignedPorts());
leases1.add(unUsedLease);
}
return zonesUsed1;
}
private List<VirtualMachineLease> getThreeVMs() {
List<VirtualMachineLease> leases = new ArrayList<>();
List<VirtualMachineLease.Range> ports = new ArrayList<>();
ports.add(new VirtualMachineLease.Range(1, 10));
leases.add(LeaseProvider.getLeaseOffer("hostA", 4, 4000, ports, attributesA));
leases.add(LeaseProvider.getLeaseOffer("hostB", 4, 4000, ports, attributesB));
leases.add(LeaseProvider.getLeaseOffer("hostC", 4, 4000, ports, attributesC));
return leases;
}
private List<TaskRequest> getThreeTasks(Map<String, TaskRequest> taskMap, Map<String, Set<String>> taskToCoTasksMap,
ConstraintEvaluator hardConstraint, VMTaskFitnessCalculator softConstraint) {
List<TaskRequest> tasks = new ArrayList<>(3);
List<ConstraintEvaluator> constraintEvaluators = new ArrayList<>(1);
if(hardConstraint!=null)
constraintEvaluators.add(hardConstraint);
List<VMTaskFitnessCalculator> softConstraints = new ArrayList<>();
if(softConstraint!=null)
softConstraints.add(softConstraint);
for(int i=0; i<numZones; i++) {
TaskRequest t = TaskRequestProvider.getTaskRequest(1, 1000, 1, constraintEvaluators, softConstraints);
taskMap.put(t.getId(), t);
tasks.add(t);
}
for(TaskRequest t: taskMap.values()) {
Set<String> coTasks = new HashSet<>();
taskToCoTasksMap.put(t.getId(), coTasks);
for(TaskRequest i: taskMap.values())
coTasks.add(i.getId());
}
return tasks;
}
@Test
public void testExceptionInConstraints() throws Exception {
final List<VirtualMachineLease> threeVMs = getThreeVMs();
List<TaskRequest> tasks = new ArrayList<>();
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1));
HostAttrValueConstraint c1 = new HostAttrValueConstraint(null, new Func1<String, String>() {
@Override
public String call(String s) {
throw new NullPointerException("Test exception");
}
});
tasks.add(TaskRequestProvider.getTaskRequest(1, 100, 1));
tasks.add(TaskRequestProvider.getTaskRequest(1, 1000, 1, Collections.singletonList(c1), null));
tasks.add(TaskRequestProvider.getTaskRequest(1, 100, 1));
try {
final SchedulingResult result = getTaskScheduler().scheduleOnce(tasks, threeVMs);
// expect to see 1 result for the first task before encountering exception with the 2nd task
Assert.assertEquals(0, result.getResultMap().size());
Assert.assertEquals(1, result.getExceptions().size());
}
catch (IllegalStateException e) {
Assert.fail("Unexpected exception: " + e.getMessage());
}
}
}