aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java
blob: 36b50e678e60b471ab7873f786dae685500a8379 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
 * 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;
        }
    }
}