/******************************************************************************* * Copyright 2013 Michael Marconi * * 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 oncue.tests.strategies; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import junit.framework.Assert; import oncue.agent.JVMCapacityAgent; import oncue.common.messages.EnqueueJob; import oncue.common.messages.Job; import oncue.common.messages.WorkResponse; import oncue.scheduler.JVMCapacityScheduler; import oncue.tests.base.ActorSystemTest; import oncue.tests.workers.TestWorker; import org.junit.Ignore; import org.junit.Test; import akka.actor.Actor; import akka.actor.ActorRef; import akka.actor.Props; import akka.actor.UntypedActorFactory; import akka.testkit.JavaTestKit; import akka.testkit.TestActorRef; /** * Test the JVM memory capacity strategy by farming jobs of known size out to * agents with known capacities. */ public class JVMCapacityStrategyTest extends ActorSystemTest { /*- * Jobs: J1(100), J2(200), J3(50), J4(200), J5(500) * Agent capacity: A1(500), A2(70), A3(200) * * J1(100): | A2(70) | A3(200) | A1(500) | * | x | J1 | - | * * J2(200): | A2(70) | A3(100) | A1(500) | * | x | x | J2 | * * J3(50): | A2(70) | A3(100) | A1(300) | * | J3 | - | - | * * J4(200): | A2(20) | A3(100) | A1(300) | * | x | x | J4 | * * J5(500): | A2(20) | A3(100) | A1(100) | * | x | x | x | * * Final allocation: A1(J2,J4) * A2(J3) * A3(J1) * Job 5 unscheduled! */ @Test @SuppressWarnings("serial") @Ignore("Ignore this test until this strategy becomes necessary") public void jvmCapacityStrategyTest() { new JavaTestKit(system) { { // Create a naked JVM capacity-aware scheduler final Props schedulerProps = new Props(new UntypedActorFactory() { @Override public Actor create() { return new JVMCapacityScheduler(null); } }); final TestActorRef<JVMCapacityScheduler> schedulerRef = TestActorRef.create(system, schedulerProps, settings.SCHEDULER_NAME); final JVMCapacityScheduler scheduler = schedulerRef.underlyingActor(); // Create agent probes final JavaTestKit agentProbe1 = createAgentProbe(); final JavaTestKit agentProbe2 = createAgentProbe(); final JavaTestKit agentProbe3 = createAgentProbe(); /* * Create three capacity-aware agents with pre-determined * capacity */ createAgent(agentProbe1, "agent1", 500); createAgent(agentProbe2, "agent2", 70); createAgent(agentProbe3, "agent3", 200); // Wait for initial work response at agents agentProbe1.expectMsgClass(WorkResponse.class); agentProbe2.expectMsgClass(WorkResponse.class); agentProbe3.expectMsgClass(WorkResponse.class); /* * Pause the scheduler, as we want the scheduler to see all * enqueued jobs in a single batch for testing purposes */ scheduler.pause(); /* * Enqueue jobs with various sizes */ enqueueJob(schedulerRef, getRef(), 100); Job job1 = expectMsgClass(Job.class); enqueueJob(schedulerRef, getRef(), 200); Job job2 = expectMsgClass(Job.class); enqueueJob(schedulerRef, getRef(), 50); Job job3 = expectMsgClass(Job.class); enqueueJob(schedulerRef, getRef(), 200); Job job4 = expectMsgClass(Job.class); enqueueJob(schedulerRef, getRef(), 500); Job job5 = expectMsgClass(Job.class); // Unpause the scheduler scheduler.unpause(); // Expect Job 2 and Job 4 at Agent 1 WorkResponse agent1WorkResponse = agentProbe1.expectMsgClass(WorkResponse.class); Assert.assertEquals(2, agent1WorkResponse.getJobs().size()); Job agent1Job2 = agent1WorkResponse.getJobs().get(0); Assert.assertEquals(job2.getParams().get(JVMCapacityScheduler.JOB_SIZE), agent1Job2.getParams().get(JVMCapacityScheduler.JOB_SIZE)); Job agent1Job4 = agent1WorkResponse.getJobs().get(0); Assert.assertEquals(job4.getParams().get(JVMCapacityScheduler.JOB_SIZE), agent1Job4.getParams().get(JVMCapacityScheduler.JOB_SIZE)); // Expect Job 3 at Agent 2 WorkResponse agent2WorkResponse = agentProbe2.expectMsgClass(WorkResponse.class); Assert.assertEquals(1, agent2WorkResponse.getJobs().size()); Job agent2Job3 = agent2WorkResponse.getJobs().get(0); Assert.assertEquals(job3.getParams().get(JVMCapacityScheduler.JOB_SIZE), agent2Job3.getParams().get(JVMCapacityScheduler.JOB_SIZE)); // Expect Job 1 at Agent 3 WorkResponse agent3WorkResponse = agentProbe3.expectMsgClass(WorkResponse.class); Assert.assertEquals(1, agent3WorkResponse.getJobs().size()); Job agent3Job1 = agent3WorkResponse.getJobs().get(0); Assert.assertEquals(job1.getParams().get(JVMCapacityScheduler.JOB_SIZE), agent3Job1.getParams().get(JVMCapacityScheduler.JOB_SIZE)); /* * Now, Jobs 1 - 4 will complete and all the agents will ask for * new work. Since Agent 1 is the only one big enough to fit Job * 5, it will receive it. */ agent1WorkResponse = agentProbe1.expectMsgClass(duration("5 seconds"), WorkResponse.class); Assert.assertEquals(1, agent1WorkResponse.getJobs().size()); Job agent1Job5 = agent1WorkResponse.getJobs().get(0); Assert.assertEquals(job5.getParams().get(JVMCapacityScheduler.JOB_SIZE), agent1Job5.getParams().get(JVMCapacityScheduler.JOB_SIZE)); } }; } private JavaTestKit createAgentProbe() { return new JavaTestKit(system) { { new IgnoreMsg() { @Override protected boolean ignore(Object message) { return !(message instanceof WorkResponse); } }; } }; } @SuppressWarnings("serial") private void createAgent(final JavaTestKit agentProbe, String name, final int capacity) { system.actorOf(new Props(new UntypedActorFactory() { @Override public Actor create() throws Exception { JVMCapacityAgent agent = new JVMCapacityAgent(new HashSet<String>(Arrays.asList(TestWorker.class .getName())), capacity); agent.injectProbe(agentProbe.getRef()); return agent; } }), name); } @SuppressWarnings("serial") private void enqueueJob(ActorRef scheduler, ActorRef testKit, final int jobSize) { scheduler.tell(new EnqueueJob(TestWorker.class.getName(), new HashMap<String, String>() { { put(JVMCapacityScheduler.JOB_SIZE, new Integer(jobSize).toString()); } }), testKit); } }