| /* |
| * Copyright 2015 Open Networking Laboratory |
| * |
| * 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 org.onlab.util; |
| |
| import com.google.common.collect.Lists; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.TimerTask; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.onlab.junit.TestTools.delay; |
| |
| /** |
| * Testing class for manually advancing timer. |
| */ |
| public class ManuallyAdvancingTimerTest { |
| |
| private ManuallyAdvancingTimer timer; |
| |
| /* Generates unique id's for TestTasks */ |
| private AtomicInteger idGenerator; |
| |
| /* Tracks TestTasks in order of creation, tasks are automatically added at creation. */ |
| private ArrayList<TestTask> taskList; |
| |
| /* Total number of tasks run */ |
| private AtomicInteger tasksRunCount; |
| |
| // FIXME if this class fails first try increasing the real time delay to account for heavy system load. |
| private static final int REAL_TIME_DELAY = 10; |
| |
| /** |
| * Sets up the testing environment. |
| */ |
| @Before |
| public void setup() { |
| timer = new ManuallyAdvancingTimer(true); |
| idGenerator = new AtomicInteger(1); |
| tasksRunCount = new AtomicInteger(0); |
| taskList = Lists.newArrayList(); |
| } |
| |
| /** |
| * Tests the one time schedule with delay. |
| * |
| * @throws Exception throws an exception if the test fails |
| */ |
| @Test |
| public void testScheduleByDelay() throws Exception { |
| /* Test scheduling in the future as normal. */ |
| timer.schedule(new TestTask(), 10); |
| timer.advanceTimeMillis(5); |
| assertFalse(taskList.get(0).hasRun()); |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertTrue(taskList.get(0).hasRun()); |
| |
| /* Test scheduling with negative numbers */ |
| timer.schedule(new TestTask(), -10); |
| timer.advanceTimeMillis(5); |
| assertFalse(taskList.get(1).hasRun()); |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertTrue(taskList.get(1).hasRun()); |
| |
| /* Reset list, counter and timer for next test */ |
| taskList.clear(); |
| idGenerator.set(1); |
| tasksRunCount.set(0); |
| |
| for (int i = 0; i < 50; i++) { |
| timer.schedule(new TestTask(), i); |
| } |
| /* Test that a task scheduled for present is run and not placed in the queue */ |
| assertEquals("Only the first task should have run.", 1, tasksRunCount.get()); |
| |
| for (int i = 2; i <= 50; i++) { |
| timer.advanceTimeMillis(1, REAL_TIME_DELAY); |
| assertEquals("One task should be executed per loop", i, tasksRunCount.get()); |
| } |
| /* Below tests ordered insertion, this will only be done once, it is the same for all schedule methods. */ |
| |
| tasksRunCount.set(0); |
| |
| for (int i = 0; i < 10; i++) { |
| timer.schedule(new TestTask(), 500); |
| } |
| |
| assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get()); |
| timer.schedule(new TestTask(), 10); |
| assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get()); |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertEquals("One new tasks should have been run since run count reset.", 1, tasksRunCount.get()); |
| timer.advanceTimeMillis(510, REAL_TIME_DELAY); |
| assertEquals("Eleven new tasks should have been run since run count reset.", 11, tasksRunCount.get()); |
| } |
| |
| /** |
| * Tests scheduling for a particular date or time which may be in the past. |
| * |
| * @throws Exception throws an exception if the test fails |
| */ |
| @Test |
| public void testScheduleByDate() throws Exception { |
| /* Tests basic scheduling for future times. */ |
| timer.schedule(new TestTask(), new Date(10)); |
| timer.advanceTimeMillis(5); |
| assertFalse(taskList.get(0).hasRun()); |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertTrue(taskList.get(0).hasRun()); |
| |
| /* Test scheduling with past times numbers */ |
| timer.schedule(new TestTask(), new Date(0)); |
| delay(REAL_TIME_DELAY); |
| assertTrue(taskList.get(1).hasRun()); |
| |
| /* Tests cancellation on non-periodic events */ |
| TestTask task = new TestTask(); |
| timer.schedule(task, new Date(timer.currentTimeInMillis() + 10)); |
| task.cancel(); |
| timer.advanceTimeMillis(12, REAL_TIME_DELAY); |
| assertFalse(task.hasRun()); |
| |
| } |
| |
| /** |
| * Test scheduling beginning after a delay and recurring periodically. |
| * |
| * @throws Exception throws an exception if the test fails |
| */ |
| @Test |
| public void testScheduleByDelayPeriodic() throws Exception { |
| /* Test straightforward periodic execution */ |
| timer.schedule(new TestTask(), 0, 10); |
| delay(REAL_TIME_DELAY); |
| assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun()); |
| |
| /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute |
| immediately on add). */ |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun()); |
| |
| /* Tests whether cancellation works on periodic events. */ |
| taskList.get(0).cancel(); |
| |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun()); |
| |
| TestTask task = new TestTask(); |
| timer.schedule(task, 0, 10); |
| timer.advanceTimeMillis(100, REAL_TIME_DELAY); |
| assertEquals("Should have run immeditaley and subsequently once during the larger skip", task.timesRun(), 2); |
| |
| } |
| |
| /** |
| * Test scheduling beginning at a specified date and recurring periodically. |
| * |
| * @throws Exception throws an exception if the test fails |
| */ |
| @Test |
| public void testScheduleByDatePeriodic() throws Exception { |
| /* Test straightforward periodic execution */ |
| timer.schedule(new TestTask(), new Date(timer.currentTimeInMillis()), 10); |
| delay(REAL_TIME_DELAY); |
| assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun()); |
| |
| /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute |
| immediately on add). */ |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun()); |
| |
| /* Tests whether cancellation works on periodic events. */ |
| taskList.get(0).cancel(); |
| |
| timer.advanceTimeMillis(10, REAL_TIME_DELAY); |
| assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun()); |
| |
| TestTask task = new TestTask(); |
| timer.schedule(task, new Date(timer.currentTimeInMillis()), 10); |
| timer.advanceTimeMillis(100, REAL_TIME_DELAY); |
| assertEquals("Should have run immediately and subsequently once during the larger skip", task.timesRun(), 2); |
| } |
| |
| /* Schedule at fixed rate runs exactly like the two scheduling methods just tested so tests are not included */ |
| |
| /** |
| * Timer task with added functions to make it better for testing. |
| */ |
| private class TestTask extends TimerTask { |
| |
| /* Remains true once the task has been run at least once */ |
| private boolean hasRun; |
| |
| /* Unique id per event. */ |
| private int id; |
| |
| /* Specifies the number of times an event has run */ |
| private int timesRun; |
| |
| /** |
| * Constructor initializes id, timesRun, and id fields. |
| */ |
| public TestTask() { |
| id = idGenerator.getAndIncrement(); |
| timesRun = 0; |
| hasRun = false; |
| taskList.add(this); |
| } |
| |
| @Override |
| public void run() { |
| this.hasRun = true; |
| tasksRunCount.incrementAndGet(); |
| timesRun++; |
| } |
| |
| /** |
| * Returns whether this event has run. |
| * |
| * @return true if the event has run, false otherwise. |
| */ |
| public boolean hasRun() { |
| return hasRun; |
| } |
| |
| /** |
| * Returns the number of times this task has run. |
| * |
| * @return an int representing the number of times this task has been run |
| */ |
| public int timesRun() { |
| return timesRun; |
| } |
| |
| /** |
| * Returns the unique identifier of this task. |
| * |
| * @return a unique integer identifier |
| */ |
| public int getId() { |
| return id; |
| } |
| } |
| } |