From a0c52ee7e7062b3fc4fc1624d6b7ee79a75837dc Mon Sep 17 00:00:00 2001 From: Jaroslav Keznikl Date: Wed, 6 Nov 2013 18:21:37 +0100 Subject: [PATCH] SingleThreadedScheduler impl and test --- .../deeco/scheduler/LocalTimeScheduler.java | 2 +- .../mff/d3s/deeco/scheduler/Scheduler.java | 46 +- .../scheduler/SingleThreadedScheduler.java | 127 +++-- .../scheduler/LocalTimeSchedulerTest.java | 2 +- .../d3s/deeco/scheduler/SchedulerTest.java | 435 +++++++++--------- .../SingleThreadedSchedulerTest.java | 19 + 6 files changed, 352 insertions(+), 279 deletions(-) create mode 100644 jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedSchedulerTest.java diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeScheduler.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeScheduler.java index f3fa2a015..693165a5a 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeScheduler.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeScheduler.java @@ -114,7 +114,7 @@ private void stopTask(final Task task) { TaskInfo ti = tasks.get(task); if( ti != null && ti.state != States.RUNNING ){ - task.setTriggerListener(null); + task.unsetTriggerListener(); ti.timer.cancel(); diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/Scheduler.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/Scheduler.java index 198b81edf..497990771 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/Scheduler.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/Scheduler.java @@ -1,24 +1,24 @@ -package cz.cuni.mff.d3s.deeco.scheduler; - -import cz.cuni.mff.d3s.deeco.executor.ExecutionListener; -import cz.cuni.mff.d3s.deeco.executor.Executor; -import cz.cuni.mff.d3s.deeco.task.Task; - - -/** - * Interface Scheduler for LocalTimeScheduler(and others if needed) - * - * @author Andranik Muradyan - * - */ -public interface Scheduler extends ExecutionListener { - public void start(); - public void stop(); - public void addTask( Task task ); - public void removeTask( Task task ); - - public void executionFailed(Task task, Exception e); - public void executionCompleted( Task task ); - public void setExecutor(Executor executor); - +package cz.cuni.mff.d3s.deeco.scheduler; + +import cz.cuni.mff.d3s.deeco.executor.ExecutionListener; +import cz.cuni.mff.d3s.deeco.executor.Executor; +import cz.cuni.mff.d3s.deeco.task.Task; + + +/** + * Interface Scheduler for LocalTimeScheduler(and others if needed) + * + * @author Andranik Muradyan + * + */ +public interface Scheduler extends ExecutionListener { + public void start(); + public void stop(); + public void addTask( Task task ); + public void removeTask( Task task ); + + public void executionFailed(Task task, Exception e); + public void executionCompleted( Task task ); + public void setExecutor(Executor executor); + } \ No newline at end of file diff --git a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedScheduler.java b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedScheduler.java index 45af39222..064405deb 100644 --- a/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedScheduler.java +++ b/jdeeco-core/src/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedScheduler.java @@ -1,10 +1,36 @@ +/* + * parts taken from java.util.Timer + * + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ package cz.cuni.mff.d3s.deeco.scheduler; import java.util.Arrays; -import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; - -import org.junit.internal.runners.statements.RunAfters; +import java.util.Set; import cz.cuni.mff.d3s.deeco.executor.Executor; import cz.cuni.mff.d3s.deeco.model.runtime.api.PeriodicTrigger; @@ -19,7 +45,9 @@ public class SingleThreadedScheduler implements Scheduler { * mostly important for postponing the Tasks' execution when the previous * execution took longer than the period. */ - Map periodicEvents; + Map periodicEvents = new HashMap<>(); + + Set allTasks = new HashSet<>(); /** * The scheduler task queue. This data structure is shared with the scheduler @@ -56,23 +84,24 @@ protected void finalize() throws Throwable { */ @Override public void executionCompleted(Task task) { - + if (task instanceof InvokeAndWaitTask) + task.notify(); + synchronized (queue) { - SchedulerEvent sTask = periodicEvents.get(task); + SchedulerEvent event = periodicEvents.get(task); // continue only for periodic tasks - if (sTask == null) + if (event == null) return; - synchronized (sTask.lock) { + synchronized (event.lock) { // if the periodic task execution took more than it remained till the next period - if (sTask.nextExecutionTime < System.currentTimeMillis()) { - queue.rescheduleTask(sTask, System.currentTimeMillis() + sTask.period); + if (event.nextExecutionTime < System.currentTimeMillis()) { + queue.rescheduleTask(event, System.currentTimeMillis() + event.period); } } } - if (task instanceof InvokeAndWaitTask) - task.notify(); + } @Override @@ -107,31 +136,45 @@ public void stop() { * @throws IllegalArgumentException of a null task is passed as an argument. */ @Override - public void addTask(Task task) { + public void addTask(Task task) { if (task == null) throw new IllegalArgumentException("The task cannot be null"); - synchronized (queue) { - if (!thread.newTasksMayBeScheduled) - throw new IllegalStateException( - "Scheduler already terminated."); + + synchronized (allTasks) { + if (allTasks.contains(task)) + return; - if (task.getPeriodicTrigger() != null) { - SchedulerEvent sTask = new SchedulerEvent(task, task.getPeriodicTrigger()); - scheduleNow(sTask, task.getPeriodicTrigger().getPeriod()); - periodicEvents.put(task, sTask); - } - } - task.setTriggerListener(new TaskTriggerListener() { - @Override - public void triggered(Task task, Trigger trigger) { - synchronized (queue) { - if (!thread.newTasksMayBeScheduled || !thread.tasksMayBeExecuted) - return; - - scheduleNow(new SchedulerEvent(task, trigger), 0); + synchronized (queue) { + if (!thread.newTasksMayBeScheduled) + throw new IllegalStateException( + "Scheduler already terminated."); + + if (task.getPeriodicTrigger() != null) { + SchedulerEvent sTask = new SchedulerEvent(task, task.getPeriodicTrigger()); + scheduleNow(sTask, task.getPeriodicTrigger().getPeriod()); + periodicEvents.put(task, sTask); } } - }); + task.setTriggerListener(new TaskTriggerListener() { + @Override + public void triggered(Task task, Trigger trigger) { + synchronized (queue) { + if (!thread.newTasksMayBeScheduled || !thread.tasksMayBeExecuted) + return; + + boolean isScheduled; + synchronized (allTasks) { + isScheduled = allTasks.contains(task); + } + if (isScheduled) { + scheduleNow(new SchedulerEvent(task, trigger), 0); + } + } + } + }); + + allTasks.add(task); + } } /** @@ -152,12 +195,18 @@ private void scheduleNow(SchedulerEvent sTask, long period) { */ @Override public void removeTask(Task task) { - task.unsetTriggerListener(); - synchronized(queue) { - // cancel all the periodic/triggered schedules of the task - queue.cancelAll(task); - periodicEvents.remove(task); - } + synchronized (allTasks) { + if (!allTasks.contains(task)) + return; + + task.unsetTriggerListener(); + synchronized(queue) { + // cancel all the periodic/triggered schedules of the task + queue.cancelAll(task); + periodicEvents.remove(task); + } + allTasks.remove(task); + } } @Override @@ -199,7 +248,7 @@ class SchedulerThread extends Thread { * temporarily stopped and all the scheduled tasks have to bee ignored. Note * that this field is protected by queue's monitor! */ - boolean tasksMayBeExecuted = true; + boolean tasksMayBeExecuted = false; /** * Our Scheduler's queue. We store this reference in preference to diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeSchedulerTest.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeSchedulerTest.java index 095f3382d..14b3b87c5 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeSchedulerTest.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/LocalTimeSchedulerTest.java @@ -3,7 +3,7 @@ import cz.cuni.mff.d3s.deeco.executor.Executor; /** - * Factory for Scheduler implementation tests + * * * @author Jaroslav Keznikl * diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SchedulerTest.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SchedulerTest.java index 729f32da3..9bfd81c94 100644 --- a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SchedulerTest.java +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SchedulerTest.java @@ -1,25 +1,26 @@ -package cz.cuni.mff.d3s.deeco.scheduler; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import cz.cuni.mff.d3s.deeco.executor.Executor; -import cz.cuni.mff.d3s.deeco.model.runtime.api.PeriodicTrigger; -import cz.cuni.mff.d3s.deeco.model.runtime.api.Trigger; -import cz.cuni.mff.d3s.deeco.task.Task; -import cz.cuni.mff.d3s.deeco.task.TaskTriggerListener; - +package cz.cuni.mff.d3s.deeco.scheduler; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import cz.cuni.mff.d3s.deeco.executor.Executor; +import cz.cuni.mff.d3s.deeco.model.runtime.api.PeriodicTrigger; +import cz.cuni.mff.d3s.deeco.model.runtime.api.Trigger; +import cz.cuni.mff.d3s.deeco.task.Task; +import cz.cuni.mff.d3s.deeco.task.TaskTriggerListener; + /** * Scheduler test suite * @@ -27,199 +28,203 @@ * @author Andranik Muradyan * * */ -public abstract class SchedulerTest { - - protected Scheduler tested; - protected Executor executor; - protected TaskTriggerListener testListener; - - protected abstract Scheduler setUpTested(Executor executor2); - - - @Before - public void setUp() throws Exception{ - executor = mock(Executor.class); - tested = setUpTested(executor); - testListener = mock(TaskTriggerListener.class); - } - - @After - public void tearDown() throws Exception{ - if (tested!=null) - tested.stop(); - } - - // TODO TB: Shouldn't we have also a test that tests repeated execution? For instnce to start the scheduler, let it run for 2 secs and see that a periodic - // task with a period of 100 ms got scheduled approx. 200 times? - - @Test - public void testPeriodicTaskScheduledWhenSchedulerStarted() throws InterruptedException { - Task t = mock(Task.class); - PeriodicTrigger p = mock(PeriodicTrigger.class); - when(p.getPeriod()).thenReturn(11L); - when(t.getPeriodicTrigger()).thenReturn(p); - - // WHEN a periodic task is added to a new (stopped) scheduler - tested.addTask(t); - // THEN the task is not scheduled - verify(executor, timeout(10).never()).execute(t, p); - - // WHEN the scheduler is started, runs for a while (longer than the - // period) and then stopped - tested.start(); - Thread.sleep(10); - tested.stop(); - // THEN the task gets eventually scheduled - verify(executor, atLeastOnce()).execute(t, p); - - reset(executor); - - // WHEN the running scheduler is stopped a bit longer (FIXME TB: not sure what it means) - // THEN the task is no longer scheduled - verify(executor, timeout(10).never()).execute(t, p); - - } - - @Test - public void testPeriodicTaskAutomaticallyScheduledWhenAddedToRunningScheduler() throws InterruptedException { - Task t = mock(Task.class); - PeriodicTrigger p = mock(PeriodicTrigger.class); - when(p.getPeriod()).thenReturn(11L); - when(t.getPeriodicTrigger()).thenReturn(p); - tested.start(); - - // WHEN a task is added to a running scheduler - tested.addTask(t); - // THEN it gets eventually scheduled - verify(executor, timeout(10).atLeastOnce()).execute(t, p); - } - - @Test - public void testPeriodicTaskNotScheduledWhenRemovedRunningScheduler() throws InterruptedException { - Task t = mock(Task.class); - PeriodicTrigger p = mock(PeriodicTrigger.class); - when(p.getPeriod()).thenReturn(11L); - when(t.getPeriodicTrigger()).thenReturn(p); - - tested.addTask(t); - tested.start(); - - // WHEN a task is removed from a running scheduler - tested.removeTask(t); - // THEN it gets eventually un-scheduled - reset(executor); - verify(executor, timeout(10).never()).execute(t, p); - } - - @Test - public void testTriggeredTaskScheduledOnlyWhenTriggered() throws InterruptedException { - Task t = createTriggeredTask(); - Trigger tr = mock(Trigger.class); - - // WHEN a triggered task is added to a stopped scheduler and the trigger is triggered - tested.addTask(t); - testListener.triggered(t, tr); - // THEN the process in not scheduled - verify(executor, never()).execute(t, tr); - - // WHEN the scheduler is started with a registered triggered task - tested.start(); - // THEN it is not scheduled if no trigger is triggered - verify(executor, timeout(10).never()).execute(t, tr); - - // WHEN the corresponding trigger is triggered - testListener.triggered(t, tr); - // THEN the process is scheduled (exactly once) - verify(executor, times(1)).execute(t, tr); - - // WHEN the scheduler is stopped and the trigger is triggered - reset(executor); - tested.stop(); - testListener.triggered(t, tr); - // THEN the process in not scheduled anymore - verify(executor, never()).execute(t, tr); - - // WHEN the task is removed from a running scheduler and the trigger is triggered - tested.start(); - tested.removeTask(t); - testListener.triggered(t, tr); - // THEN the process in not scheduled - verify(executor, never()).execute(t, tr); - } - - @Test - public void testTriggerListenerRegisteredAfterAddWhenRunning() { - Task t = mock(Task.class); - - tested.start(); - - // WHEN a task is added to a running scheduler - tested.addTask(t); - // THEN the scheduler registers a trigger listener for the task - verify(t, times(1)).setTriggerListener(any(TaskTriggerListener.class)); - - // WHEN repeating the action - reset(t); - tested.addTask(t); - // THEN nothing happens anymore - verify(t, never()).setTriggerListener(any(TaskTriggerListener.class)); - } - - @Test - public void testTriggerListenerUnregisteredAfterRemoveWhenRunning() { - Task t = mock(Task.class); - tested.start(); - tested.addTask(t); - - // WHEN a task is removed from a running scheduler - tested.removeTask(t); - - // THEN the scheduler unregisters its trigger listener for the task - verify(t, times(1)).setTriggerListener(null); - - // WHEN repeating the action - reset(t); - tested.removeTask(t); - // THEN nothing happens anymore - verify(t, never()).setTriggerListener(null); - } - - @Test - public void testTriggerListenerRegisteredAfterStartWhenAdded() { - Task t = mock(Task.class); - tested.addTask(t); - - // WHEN a scheduler with a single added task is started - tested.start(); - // THEN the scheduler registers a trigger listener for the task - verify(t, times(1)).setTriggerListener(any(TaskTriggerListener.class)); - - // WHEN repeating the action - reset(t); - tested.start(); - // THEN nothing happens anymore - verify(t, never()).setTriggerListener(any(TaskTriggerListener.class)); - } - - @Test - public void testTriggerListenerUnregisteredAfterStopWhenAdded() { - Task t = mock(Task.class); - tested.start(); - tested.addTask(t); - - // WHEN a scheduler with a single added task is stopped - tested.stop(); - - // THEN the scheduler unregisters its trigger listener for the task - verify(t, times(1)).setTriggerListener(null); - - // WHEN repeating the action - reset(t); - tested.stop(); - // THEN nothing happens anymore - verify(t, never()).setTriggerListener(null); - } - +public abstract class SchedulerTest { + + protected Scheduler tested; + protected Executor executor; + protected TaskTriggerListener testListener; + + protected abstract Scheduler setUpTested(Executor executor2); + + + @Before + public void setUp() throws Exception{ + executor = mock(Executor.class); + tested = setUpTested(executor); + testListener = mock(TaskTriggerListener.class); + } + + @After + public void tearDown() throws Exception{ + if (tested!=null) + tested.stop(); + } + + // TODO TB: Shouldn't we have also a test that tests repeated execution? For instnce to start the scheduler, let it run for 2 secs and see that a periodic + // task with a period of 100 ms got scheduled approx. 200 times? + + @Test + public void testPeriodicTaskScheduledWhenSchedulerStarted() throws InterruptedException { + Task t = mock(Task.class); + PeriodicTrigger p = mock(PeriodicTrigger.class); + when(p.getPeriod()).thenReturn(11L); + when(t.getPeriodicTrigger()).thenReturn(p); + + // WHEN a periodic task is added to a new (stopped) scheduler + tested.addTask(t); + // THEN the task is not scheduled + verify(executor, timeout(10).never()).execute(t, p); + + // WHEN the scheduler is started, runs for a while (longer than the + // period) and then stopped + tested.start(); + Thread.sleep(10); + tested.stop(); + // THEN the task gets eventually scheduled + verify(executor, atLeastOnce()).execute(t, p); + + reset(executor); + + // WHEN the running scheduler is stopped a bit longer (FIXME TB: not sure what it means) + // THEN the task is no longer scheduled + verify(executor, timeout(10).never()).execute(t, p); + + } + + @Test + public void testPeriodicTaskAutomaticallyScheduledWhenAddedToRunningScheduler() throws InterruptedException { + Task t = mock(Task.class); + PeriodicTrigger p = mock(PeriodicTrigger.class); + when(p.getPeriod()).thenReturn(11L); + when(t.getPeriodicTrigger()).thenReturn(p); + tested.start(); + + // WHEN a task is added to a running scheduler + tested.addTask(t); + // THEN it gets eventually scheduled + verify(executor, timeout(10).atLeastOnce()).execute(t, p); + } + + @Test + public void testPeriodicTaskNotScheduledWhenRemovedRunningScheduler() throws InterruptedException { + Task t = mock(Task.class); + PeriodicTrigger p = mock(PeriodicTrigger.class); + when(p.getPeriod()).thenReturn(11L); + when(t.getPeriodicTrigger()).thenReturn(p); + + tested.addTask(t); + tested.start(); + + // WHEN a task is removed from a running scheduler + tested.removeTask(t); + // THEN it gets eventually un-scheduled + reset(executor); + verify(executor, timeout(10).never()).execute(t, p); + } + + @Test + public void testTriggeredTaskScheduledOnlyWhenTriggered() throws InterruptedException { + Task t = createTriggeredTask(); + Trigger tr = mock(Trigger.class); + + // WHEN a triggered task is added to a stopped scheduler and the trigger is triggered + tested.addTask(t); + testListener.triggered(t, tr); + // THEN the process in not scheduled + verify(executor, never()).execute(t, tr); + + // WHEN the scheduler is started with a registered triggered task + tested.start(); + // THEN it is not scheduled if no trigger is triggered + verify(executor, timeout(100).never()).execute(t, tr); + + // WHEN the corresponding trigger is triggered + testListener.triggered(t, tr); + // THEN the process is scheduled (exactly once) + // (we use a small timeout because the scheduler might have a separate thread for scheduling) + verify(executor, timeout(20).times(1)).execute(t, tr); + + + // WHEN the scheduler is stopped and the trigger is triggered + tested.stop(); + reset(executor); + testListener.triggered(t, tr); + // THEN the process in not scheduled anymore + verify(executor, never()).execute(t, tr); + + // WHEN the task is removed from a running scheduler and the trigger is triggered + tested.start(); + tested.removeTask(t); + testListener.triggered(t, tr); + // THEN the process in not scheduled + verify(executor, never()).execute(t, tr); + } + + @Test + public void testTriggerListenerRegisteredAfterAddWhenRunning() { + Task t = mock(Task.class); + + tested.start(); + + // WHEN a task is added to a running scheduler + tested.addTask(t); + // THEN the scheduler registers a trigger listener for the task + verify(t, times(1)).setTriggerListener(any(TaskTriggerListener.class)); + + // WHEN repeating the action + reset(t); + tested.addTask(t); + // THEN nothing happens anymore + verify(t, never()).setTriggerListener(any(TaskTriggerListener.class)); + } + + @Test + public void testTriggerListenerUnregisteredAfterRemoveWhenRunning() { + Task t = mock(Task.class); + tested.start(); + tested.addTask(t); + + // WHEN a task is removed from a running scheduler + tested.removeTask(t); + + // THEN the scheduler unregisters its trigger listener for the task + verify(t, times(1)).unsetTriggerListener(); + + // WHEN repeating the action + reset(t); + tested.removeTask(t); + // THEN nothing happens anymore + verify(t, never()).unsetTriggerListener(); + } + + @Test + public void testTriggerListenerRegisteredAfterStartWhenAdded() { + Task t = mock(Task.class); + tested.addTask(t); + + // WHEN a scheduler with a single added task is started + tested.start(); + // THEN the scheduler registers a trigger listener for the task + verify(t, times(1)).setTriggerListener(any(TaskTriggerListener.class)); + + // WHEN repeating the action + reset(t); + tested.start(); + // THEN nothing happens anymore + verify(t, never()).setTriggerListener(any(TaskTriggerListener.class)); + } + + // TODO: decide whether this is really needed + @Test + @Ignore + public void testTriggerListenerUnregisteredAfterStopWhenAdded() { + Task t = mock(Task.class); + tested.start(); + tested.addTask(t); + + // WHEN a scheduler with a single added task is stopped + tested.stop(); + + // THEN the scheduler unregisters its trigger listener for the task + verify(t, times(1)).unsetTriggerListener(); + + // WHEN repeating the action + reset(t); + tested.stop(); + // THEN nothing happens anymore + verify(t, never()).unsetTriggerListener(); + } + /** * Creates a purely triggered task which stores the given trigger listener * into {@link #testListener}. diff --git a/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedSchedulerTest.java b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedSchedulerTest.java new file mode 100644 index 000000000..72602ec8b --- /dev/null +++ b/jdeeco-core/test/cz/cuni/mff/d3s/deeco/scheduler/SingleThreadedSchedulerTest.java @@ -0,0 +1,19 @@ +package cz.cuni.mff.d3s.deeco.scheduler; + +import cz.cuni.mff.d3s.deeco.executor.Executor; + +/** + * + * + * @author Jaroslav Keznikl + * + */ +public class SingleThreadedSchedulerTest extends SchedulerTest { + + @Override + protected Scheduler setUpTested(Executor executor) { + Scheduler s = new SingleThreadedScheduler(); + s.setExecutor(executor); + return s; + } +} \ No newline at end of file