Aaron Kruglikov
Committed by Gerrit Code Review

Adds manually advancing timer.

Change-Id: I83936f4fff577b0f23404560c6ecfbc0c9f18e2e
...@@ -64,27 +64,40 @@ public final class TestUtils { ...@@ -64,27 +64,40 @@ public final class TestUtils {
64 /** 64 /**
65 * Gets the field, bypassing scope restriction. 65 * Gets the field, bypassing scope restriction.
66 * 66 *
67 - * @param subject Object where the field belongs 67 + * @param subject Object where the field belongs
68 * @param fieldName name of the field to get 68 * @param fieldName name of the field to get
69 + * @param <T> subject type
70 + * @param <U> fieldO value type
69 * @return value of the field. 71 * @return value of the field.
70 - * @param <T> subject type
71 - * @param <U> field value type
72 * @throws TestUtilsException if there are reflection errors while getting 72 * @throws TestUtilsException if there are reflection errors while getting
73 - * the field 73 + * the field
74 */ 74 */
75 public static <T, U> U getField(T subject, String fieldName) 75 public static <T, U> U getField(T subject, String fieldName)
76 throws TestUtilsException { 76 throws TestUtilsException {
77 try { 77 try {
78 + NoSuchFieldException exception = null;
78 @SuppressWarnings("unchecked") 79 @SuppressWarnings("unchecked")
79 - Class<T> clazz = (Class<T>) subject.getClass(); 80 + Class clazz = subject.getClass();
80 - Field field = clazz.getDeclaredField(fieldName); 81 + while (clazz != null) {
81 - field.setAccessible(true); 82 + try {
83 + Field field = clazz.getDeclaredField(fieldName);
84 + field.setAccessible(true);
82 85
83 - @SuppressWarnings("unchecked") 86 + @SuppressWarnings("unchecked")
84 - U result = (U) field.get(subject); 87 + U result = (U) field.get(subject);
85 - return result; 88 + return result;
86 - } catch (NoSuchFieldException | SecurityException | 89 + } catch (NoSuchFieldException e) {
87 - IllegalArgumentException | IllegalAccessException e) { 90 + exception = e;
91 + if (clazz == clazz.getSuperclass()) {
92 + break;
93 + }
94 + clazz = clazz.getSuperclass();
95 + }
96 + }
97 + throw new TestUtilsException("Field not found. " + fieldName, exception);
98 +
99 + } catch (SecurityException |
100 + IllegalArgumentException | IllegalAccessException e) {
88 throw new TestUtilsException("getField failed", e); 101 throw new TestUtilsException("getField failed", e);
89 } 102 }
90 } 103 }
......
...@@ -15,23 +15,24 @@ ...@@ -15,23 +15,24 @@
15 */ 15 */
16 package org.onlab.util; 16 package org.onlab.util;
17 17
18 -import org.junit.Ignore;
19 import org.junit.Test; 18 import org.junit.Test;
20 19
21 import java.util.List; 20 import java.util.List;
22 -import java.util.Timer;
23 import java.util.stream.IntStream; 21 import java.util.stream.IntStream;
24 22
25 -import static org.junit.Assert.*; 23 +import static org.junit.Assert.assertEquals;
24 +import static org.junit.Assert.assertFalse;
25 +import static org.junit.Assert.assertTrue;
26 import static org.onlab.junit.TestTools.assertAfter; 26 import static org.onlab.junit.TestTools.assertAfter;
27 -import static org.onlab.junit.TestTools.delay;
28 27
29 /** 28 /**
30 * Tests the operation of the accumulator. 29 * Tests the operation of the accumulator.
31 */ 30 */
32 public class AbstractAccumulatorTest { 31 public class AbstractAccumulatorTest {
33 32
34 - private final Timer timer = new Timer(); 33 +
34 + private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer();
35 +
35 36
36 @Test 37 @Test
37 public void basics() throws Exception { 38 public void basics() throws Exception {
...@@ -42,7 +43,6 @@ public class AbstractAccumulatorTest { ...@@ -42,7 +43,6 @@ public class AbstractAccumulatorTest {
42 assertEquals("incorrect idle ms", 70, accumulator.maxIdleMillis()); 43 assertEquals("incorrect idle ms", 70, accumulator.maxIdleMillis());
43 } 44 }
44 45
45 - @Ignore("FIXME: timing sensitive test failing randomly.")
46 @Test 46 @Test
47 public void eventTrigger() { 47 public void eventTrigger() {
48 TestAccumulator accumulator = new TestAccumulator(); 48 TestAccumulator accumulator = new TestAccumulator();
...@@ -52,43 +52,40 @@ public class AbstractAccumulatorTest { ...@@ -52,43 +52,40 @@ public class AbstractAccumulatorTest {
52 accumulator.add(new TestItem("d")); 52 accumulator.add(new TestItem("d"));
53 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 53 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
54 accumulator.add(new TestItem("e")); 54 accumulator.add(new TestItem("e"));
55 - delay(20); 55 + timer.advanceTimeMillis(20, 10);
56 assertFalse("should have fired", accumulator.batch.isEmpty()); 56 assertFalse("should have fired", accumulator.batch.isEmpty());
57 assertEquals("incorrect batch", "abcde", accumulator.batch); 57 assertEquals("incorrect batch", "abcde", accumulator.batch);
58 } 58 }
59 59
60 - @Ignore("FIXME: timing sensitive test failing randomly.")
61 @Test 60 @Test
62 public void timeTrigger() { 61 public void timeTrigger() {
63 TestAccumulator accumulator = new TestAccumulator(); 62 TestAccumulator accumulator = new TestAccumulator();
64 accumulator.add(new TestItem("a")); 63 accumulator.add(new TestItem("a"));
65 - delay(30); 64 + timer.advanceTimeMillis(30, 1);
66 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 65 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
67 accumulator.add(new TestItem("b")); 66 accumulator.add(new TestItem("b"));
68 - delay(30); 67 + timer.advanceTimeMillis(30, 1);
69 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 68 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
70 accumulator.add(new TestItem("c")); 69 accumulator.add(new TestItem("c"));
71 - delay(30); 70 + timer.advanceTimeMillis(30, 1);
72 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 71 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
73 accumulator.add(new TestItem("d")); 72 accumulator.add(new TestItem("d"));
74 - delay(60); 73 + timer.advanceTimeMillis(10, 10);
75 assertFalse("should have fired", accumulator.batch.isEmpty()); 74 assertFalse("should have fired", accumulator.batch.isEmpty());
76 assertEquals("incorrect batch", "abcd", accumulator.batch); 75 assertEquals("incorrect batch", "abcd", accumulator.batch);
77 } 76 }
78 77
79 - @Ignore("FIXME: timing sensitive test failing randomly.")
80 @Test 78 @Test
81 public void idleTrigger() { 79 public void idleTrigger() {
82 TestAccumulator accumulator = new TestAccumulator(); 80 TestAccumulator accumulator = new TestAccumulator();
83 accumulator.add(new TestItem("a")); 81 accumulator.add(new TestItem("a"));
84 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 82 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
85 accumulator.add(new TestItem("b")); 83 accumulator.add(new TestItem("b"));
86 - delay(80); 84 + timer.advanceTimeMillis(70, 10);
87 assertFalse("should have fired", accumulator.batch.isEmpty()); 85 assertFalse("should have fired", accumulator.batch.isEmpty());
88 assertEquals("incorrect batch", "ab", accumulator.batch); 86 assertEquals("incorrect batch", "ab", accumulator.batch);
89 } 87 }
90 88
91 - @Ignore("FIXME: timing sensitive test failing randomly.")
92 @Test 89 @Test
93 public void readyIdleTrigger() { 90 public void readyIdleTrigger() {
94 TestAccumulator accumulator = new TestAccumulator(); 91 TestAccumulator accumulator = new TestAccumulator();
...@@ -96,30 +93,28 @@ public class AbstractAccumulatorTest { ...@@ -96,30 +93,28 @@ public class AbstractAccumulatorTest {
96 accumulator.add(new TestItem("a")); 93 accumulator.add(new TestItem("a"));
97 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 94 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
98 accumulator.add(new TestItem("b")); 95 accumulator.add(new TestItem("b"));
99 - delay(80); 96 + timer.advanceTimeMillis(80, 1);
100 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 97 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
101 accumulator.ready = true; 98 accumulator.ready = true;
102 - delay(80); 99 + timer.advanceTimeMillis(80, 10);
103 assertFalse("should have fired", accumulator.batch.isEmpty()); 100 assertFalse("should have fired", accumulator.batch.isEmpty());
104 assertEquals("incorrect batch", "ab", accumulator.batch); 101 assertEquals("incorrect batch", "ab", accumulator.batch);
105 } 102 }
106 103
107 - @Ignore("FIXME: timing sensitive test failing randomly.")
108 @Test 104 @Test
109 public void readyLongTrigger() { 105 public void readyLongTrigger() {
110 TestAccumulator accumulator = new TestAccumulator(); 106 TestAccumulator accumulator = new TestAccumulator();
111 accumulator.ready = false; 107 accumulator.ready = false;
112 - delay(120); 108 + timer.advanceTimeMillis(120, 1);
113 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 109 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
114 accumulator.add(new TestItem("a")); 110 accumulator.add(new TestItem("a"));
115 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 111 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
116 accumulator.ready = true; 112 accumulator.ready = true;
117 - delay(80); 113 + timer.advanceTimeMillis(120, 10);
118 assertFalse("should have fired", accumulator.batch.isEmpty()); 114 assertFalse("should have fired", accumulator.batch.isEmpty());
119 assertEquals("incorrect batch", "a", accumulator.batch); 115 assertEquals("incorrect batch", "a", accumulator.batch);
120 } 116 }
121 117
122 - @Ignore("FIXME: timing sensitive test failing randomly.")
123 @Test 118 @Test
124 public void readyMaxTrigger() { 119 public void readyMaxTrigger() {
125 TestAccumulator accumulator = new TestAccumulator(); 120 TestAccumulator accumulator = new TestAccumulator();
...@@ -133,16 +128,16 @@ public class AbstractAccumulatorTest { ...@@ -133,16 +128,16 @@ public class AbstractAccumulatorTest {
133 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 128 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
134 accumulator.ready = true; 129 accumulator.ready = true;
135 accumulator.add(new TestItem("g")); 130 accumulator.add(new TestItem("g"));
136 - delay(5); 131 + timer.advanceTimeMillis(10, 10);
137 assertFalse("should have fired", accumulator.batch.isEmpty()); 132 assertFalse("should have fired", accumulator.batch.isEmpty());
138 assertEquals("incorrect batch", "abcdefg", accumulator.batch); 133 assertEquals("incorrect batch", "abcdefg", accumulator.batch);
139 } 134 }
140 135
141 - @Ignore("FIXME: timing sensitive test failing randomly.")
142 @Test 136 @Test
143 public void stormTest() { 137 public void stormTest() {
144 TestAccumulator accumulator = new TestAccumulator(); 138 TestAccumulator accumulator = new TestAccumulator();
145 IntStream.range(0, 1000).forEach(i -> accumulator.add(new TestItem("#" + i))); 139 IntStream.range(0, 1000).forEach(i -> accumulator.add(new TestItem("#" + i)));
140 + timer.advanceTimeMillis(1);
146 assertAfter(100, () -> assertEquals("wrong item count", 1000, accumulator.itemCount)); 141 assertAfter(100, () -> assertEquals("wrong item count", 1000, accumulator.itemCount));
147 assertEquals("wrong batch count", 200, accumulator.batchCount); 142 assertEquals("wrong batch count", 200, accumulator.batchCount);
148 } 143 }
...@@ -180,5 +175,4 @@ public class AbstractAccumulatorTest { ...@@ -180,5 +175,4 @@ public class AbstractAccumulatorTest {
180 return ready; 175 return ready;
181 } 176 }
182 } 177 }
183 -
184 } 178 }
......
1 +/*
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 +
17 +package org.onlab.util;
18 +
19 +import com.google.common.collect.Lists;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +
23 +import java.util.ArrayList;
24 +import java.util.Date;
25 +import java.util.TimerTask;
26 +import java.util.concurrent.atomic.AtomicInteger;
27 +
28 +import static org.junit.Assert.assertEquals;
29 +import static org.junit.Assert.assertFalse;
30 +import static org.junit.Assert.assertTrue;
31 +import static org.onlab.junit.TestTools.delay;
32 +
33 +/**
34 + * Testing class for manually advancing timer.
35 + */
36 +public 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 +}
...\ No newline at end of file ...\ No newline at end of file