2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.pap.main.comm;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import java.util.concurrent.Semaphore;
31 import java.util.concurrent.TimeUnit;
32 import java.util.function.Consumer;
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.onap.policy.pap.main.comm.TimerManager.Timer;
38 public class TimerManagerTest extends Threaded {
39 private static final String EXPECTED_EXCEPTION = "expected exception";
40 private static final String MGR_NAME = "my-manager";
41 private static final String NAME1 = "timer-A";
42 private static final String NAME2 = "timer-B";
43 private static final String NAME3 = "timer-C";
45 private static final long MGR_TIMEOUT_MS = 10000;
47 private MyManager mgr;
50 * This is a field rather than a local variable to prevent checkstyle from complaining
51 * about the distance between its assignment and its use.
58 * @throws Exception if an error occurs
61 public void setUp() throws Exception {
64 mgr = new MyManager(MGR_NAME, MGR_TIMEOUT_MS);
68 public void tearDown() throws Exception {
73 protected void stopThread() throws Exception {
81 public void testTimerManager_testStop() throws Exception {
85 assertTrue(waitStop());
87 // ensure we can call "stop" a second time
92 public void testRegister() throws Exception {
93 mgr.register(NAME2, mgr::addToQueue);
94 mgr.registerNewTime(NAME1, mgr::addToQueue);
96 // goes to the end of the queue
97 mgr.registerNewTime(NAME2, mgr::addToQueue);
103 assertEquals(NAME1, mgr.awaitTimer());
104 assertEquals(NAME2, mgr.awaitTimer());
108 public void testRun_Ex() throws Exception {
110 mgr.register(NAME1, mgr::addToQueue);
114 // background thread is "sleeping" - now we can interrupt it
117 assertTrue(waitStop());
121 public void testProcessTimers() throws Exception {
123 mgr.register(NAME1, mgr::addToQueue);
127 mgr.registerNewTime(NAME2, mgr::addToQueue);
130 // tell it to stop before returning from "sleep"
134 assertTrue(waitStop());
136 assertEquals(NAME1, mgr.pollTimer());
137 assertNull(mgr.pollTimer());
141 public void testGetNextTimer() throws Exception {
143 mgr.register(NAME1, mgr::addToQueue);
147 mgr.registerNewTime(NAME2, mgr::addToQueue);
152 public void testProcessTimer_StopWhileWaiting() throws Exception {
154 mgr.register(NAME1, mgr::addToQueue);
158 mgr.registerNewTime(NAME2, mgr::addToQueue);
164 assertTrue(waitStop());
166 // should have stopped after processing the first timer
167 assertEquals(NAME1, mgr.pollTimer());
168 assertNull(mgr.pollTimer());
172 public void testProcessTimer_CancelWhileWaiting() throws Exception {
174 Timer timer = mgr.register(NAME1, mgr::addToQueue);
180 mgr.registerNewTime(NAME2, mgr::addToQueue);
184 mgr.registerNewTime(NAME1, mgr::addToQueue);
187 // should have fired timer 2, but not timer 1
188 assertEquals(NAME2, mgr.pollTimer());
189 assertNull(mgr.pollTimer());
193 public void testProcessTimer_TimerEx() throws Exception {
195 mgr.register(NAME1, name -> {
196 throw new RuntimeException(EXPECTED_EXCEPTION);
199 mgr.register(NAME2, mgr::addToQueue);
201 // same times, so only need one sleep
206 mgr.registerNewTime(NAME3, mgr::addToQueue);
209 // timer 1 fired but threw an exception, so only timer 2 should be in the queue
210 assertEquals(NAME2, mgr.pollTimer());
214 public void testTimerAwait() throws Exception {
217 // same times - should only sleep once
218 mgr.register(NAME1, mgr::addToQueue);
219 mgr.register(NAME2, mgr::addToQueue);
222 tcur = mgr.currentTimeMillis();
226 // next one will have a new timeout, so expect to sleep again
227 mgr.registerNewTime(NAME3, mgr::addToQueue);
230 long tcur2 = mgr.currentTimeMillis();
231 assertTrue(tcur2 >= tcur + MGR_TIMEOUT_MS);
233 assertEquals(NAME1, mgr.pollTimer());
234 assertEquals(NAME2, mgr.pollTimer());
235 assertNull(mgr.pollTimer());
239 public void testTimerCancel_WhileWaiting() throws Exception {
242 Timer timer = mgr.register(NAME1, mgr::addToQueue);
245 // cancel while sleeping
248 mgr.registerNewTime(NAME2, mgr::addToQueue);
250 // allow it to sleep through both timers
253 // only timer 2 should have fired
254 assertEquals(NAME2, mgr.awaitTimer());
258 public void testTimerCancel_ViaReplace() throws Exception {
261 mgr.register(NAME1, name -> mgr.addToQueue("hello"));
264 // replace the timer while the background thread is sleeping
265 mgr.registerNewTime(NAME1, name -> mgr.addToQueue("world"));
267 // allow it to sleep through both timers
270 // only timer 2 should have fired
271 assertEquals("world", mgr.awaitTimer());
275 public void testTimerToString() {
276 Timer timer = mgr.register(NAME1, mgr::addToQueue);
277 assertNotNull(timer.toString());
278 assertTrue(timer.toString().contains(NAME1));
282 public void testCurrentTimeMillis() {
283 long tbeg = System.currentTimeMillis();
284 long tcur = new TimerManager(MGR_NAME, MGR_TIMEOUT_MS).currentTimeMillis();
285 long tend = System.currentTimeMillis();
287 assertTrue(tcur >= tbeg);
288 assertTrue(tend >= tcur);
292 public void testSleep() throws Exception {
293 long tbeg = System.currentTimeMillis();
294 new TimerManager(MGR_NAME, MGR_TIMEOUT_MS).sleep(10);
295 long tend = System.currentTimeMillis();
297 assertTrue(tend >= tbeg + 10);
302 * Timer Manager whose notions of time are controlled here. It also overrides the
303 * {@link #sleep(long)} method so that the test thread can control when the background
304 * timer thread finishes sleeping.
306 private static class MyManager extends TimerManager {
307 private final Object lockit = new Object();
308 private long curTime = 1000;
309 private int offset = 0;
310 private final Semaphore sleepEntered = new Semaphore(0);
311 private final Semaphore sleepsAllowed = new Semaphore(0);
312 private final LinkedBlockingQueue<String> results = new LinkedBlockingQueue<>();
314 public MyManager(String name, long waitTimeMs) {
315 super(name, waitTimeMs);
319 * Registers a timer with a new starting time. Because the manager uses the
320 * current time when determining the expiration time, we have to temporarily
321 * fiddle with {@link #curTime}, but we leave it unchanged when we're done.
322 * Increases the {@link #offset} each time it's invoked.
324 * @return the new timer
326 public Timer registerNewTime(String timerName, Consumer<String> action) {
327 synchronized (lockit) {
331 Timer timer = super.register(timerName, action);
339 * Allows the manager to "sleep" several times.
341 * @param ntimes the number of times the manager should sleep
343 public void allowSleep(int ntimes) {
344 sleepsAllowed.release(ntimes);
348 * Waits for the manager to "sleep".
350 * @throws InterruptedException if the thread is interrupted while waiting for the
351 * background thread to sleep
353 public void awaitSleep() throws InterruptedException {
354 if (!sleepEntered.tryAcquire(MAX_WAIT_MS, TimeUnit.MILLISECONDS)) {
355 fail("background thread failed to sleep");
360 protected long currentTimeMillis() {
361 synchronized (lockit) {
367 protected void sleep(long timeMs) throws InterruptedException {
368 sleepEntered.release();
369 sleepsAllowed.acquire();
371 synchronized (lockit) {
377 * Waits for a timer to fire.
379 * @return the message the timer added to {@link #results}
380 * @throws InterruptedException if this thread is interrupted while waiting
382 private String awaitTimer() throws InterruptedException {
383 return results.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS);
387 * Adds a name to the queue.
389 * @param name the name to add
391 private void addToQueue(String name) {
396 * Polls to see if a timer has fired.
398 * @return the message the timer added to {@link #results}, or {@code null} if no
399 * timer has fired yet
401 private String pollTimer() {
402 return results.poll();