blob: b8e1e85eb1fd587b4c0afa3c05552629ed2b805d [file] [log] [blame]
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onlab.util;
18
19import com.google.common.collect.Lists;
20import org.junit.Before;
21import org.junit.Test;
22
23import java.util.ArrayList;
24import java.util.Date;
25import java.util.TimerTask;
26import java.util.concurrent.atomic.AtomicInteger;
27
28import static org.junit.Assert.assertEquals;
29import static org.junit.Assert.assertFalse;
30import static org.junit.Assert.assertTrue;
31import static org.onlab.junit.TestTools.delay;
32
33/**
34 * Testing class for manually advancing timer.
35 */
36public class ManuallyAdvancingTimerTest {
37
38 private ManuallyAdvancingTimer timer;
39
40 /* Generates unique id's for TestTasks */
41 private AtomicInteger idGenerator;
42
43 /* Tracks TestTasks in order of creation, tasks are automatically added at creation. */
44 private ArrayList<TestTask> taskList;
45
46 /* Total number of tasks run */
47 private AtomicInteger tasksRunCount;
48
49 // FIXME if this class fails first try increasing the real time delay to account for heavy system load.
50 private static final int REAL_TIME_DELAY = 1;
51
52 /**
53 * Sets up the testing environment.
54 */
55 @Before
56 public void setup() {
57 timer = new ManuallyAdvancingTimer();
58 idGenerator = new AtomicInteger(1);
59 tasksRunCount = new AtomicInteger(0);
60 taskList = Lists.newArrayList();
61 }
62
63 /**
64 * Tests the one time schedule with delay.
65 *
66 * @throws Exception throws an exception if the test fails
67 */
68 @Test
69 public void testScheduleByDelay() throws Exception {
70 /* Test scheduling in the future as normal. */
71 timer.schedule(new TestTask(), 10);
72 timer.advanceTimeMillis(5);
73 assertFalse(taskList.get(0).hasRun());
74 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
75 assertTrue(taskList.get(0).hasRun());
76
77 /* Test scheduling with negative numbers */
78 timer.schedule(new TestTask(), -10);
79 timer.advanceTimeMillis(5);
80 assertFalse(taskList.get(1).hasRun());
81 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
82 assertTrue(taskList.get(1).hasRun());
83
84 /* Reset list, counter and timer for next test */
85 taskList.clear();
86 idGenerator.set(1);
87 tasksRunCount.set(0);
88
89 for (int i = 0; i < 50; i++) {
90 timer.schedule(new TestTask(), i);
91 }
92 /* Test that a task scheduled for present is run and not placed in the queue */
93 assertEquals("Only the first task should have run.", 1, tasksRunCount.get());
94
95 for (int i = 2; i <= 50; i++) {
96 timer.advanceTimeMillis(1, REAL_TIME_DELAY);
97 assertEquals("One task should be executed per loop", i, tasksRunCount.get());
98 }
99 /* Below tests ordered insertion, this will only be done once, it is the same for all schedule methods. */
100
101 tasksRunCount.set(0);
102
103 for (int i = 0; i < 10; i++) {
104 timer.schedule(new TestTask(), 500);
105 }
106
107 assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get());
108 timer.schedule(new TestTask(), 10);
109 assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get());
110 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
111 assertEquals("One new tasks should have been run since run count reset.", 1, tasksRunCount.get());
112 timer.advanceTimeMillis(510, REAL_TIME_DELAY);
113 assertEquals("Eleven new tasks should have been run since run count reset.", 11, tasksRunCount.get());
114 }
115
116 /**
117 * Tests scheduling for a particular date or time which may be in the past.
118 *
119 * @throws Exception throws an exception if the test fails
120 */
121 @Test
122 public void testScheduleByDate() throws Exception {
123 /* Tests basic scheduling for future times. */
124 timer.schedule(new TestTask(), new Date(10));
125 timer.advanceTimeMillis(5);
126 assertFalse(taskList.get(0).hasRun());
127 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
128 assertTrue(taskList.get(0).hasRun());
129
130 /* Test scheduling with past times numbers */
131 timer.schedule(new TestTask(), new Date(0));
132 delay(REAL_TIME_DELAY);
133 assertTrue(taskList.get(1).hasRun());
134
135 /* Tests cancellation on non-periodic events */
136 TestTask task = new TestTask();
137 timer.schedule(task, new Date(timer.currentTimeInMillis() + 10));
138 task.cancel();
139 timer.advanceTimeMillis(12, REAL_TIME_DELAY);
140 assertFalse(task.hasRun());
141
142 }
143
144 /**
145 * Test scheduling beginning after a delay and recurring periodically.
146 *
147 * @throws Exception throws an exception if the test fails
148 */
149 @Test
150 public void testScheduleByDelayPeriodic() throws Exception {
151 /* Test straightforward periodic execution */
152 timer.schedule(new TestTask(), 0, 10);
153 delay(REAL_TIME_DELAY);
154 assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun());
155
156 /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute
157 immediately on add). */
158 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
159 assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun());
160
161 /* Tests whether cancellation works on periodic events. */
162 taskList.get(0).cancel();
163
164 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
165 assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun());
166
167 TestTask task = new TestTask();
168 timer.schedule(task, 0, 10);
169 timer.advanceTimeMillis(100, REAL_TIME_DELAY);
170 assertEquals("Should have run immeditaley and subsequently once during the larger skip", task.timesRun(), 2);
171
172 }
173
174 /**
175 * Test scheduling beginning at a specified date and recurring periodically.
176 *
177 * @throws Exception throws an exception if the test fails
178 */
179 @Test
180 public void testScheduleByDatePeriodic() throws Exception {
181 /* Test straightforward periodic execution */
182 timer.schedule(new TestTask(), new Date(timer.currentTimeInMillis()), 10);
183 delay(REAL_TIME_DELAY);
184 assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun());
185
186 /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute
187 immediately on add). */
188 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
189 assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun());
190
191 /* Tests whether cancellation works on periodic events. */
192 taskList.get(0).cancel();
193
194 timer.advanceTimeMillis(10, REAL_TIME_DELAY);
195 assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun());
196
197 TestTask task = new TestTask();
198 timer.schedule(task, new Date(timer.currentTimeInMillis()), 10);
199 timer.advanceTimeMillis(100, REAL_TIME_DELAY);
200 assertEquals("Should have run immediately and subsequently once during the larger skip", task.timesRun(), 2);
201 }
202
203 /* Schedule at fixed rate runs exactly like the two scheduling methods just tested so tests are not included */
204
205 /**
206 * Timer task with added functions to make it better for testing.
207 */
208 private class TestTask extends TimerTask {
209
210 /* Remains true once the task has been run at least once */
211 private boolean hasRun;
212
213 /* Unique id per event. */
214 private int id;
215
216 /* Specifies the number of times an event has run */
217 private int timesRun;
218
219 /**
220 * Constructor initializes id, timesRun, and id fields.
221 */
222 public TestTask() {
223 id = idGenerator.getAndIncrement();
224 timesRun = 0;
225 hasRun = false;
226 taskList.add(this);
227 }
228
229 @Override
230 public void run() {
231 this.hasRun = true;
232 tasksRunCount.incrementAndGet();
233 timesRun++;
234 }
235
236 /**
237 * Returns whether this event has run.
238 *
239 * @return true if the event has run, false otherwise.
240 */
241 public boolean hasRun() {
242 return hasRun;
243 }
244
245 /**
246 * Returns the number of times this task has run.
247 *
248 * @return an int representing the number of times this task has been run
249 */
250 public int timesRun() {
251 return timesRun;
252 }
253
254 /**
255 * Returns the unique identifier of this task.
256 *
257 * @return a unique integer identifier
258 */
259 public int getId() {
260 return id;
261 }
262 }
263}