Repository: incubator-geode Updated Branches: refs/heads/develop ff9b2f05f -> 9efe74e4c
GEODE-228: fix intermittent failures in NanoTimer tests - NanoTimer2JUnitTest has been removed since it was an old test that has been replaced by NanoTimerJUnitTest. - NanoTimer can now be constructed with a TimeService. This allows unit tests to insert a different clock. - NanoTimerJUnitTest now uses its own TimeService when testing NanoTimer which prevents intermittent failures. Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/9efe74e4 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/9efe74e4 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/9efe74e4 Branch: refs/heads/develop Commit: 9efe74e4cfc8e7130b538cd67b9ec315c5fcec7a Parents: ff9b2f0 Author: Darrel Schneider <dschnei...@pivotal.io> Authored: Wed Aug 19 10:46:59 2015 -0700 Committer: Darrel Schneider <dschnei...@pivotal.io> Committed: Wed Aug 19 14:07:33 2015 -0700 ---------------------------------------------------------------------- .../gemstone/gemfire/internal/NanoTimer.java | 37 +++++- .../gemfire/internal/NanoTimer2JUnitTest.java | 79 ------------ .../gemfire/internal/NanoTimerJUnitTest.java | 121 +++++++++---------- 3 files changed, 88 insertions(+), 149 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9efe74e4/gemfire-core/src/main/java/com/gemstone/gemfire/internal/NanoTimer.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/NanoTimer.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/NanoTimer.java index d0055dd..f9a04ed 100644 --- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/NanoTimer.java +++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/NanoTimer.java @@ -48,11 +48,30 @@ public final class NanoTimer { */ private long lastResetTime; + private final TimeService timeService; + + private final static TimeService systemTimeService = new TimeService() { + @Override + public long getTime() { + return java.lang.System.nanoTime(); + } + }; + /** * Create a NanoTimer. */ public NanoTimer() { - this.lastResetTime = getTime(); + this.timeService = systemTimeService; + this.lastResetTime = systemTimeService.getTime(); + this.constructionTime = this.lastResetTime; + } + + /** + * For unit testing + */ + NanoTimer(TimeService ts) { + this.timeService = ts; + this.lastResetTime = ts.getTime(); this.constructionTime = this.lastResetTime; } @@ -121,7 +140,7 @@ public final class NanoTimer { */ public long reset() { long save = this.lastResetTime; - this.lastResetTime = getTime(); + this.lastResetTime = this.timeService.getTime(); return this.lastResetTime - save; } @@ -132,7 +151,7 @@ public final class NanoTimer { * @return time in nanoseconds since construction or last reset. */ public long getTimeSinceReset() { - return getTime() - this.lastResetTime; + return this.timeService.getTime() - this.lastResetTime; } /** @@ -142,7 +161,17 @@ public final class NanoTimer { * @return time in nanoseconds since construction. */ public long getTimeSinceConstruction() { - return getTime() - this.constructionTime; + return this.timeService.getTime() - this.constructionTime; + } + + /** + * Allows unit tests to insert a deterministic clock for testing. + */ + interface TimeService { + /** + * Returns the current time. + */ + public long getTime(); } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9efe74e4/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimer2JUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimer2JUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimer2JUnitTest.java deleted file mode 100644 index fe243fb..0000000 --- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimer2JUnitTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/*========================================================================= - * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. - * This product is protected by U.S. and international copyright - * and intellectual property laws. Pivotal products are covered by - * one or more patents listed at http://www.pivotal.io/patents. - *========================================================================= - */ -package com.gemstone.gemfire.internal; - -import org.junit.experimental.categories.Category; - -import com.gemstone.gemfire.test.junit.categories.UnitTest; - -import junit.framework.*; - -/** - * Unit tests for NanoTimer - */ -@Category(UnitTest.class) -public class NanoTimer2JUnitTest extends TestCase { - - public NanoTimer2JUnitTest(String name) { - super(name); - } - /////////////////////// Test Methods /////////////////////// - - private void _testGetTime(int waitTimeSeconds) { - final int nanosPerMilli = 1000000; - long start = NanoTimer.getTime(); - long startMillis = System.currentTimeMillis(); - try { - Thread.sleep(waitTimeSeconds * 1000); - } catch (InterruptedException e) { - fail("interrupted"); - } - long end = NanoTimer.getTime(); - long endMillis = System.currentTimeMillis(); - long elapsed = (end - start); - long elapsedMillis = endMillis - startMillis; - assertApproximate("expected approximately " + waitTimeSeconds + " seconds", nanosPerMilli*30, - elapsedMillis * nanosPerMilli, elapsed); - } - public void testGetTime() { - _testGetTime(2); - } - - private long calculateSlop() { - // calculate how much time this vm takes to do some basic stuff. - long startTime = NanoTimer.getTime(); - new NanoTimer(); - assertApproximate("should never fail", 0, 0, 0); - long result = NanoTimer.getTime() - startTime; - return result * 3; // triple to be on the safe side - } - - public void testReset() { - final long slop = calculateSlop(); - NanoTimer nt = new NanoTimer(); - long createTime = NanoTimer.getTime(); - assertApproximate("create time", slop, 0, nt.getTimeSinceConstruction()); - assertApproximate("construction vs. reset", slop, nt.getTimeSinceConstruction(), nt.getTimeSinceReset()); - assertApproximate("time since reset time same as construct", slop, NanoTimer.getTime() - createTime, nt.getTimeSinceReset()); - assertApproximate("reset time same as construct", slop, NanoTimer.getTime() - createTime, nt.reset()); - long resetTime = NanoTimer.getTime(); - assertApproximate("reset time updated", slop, NanoTimer.getTime() - resetTime, nt.getTimeSinceReset()); - } - - /** - * Checks to see if actual is within range nanos of expected. - */ - private static void assertApproximate(String message, long range, - long expected, long actual) { - if ((actual < (expected - range)) || (actual > (expected + range))) { - fail(message + " expected to be in the range [" - + (expected - range) + ".." + (expected + range) - + "] but was:<" + actual + ">"); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/9efe74e4/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimerJUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimerJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimerJUnitTest.java index 16b423a..6e25ca8 100755 --- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimerJUnitTest.java +++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/NanoTimerJUnitTest.java @@ -12,125 +12,114 @@ import static org.junit.Assert.*; import org.junit.Test; import org.junit.experimental.categories.Category; +import com.gemstone.gemfire.internal.NanoTimer.TimeService; import com.gemstone.gemfire.internal.util.StopWatch; import com.gemstone.gemfire.test.junit.categories.UnitTest; /** - * Unit tests for NanoTimer. This is in addition to NanoTimer2JUnitTest which is - * an older a JUnit test case for NanoTimer. + * Unit tests for NanoTimer. * * @author Kirk Lund * @since 7.0 - * @see NanoTimer2JUnitTest */ @Category(UnitTest.class) public class NanoTimerJUnitTest { + + /** + * Simple deterministic clock. Any time you want + * your clock to tick call incTime. + */ + private class TestTimeService implements TimeService { + private long now; + public void incTime() { + this.now++; + } + @Override + public long getTime() { + return this.now; + } + } @Test - public void testGetTimeIsPositive() { - long lastTime = 0; - for (int i = 0; i < 1000; i++) { - final long time = NanoTimer.getTime(); - assertTrue(time >= 0); - assertTrue(time >= lastTime); - lastTime = time; - } + public void testMillisToNanos() { + assertEquals(0, NanoTimer.millisToNanos(0)); + assertEquals(1000000, NanoTimer.millisToNanos(1)); + } + + @Test + public void testNanosToMillis() { + assertEquals(0, NanoTimer.nanosToMillis(1)); + assertEquals(1, NanoTimer.nanosToMillis(1000000)); } @Test - public void testGetTimeIncreases() { - final long startNanos = NanoTimer.getTime(); - final long startMillis = System.currentTimeMillis(); - - waitMillis(10); - - final long endMillis = System.currentTimeMillis(); - final long endNanos = NanoTimer.getTime(); - - long elapsedMillis = endMillis - startMillis; - long elapsedNanos = endNanos - startNanos; - - assertTrue(elapsedMillis > 10); - assertTrue(endNanos > NanoTimer.NANOS_PER_MILLISECOND * 10); - assertTrue(elapsedNanos * NanoTimer.NANOS_PER_MILLISECOND >= elapsedMillis); + public void testDefaultNanoTimer() { + // All the other unit test methods of NanoTimer + // inject TestTimeService into the NanoTimer. + // This method verifies that the default constructor + // works. + final NanoTimer timer = new NanoTimer(); + timer.getConstructionTime(); + timer.getLastResetTime(); + timer.getTimeSinceConstruction(); + timer.getTimeSinceReset(); + timer.reset(); } @Test public void testInitialTimes() { - final long nanoTime = NanoTimer.getTime(); - final NanoTimer timer = new NanoTimer(); + TestTimeService ts = new TestTimeService(); + final long nanoTime = ts.getTime(); + final NanoTimer timer = new NanoTimer(ts); assertEquals(timer.getConstructionTime(), timer.getLastResetTime()); assertTrue(timer.getTimeSinceConstruction() <= timer.getTimeSinceReset()); assertTrue(timer.getLastResetTime() >= nanoTime); assertTrue(timer.getConstructionTime() >= nanoTime); - assertTrue(NanoTimer.getTime() >= nanoTime); + assertTrue(ts.getTime() >= nanoTime); - final long nanosOne = NanoTimer.getTime(); - - waitMillis(10); - - assertTrue(timer.getTimeSinceConstruction() > NanoTimer.NANOS_PER_MILLISECOND * 10); - assertTrue(timer.getTimeSinceConstruction() <= NanoTimer.getTime()); + final long nanosOne = ts.getTime(); - final long nanosTwo = NanoTimer.getTime(); + ts.incTime(); - assertTrue(timer.getTimeSinceConstruction() >= nanosTwo - nanosOne); + assertEquals(1, timer.getTimeSinceConstruction()); } @Test public void testReset() { - final NanoTimer timer = new NanoTimer(); - final long nanosOne = NanoTimer.getTime(); + TestTimeService ts = new TestTimeService(); + final NanoTimer timer = new NanoTimer(ts); + final long nanosOne = ts.getTime(); - waitMillis(10); + ts.incTime(); assertEquals(timer.getConstructionTime(), timer.getLastResetTime()); assertTrue(timer.getTimeSinceConstruction() <= timer.getTimeSinceReset()); - final long nanosTwo = NanoTimer.getTime(); + final long nanosTwo = ts.getTime(); final long resetOne = timer.reset(); assertTrue(resetOne >= nanosTwo - nanosOne); assertFalse(timer.getConstructionTime() == timer.getLastResetTime()); - final long nanosThree = NanoTimer.getTime(); + final long nanosThree = ts.getTime(); - waitMillis(10); + ts.incTime(); assertTrue(timer.getLastResetTime() >= nanosTwo); assertTrue(timer.getTimeSinceReset() < timer.getTimeSinceConstruction()); assertTrue(timer.getLastResetTime() <= nanosThree); - assertTrue(timer.getTimeSinceReset() < NanoTimer.getTime()); - assertTrue(timer.getTimeSinceReset() <= NanoTimer.getTime() - timer.getLastResetTime()); + assertTrue(timer.getTimeSinceReset() <= ts.getTime() - timer.getLastResetTime()); - final long nanosFour = NanoTimer.getTime(); + final long nanosFour = ts.getTime(); final long resetTwo = timer.reset(); assertTrue(resetTwo >= nanosFour - nanosThree); - waitMillis(10); + ts.incTime(); assertTrue(timer.getLastResetTime() >= nanosFour); assertTrue(timer.getTimeSinceReset() < timer.getTimeSinceConstruction()); - assertTrue(timer.getLastResetTime() <= NanoTimer.getTime()); - assertTrue(timer.getTimeSinceReset() <= NanoTimer.getTime() - timer.getLastResetTime()); - } - - /** - * Waits for the specified milliseconds to pass as measured by - * {@link java.lang.System#currentTimeMillis()}. - */ - private void waitMillis(final long millis) { - long began = System.currentTimeMillis(); - boolean done = false; - try { - for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < millis; done = (System.currentTimeMillis() - began > millis)) { - Thread.sleep(1000); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - assertTrue("waiting " + millis + " millis", done); + assertTrue(timer.getTimeSinceReset() <= ts.getTime() - timer.getLastResetTime()); } }