/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.brooklyn.util.time; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import java.util.Arrays; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.time.CountdownTimer; import org.apache.brooklyn.util.time.Duration; import org.apache.brooklyn.util.time.Time; import org.testng.annotations.Test; import com.google.common.base.Stopwatch; @Test public class CountdownTimerTest { // Test failed on jenkins when using 1 second, sleeping for 500ms; // hence relaxing time constraints so is less time-sensitive at the expense of being a slower test. @Test(groups="Integration") public void testSimpleExpiry() { final int TOTAL_TIME_MS = 5*1000; final int OVERHEAD_MS = 2000; final int EARLY_RETURN_GRACE_MS = 30; final int FIRST_SLEEP_TIME_MS = 2500; final int SECOND_SLEEP_TIME_MS = TOTAL_TIME_MS - FIRST_SLEEP_TIME_MS + EARLY_RETURN_GRACE_MS*2; final Duration SIMPLE_DURATION = Duration.millis(TOTAL_TIME_MS); CountdownTimer timer = SIMPLE_DURATION.countdownTimer(); assertFalse(timer.isExpired()); assertTrue(timer.isNotExpired()); assertTrue(timer.isLive()); assertTrue(timer.isNotPaused()); assertTrue(timer.getDurationElapsed().toMilliseconds() <= OVERHEAD_MS, "elapsed="+timer.getDurationElapsed().toMilliseconds()); assertTrue(timer.getDurationRemaining().toMilliseconds() >= TOTAL_TIME_MS - OVERHEAD_MS, "remaining="+timer.getDurationElapsed().toMilliseconds()); Time.sleep(Duration.millis(FIRST_SLEEP_TIME_MS)); assertFalse(timer.isExpired()); assertOrdered(FIRST_SLEEP_TIME_MS - EARLY_RETURN_GRACE_MS, timer.getDurationElapsed().toMilliseconds(), FIRST_SLEEP_TIME_MS + OVERHEAD_MS); assertOrdered(TOTAL_TIME_MS - FIRST_SLEEP_TIME_MS - OVERHEAD_MS, timer.getDurationRemaining().toMilliseconds(), TOTAL_TIME_MS - FIRST_SLEEP_TIME_MS + EARLY_RETURN_GRACE_MS); Time.sleep(Duration.millis(SECOND_SLEEP_TIME_MS)); assertTrue(timer.isExpired()); assertFalse(timer.isNotExpired()); assertFalse(timer.isLive()); assertTrue(timer.isNotPaused()); } public void testNotify() throws InterruptedException { CountdownTimer timer = Duration.FIVE_SECONDS.countdownTimer(); final Object mutex = new Object(); final Semaphore gun = new Semaphore(0); Stopwatch watch = Stopwatch.createStarted(); new Thread(new Runnable() { @Override public void run() { try { gun.acquire(); } catch (Exception e) { throw Exceptions.propagate(e); } synchronized (mutex) { mutex.notifyAll(); } } }).start(); synchronized (mutex) { gun.release(); assertTrue(timer.waitOnForExpiry(mutex)); } assertTrue(watch.elapsed(TimeUnit.MILLISECONDS) < 3000, "took too long: "+watch); } private void assertOrdered(long... vals) { String errmsg = "vals="+Arrays.toString(vals); long prevVal = Long.MIN_VALUE; for (long val : vals) { assertTrue(val >= prevVal, errmsg); prevVal = val; } } }