/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * -- */ package com.sun.sgs.impl.kernel.schedule; import com.sun.sgs.kernel.schedule.ScheduledTask; import com.sun.sgs.kernel.schedule.SchedulerQueue; import com.sun.sgs.app.TaskRejectedException; import com.sun.sgs.auth.Identity; import com.sun.sgs.kernel.KernelRunnable; import com.sun.sgs.kernel.Priority; import com.sun.sgs.kernel.RecurringTaskHandle; import com.sun.sgs.kernel.TaskReservation; import com.sun.sgs.test.util.DummyIdentity; import com.sun.sgs.test.util.DummyKernelRunnable; import com.sun.sgs.test.util.UtilThreadGroup; import com.sun.sgs.tools.test.ParameterizedFilteredNameRunner; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import java.util.Properties; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; /** * Tests for the various <code>SchedulerQueue</code> implementations. * Note that this is a general collection of tests that apply to any * queue. */ @RunWith(ParameterizedFilteredNameRunner.class) public class TestSchedulerQueueImpl { @Parameterized.Parameters public static LinkedList<String[]> data() { LinkedList<String[]> params = new LinkedList<String[]>(); params.add(new String [] {FIFOSchedulerQueue.class.getName()}); params.add(new String [] {WindowSchedulerQueue.class.getName()}); return params; } // a basic task that shouldn't be run but can be used for tests private static final ScheduledTaskImpl testTask = new ScheduledTaskImpl(); // the fully-qualified name of the queue we're testing private String schedulerQueueName; // the scheduler used in any given test private SchedulerQueue schedulerQueue; @BeforeClass public static void setupSystem() { // class-wide setup can happen here } @AfterClass public static void teardownSystem() { // class-wide teardown can happen here } public TestSchedulerQueueImpl(String schedulerQueueName) { this.schedulerQueueName = schedulerQueueName; } @Before public void setupSingleTest() { schedulerQueue = null; } @After public void teardownSingleTest() { if (schedulerQueue != null) schedulerQueue.shutdown(); } /** * Constructor tests. */ @Test public void constructorWithValidArgs() throws Exception { getQueueInstance(); } @Test(expected=NullPointerException.class) public void constructorWithNullArgs() throws Exception { try { getQueueInstance(null); } catch (InvocationTargetException ite) { throw (Exception)(ite.getCause()); } fail("Invocation exception expected"); } /** * Task reservation tests. */ @Test public void reserveTask() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.reserveTask(testTask); } @Test public void reserveTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); } @Test public void reserveTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.reserveTask(testTask); queue.reserveTask(testTask); queue.reserveTask(testTask); queue.reserveTask(testTask); queue.reserveTask(testTask); queue.reserveTask(testTask); } @Test public void reserveTasksDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); ScheduledTask delayedTask = new ScheduledTaskImpl(testTask, 100); queue.reserveTask(delayedTask); queue.reserveTask(delayedTask); queue.reserveTask(delayedTask); queue.reserveTask(delayedTask); queue.reserveTask(delayedTask); queue.reserveTask(delayedTask); } @Test (expected=NullPointerException.class) public void reserveTaskNull() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.reserveTask(null); } @Test public void useReservedTask() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(testTask); reservation.use(); } @Test public void useReservedTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); reservation.use(); } @Test public void cancelReservedTask() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(testTask); reservation.cancel(); } @Test public void cancelReservedTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); reservation.cancel(); } @Test (expected=IllegalStateException.class) public void reuseReservedTask() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(testTask); reservation.use(); reservation.use(); } @Test (expected=IllegalStateException.class) public void reuseReservedTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); reservation.use(); reservation.use(); } @Test (expected=IllegalStateException.class) public void recancelReservedTask() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(testTask); reservation.cancel(); reservation.cancel(); } @Test (expected=IllegalStateException.class) public void recancelReservedTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); reservation.cancel(); reservation.cancel(); } @Test (expected=IllegalStateException.class) public void cancelAfterUseReservedTask() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(testTask); reservation.use(); reservation.cancel(); } @Test (expected=IllegalStateException.class) public void cancelAfterUseReservedTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); reservation.use(); reservation.cancel(); } @Test (expected=IllegalStateException.class) public void useAfterCancelReservedTask() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(testTask); reservation.cancel(); reservation.use(); } @Test (expected=IllegalStateException.class) public void useAfterCancelReservedTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation = queue.reserveTask(new ScheduledTaskImpl(testTask, 100)); reservation.cancel(); reservation.use(); } @Test (expected=TaskRejectedException.class) public void reserveTaskRecurring() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.reserveTask(new ScheduledTaskImpl(0, 100)); } /** * Task addition tests. */ @Test public void addTask() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(testTask); } @Test public void addTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(new ScheduledTaskImpl(testTask, 100)); } @Test public void addTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(testTask); queue.addTask(testTask); queue.addTask(testTask); queue.addTask(testTask); queue.addTask(testTask); queue.addTask(testTask); } @Test public void addTasksDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); ScheduledTask delayedTask = new ScheduledTaskImpl(testTask, 100); queue.addTask(delayedTask); queue.addTask(delayedTask); queue.addTask(delayedTask); queue.addTask(delayedTask); queue.addTask(delayedTask); queue.addTask(delayedTask); } @Test (expected=NullPointerException.class) public void addTaskNull() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(null); } /** * Recurring task addition tests. */ @Test public void addTaskRecurring() throws Exception { getRecurringTask(); } @Test public void addTasksRecurring() throws Exception { getRecurringTask(); getRecurringTask(); getRecurringTask(); getRecurringTask(); getRecurringTask(); getRecurringTask(); } @Test (expected=NullPointerException.class) public void addTaskRecurringNull() throws Exception { getQueueInstance().createRecurringTaskHandle(null); } @Test public void cancelAfterStartRecurringTask() throws Exception { RecurringTaskHandle handle = getRecurringTask().getRecurringTaskHandle(); handle.start(); handle.cancel(); } @Test public void startSleepAndCancelRecurringTask() throws Exception { RecurringTaskHandle handle = getRecurringTask().getRecurringTaskHandle(); handle.start(); Thread.sleep(200); handle.cancel(); } @Test public void cancelRecurringTask() throws Exception { RecurringTaskHandle handle = getRecurringTask().getRecurringTaskHandle(); handle.cancel(); } @Test public void restartRecurringTask() throws Exception { RecurringTaskHandle handle = getRecurringTask().getRecurringTaskHandle(); handle.start(); try { handle.start(); fail("Expected an IllegalStateException"); } catch(IllegalStateException e) {} finally { // this is to make sure that the timer doesn't keep going handle.cancel(); } } @Test (expected=IllegalStateException.class) public void recancelRecurringTask() throws Exception { RecurringTaskHandle handle = getRecurringTask().getRecurringTaskHandle(); handle.cancel(); handle.cancel(); } @Test (expected=IllegalStateException.class) public void startAfterCancelRecurringTask() throws Exception { RecurringTaskHandle handle = getRecurringTask().getRecurringTaskHandle(); handle.cancel(); handle.start(); } /** * Add and consume correctness tests. */ @Test public void addAndConsumeTask() throws Exception { SchedulerQueue queue = getQueueInstance(); ScheduledTask task = new ScheduledTaskImpl(); queue.addTask(task); assertEquals(task, queue.getNextTask(false)); } @Test (timeout=100) public void addAndConsumeTaskWaiting() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(new ScheduledTaskImpl()); queue.getNextTask(true); } @Test public void addAndConsumeTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); assertNotNull(queue.getNextTask(false)); assertNotNull(queue.getNextTask(false)); assertNotNull(queue.getNextTask(false)); assertNull(queue.getNextTask(false)); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); queue.addTask(new ScheduledTaskImpl()); LinkedList<ScheduledTask> tasks = new LinkedList<ScheduledTask>(); assertEquals(6, queue.getNextTasks(tasks, 10)); } @Test (timeout=300) public void reserveAndConsumeTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); TaskReservation reservation =queue.reserveTask(new ScheduledTaskImpl()); reservation.use(); reservation = queue.reserveTask(new ScheduledTaskImpl()); reservation.cancel(); reservation = queue.reserveTask(new ScheduledTaskImpl(100)); reservation.use(); reservation = queue.reserveTask(new ScheduledTaskImpl(120)); reservation.cancel(); reservation = queue.reserveTask(new ScheduledTaskImpl(140)); reservation.use(); assertNotNull(queue.getNextTask(false)); assertNull(queue.getNextTask(false)); assertNotNull(queue.getNextTask(true)); assertNotNull(queue.getNextTask(true)); assertNull(queue.getNextTask(false)); } @Test public void addAndConsumeTaskDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); ScheduledTask task = new ScheduledTaskImpl(100); queue.addTask(task); assertNull(queue.getNextTask(false)); Thread.sleep(200); assertEquals(task, queue.getNextTask(false)); } @Test (timeout=200) public void addAndConsumeTaskDelayedWaiting() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(new ScheduledTaskImpl(100)); queue.getNextTask(true); } @Test public void addAndConsumeTasksDelayed() throws Exception { SchedulerQueue queue = getQueueInstance(); queue.addTask(new ScheduledTaskImpl(100)); queue.addTask(new ScheduledTaskImpl(100)); queue.addTask(new ScheduledTaskImpl(120)); queue.addTask(new ScheduledTaskImpl(110)); Thread.sleep(200); assertNotNull(queue.getNextTask(false)); assertNotNull(queue.getNextTask(false)); assertNotNull(queue.getNextTask(false)); assertNotNull(queue.getNextTask(false)); assertNull(queue.getNextTask(false)); queue.addTask(new ScheduledTaskImpl(100)); queue.addTask(new ScheduledTaskImpl(100)); queue.addTask(new ScheduledTaskImpl(120)); queue.addTask(new ScheduledTaskImpl(110)); queue.addTask(new ScheduledTaskImpl(150)); LinkedList<ScheduledTask> tasks = new LinkedList<ScheduledTask>(); assertEquals(0, queue.getNextTasks(tasks, 5)); Thread.sleep(200); assertEquals(3, queue.getNextTasks(tasks, 3)); assertEquals(2, queue.getNextTasks(tasks, 3)); } @Test public void addAndConsumeTasksRecurring() throws Exception { RecurringTaskHandle handle1 = getRecurringTask().getRecurringTaskHandle(); handle1.start(); RecurringTaskHandle handle2 = getRecurringTask().getRecurringTaskHandle(); handle2.cancel(); RecurringTaskHandle handle3 = getRecurringTask().getRecurringTaskHandle(); handle3.start(); handle1.cancel(); handle3.cancel(); LinkedList<ScheduledTask> tasks = new LinkedList<ScheduledTask>(); assertEquals(2, schedulerQueue.getNextTasks(tasks, 6)); Thread.sleep(150); assertNull(schedulerQueue.getNextTask(false)); } /** * Test scale through number of tasks and number of threads. */ @Test (timeout=1000) public void addAndConsumeManyTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); for (int i = 0; i < 537; i++) queue.addTask(new ScheduledTaskImpl(50)); for (int i = 0; i < 679; i++) queue.addTask(new ScheduledTaskImpl()); int count = 0; while (queue.getNextTask(false) != null) count++; Thread.sleep(100); while (queue.getNextTask(false) != null) count++; assertEquals(1216, count); } @Test (timeout=5000) public void fewThreadsFewTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); Runnable [] r = new Runnable[4]; r[0] = new ProducerRunnable(queue, 1); r[1] = new ProducerRunnable(queue, 10); r[2] = new ConsumerRunnable(queue, 4); r[3] = new ConsumerRunnable(queue, 7); UtilThreadGroup threadGroup = new UtilThreadGroup(r); threadGroup.run(); assertEquals(0, threadGroup.getFailureCount()); } @Test (timeout=5000) public void manyThreadsFewTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); Runnable [] r = new Runnable[128]; for (int i = 0; i < 64; i++) r[i] = new ProducerRunnable(queue, 4); for (int i = 64; i < 128; i++) r[i] = new ConsumerRunnable(queue, 4); UtilThreadGroup threadGroup = new UtilThreadGroup(r); threadGroup.run(); assertEquals(0, threadGroup.getFailureCount()); } @Test (timeout=5000) public void fewThreadsManyTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); Runnable [] r = new Runnable[4]; r[0] = new ProducerRunnable(queue, 674); r[1] = new ProducerRunnable(queue, 458); r[2] = new ConsumerRunnable(queue, 539); r[3] = new ConsumerRunnable(queue, 593); UtilThreadGroup threadGroup = new UtilThreadGroup(r); threadGroup.run(); assertEquals(0, threadGroup.getFailureCount()); } @Test (timeout=5000) public void manyThreadsManyTasks() throws Exception { SchedulerQueue queue = getQueueInstance(); Runnable [] r = new Runnable[128]; for (int i = 0; i < 64; i++) r[i] = new ProducerRunnable(queue, 83); for (int i = 64; i < 128; i++) r[i] = new ConsumerRunnable(queue, 83); UtilThreadGroup threadGroup = new UtilThreadGroup(r); threadGroup.run(); assertEquals(0, threadGroup.getFailureCount()); } /** * Utility methods. */ protected SchedulerQueue getQueueInstance() throws Exception { return getQueueInstance(new Properties()); } protected SchedulerQueue getQueueInstance(Properties p) throws Exception { Constructor<?> schedulerConstructor = null; Class<?> schedulerClass = Class.forName(schedulerQueueName); schedulerConstructor = schedulerClass.getConstructor(Properties.class); schedulerQueue = (SchedulerQueue)(schedulerConstructor.newInstance(p)); return schedulerQueue; } protected ScheduledTaskImpl getRecurringTask() throws Exception { if (schedulerQueue == null) getQueueInstance(); ScheduledTaskImpl task = new ScheduledTaskImpl(0, 100); task.setRecurringTaskHandle(schedulerQueue. createRecurringTaskHandle(task)); return task; } /** * Utility classes. */ private class ConsumerRunnable implements Runnable { private SchedulerQueue queue; private int tasks; public ConsumerRunnable(SchedulerQueue queue, int tasks) { this.queue = queue; this.tasks = tasks; } public void run() { try { for (int i = 0; i< tasks; i++) queue.getNextTask(true); } catch (InterruptedException ie) {} } } private class ProducerRunnable implements Runnable { private SchedulerQueue queue; private int tasks; public ProducerRunnable(SchedulerQueue queue, int tasks) { this.queue = queue; this.tasks = tasks; } public void run() { for (int i = 0; i < tasks; i++) queue.addTask(new ScheduledTaskImpl()); } } private static class ScheduledTaskImpl implements ScheduledTask { private final KernelRunnable task; private final DummyIdentity owner; private final long start; private final long period; private long timeout = 100; private Throwable lastFailure = null; private RecurringTaskHandle handle = null; private boolean cancelled = false; ScheduledTaskImpl() { this(0, NON_RECURRING); } ScheduledTaskImpl(long delay) { this(delay, NON_RECURRING); } ScheduledTaskImpl(long delay, long period) { this.task = new DummyKernelRunnable(); this.owner = new DummyIdentity(); this.start = System.currentTimeMillis() + delay; this.period = period; } ScheduledTaskImpl(ScheduledTaskImpl schedTask) { this(schedTask, 0); } ScheduledTaskImpl(ScheduledTaskImpl schedTask, long delay) { this.task = schedTask.task; this.owner = schedTask.owner; this.start = System.currentTimeMillis() + delay; this.period = schedTask.period; } public KernelRunnable getTask() { return task; } public Identity getOwner() { return owner; } public Priority getPriority() { return Priority.getDefaultPriority(); } public long getStartTime() { return start; } public long getPeriod() { return period; } public long getTimeout() { return timeout; } public Throwable getLastFailure() { return lastFailure; } public void setPriority(Priority priority) { } public void setTimeout(long timeout) { throw new UnsupportedOperationException("not supported"); } public int getTryCount() { return 0; } public boolean isRecurring() { return period != NON_RECURRING; } void setRecurringTaskHandle(RecurringTaskHandle handle) { this.handle = handle; } public RecurringTaskHandle getRecurringTaskHandle() { return handle; } public synchronized boolean isCancelled() { return cancelled; } public synchronized boolean cancel(boolean allowInterrupt) { if (cancelled) return false; cancelled = true; return true; } } }