From 0dc908c79c5770edc57bd513a663996f65ede3de Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 18 Aug 2019 09:27:18 +0200 Subject: [PATCH] show the removal listener of HotEntryCache is not called on expire --- .../utils/cache/HotEntryCacheTest.java | 331 ++---------------- 1 file changed, 30 insertions(+), 301 deletions(-) diff --git a/pdb-utils/src/test/java/org/lucares/utils/cache/HotEntryCacheTest.java b/pdb-utils/src/test/java/org/lucares/utils/cache/HotEntryCacheTest.java index 3971e6b..f084788 100644 --- a/pdb-utils/src/test/java/org/lucares/utils/cache/HotEntryCacheTest.java +++ b/pdb-utils/src/test/java/org/lucares/utils/cache/HotEntryCacheTest.java @@ -1,301 +1,30 @@ -//package org.lucares.utils.cache; -// -//import java.time.Duration; -//import java.time.Instant; -//import java.util.ArrayList; -//import java.util.Arrays; -//import java.util.List; -//import java.util.concurrent.CompletableFuture; -//import java.util.concurrent.CountDownLatch; -//import java.util.concurrent.ExecutionException; -//import java.util.concurrent.ExecutorService; -//import java.util.concurrent.Executors; -//import java.util.concurrent.TimeUnit; -//import java.util.concurrent.TimeoutException; -// -//import org.apache.logging.log4j.Level; -//import org.apache.logging.log4j.core.config.Configurator; -//import org.lucares.utils.cache.HotEntryCache.EventType; -//import org.testng.Assert; -//import org.testng.annotations.Test; -// -//@Test -//public class HotEntryCacheTest { -// public void testPutAndGet() throws InterruptedException, ExecutionException, TimeoutException { -// final HotEntryCache cache = new HotEntryCache<>(Duration.ofSeconds(10)); -// -// final String replacedNull = cache.put("key", "value1"); -// Assert.assertEquals(replacedNull, null); -// -// final String cachedValue1 = cache.get("key"); -// Assert.assertEquals(cachedValue1, "value1"); -// -// final String replacedValue1 = cache.put("key", "value2"); -// Assert.assertEquals(replacedValue1, "value1"); -// -// final String cachedValue2 = cache.get("key"); -// Assert.assertEquals(cachedValue2, "value2"); -// } -// -// public void testPutTouches() throws InterruptedException, ExecutionException, TimeoutException { -// final ModifiableFixedTimeClock clock = new ModifiableFixedTimeClock(); -// final Duration timeToLive = Duration.ofSeconds(10); -// final HotEntryCache cache = new HotEntryCache<>(timeToLive, clock); -// -// cache.put("key", "value1"); -// -// clock.plusSeconds(2); -// cache.updateTime(); -// -// cache.put("key", "value2"); -// -// clock.plus(timeToLive.minusSeconds(1)); -// cache.triggerEvictionAndWait(); -// // at this point the entry would have been evicted it it was not touched by the -// // second put. -// -// final String cachedValue2 = cache.get("key"); -// Assert.assertEquals(cachedValue2, "value2"); -// -// clock.plus(timeToLive.plusSeconds(1)); -// // time elapsed since the last put: timeToLive +1s -// cache.triggerEvictionAndWait(); -// -// final String cachedValue1_evicted = cache.get("key"); -// Assert.assertEquals(cachedValue1_evicted, null); -// } -// -// public void testGetTouches() throws Exception { -// final ModifiableFixedTimeClock clock = new ModifiableFixedTimeClock(); -// final Duration timeToLive = Duration.ofSeconds(10); -// final HotEntryCache cache = new HotEntryCache<>(timeToLive, clock); -// -// cache.put("key", "value1"); -// -// // skip forward in time, but do not yet trigger eviction -// clock.plus(timeToLive.plusMillis(1)); -// cache.updateTime(); -// -// cache.get("key"); // will touch the entry -// -// cache.triggerEvictionAndWait(); // if get didn't touch, then this will evict the entry -// -// final String cachedValue1 = cache.get("key"); -// Assert.assertEquals(cachedValue1, "value1"); -// } -// -// public void testEvictionByBackgroundThread() throws InterruptedException, ExecutionException, TimeoutException { -// final ModifiableFixedTimeClock clock = new ModifiableFixedTimeClock(); -// final Duration timeToLive = Duration.ofSeconds(10); -// final HotEntryCache cache = new HotEntryCache<>(timeToLive, clock); -// -// final CompletableFuture evictionEventFuture = new CompletableFuture<>(); -// cache.addListener(event -> { -// evictionEventFuture.complete(event.getValue()); -// }, EventType.EVICTED); -// -// cache.put("key", "value1"); -// -// clock.plus(timeToLive.minusSeconds(1)); -// cache.updateTime(); -// -// cache.put("key2", "value2"); -// clock.plus(Duration.ofSeconds(1).plusMillis(1)); -// cache.triggerEvictionAndWait(); -// -// final String evictedValue1 = evictionEventFuture.get(5, TimeUnit.MINUTES); // enough time for debugging -// Assert.assertEquals(evictedValue1, "value1"); -// } -// -// public void testRemove() throws InterruptedException, ExecutionException, TimeoutException { -// final HotEntryCache cache = new HotEntryCache<>(Duration.ofSeconds(10)); -// -// final List removedValues = new ArrayList<>(); -// cache.addListener(event -> removedValues.add(event.getValue()), EventType.REMOVED); -// -// cache.put("key", "value1"); -// -// final String removedValue = cache.remove("key"); -// Assert.assertEquals(removedValue, "value1"); -// -// Assert.assertEquals(removedValues, Arrays.asList("value1")); -// -// Assert.assertEquals(cache.get("key"), null); -// } -// -// public void testClear() throws InterruptedException, ExecutionException, TimeoutException { -// final HotEntryCache cache = new HotEntryCache<>(Duration.ofSeconds(10)); -// -// final List removedValues = new ArrayList<>(); -// cache.addListener(event -> removedValues.add(event.getValue()), EventType.REMOVED); -// -// cache.put("key1", "value1"); -// cache.put("key2", "value2"); -// -// cache.clear(); -// -// Assert.assertEquals(cache.get("key1"), null); -// Assert.assertEquals(cache.get("key2"), null); -// -// Assert.assertEquals(removedValues, Arrays.asList("value1", "value2")); -// } -// -// public void testForEachTouches() throws InterruptedException, ExecutionException, TimeoutException { -// final ModifiableFixedTimeClock clock = new ModifiableFixedTimeClock(); -// final Duration timeToLive = Duration.ofSeconds(10); -// final HotEntryCache cache = new HotEntryCache<>(timeToLive, clock); -// -// final CompletableFuture evictionEventFuture = new CompletableFuture<>(); -// cache.addListener(event -> { -// evictionEventFuture.complete(event.getValue()); -// }, EventType.EVICTED); -// -// // add value -// cache.put("key", "value1"); -// -// // seek, so that it is almost evicted -// clock.plus(timeToLive.minusMillis(1)); -// cache.updateTime(); -// -// // the for each should touch the entries -// cache.forEach(s -> { -// /* no-op */}); -// -// // seek again -// clock.plus(timeToLive.minusMillis(1)); -// cache.triggerEvictionAndWait(); -// -// // if the touch didn't happen, then the value is now evicted -// Assert.assertEquals(evictionEventFuture.isDone(), false); -// -// // seek again, so that the entry will get evicted -// clock.plus(timeToLive.minusMillis(1)); -// cache.triggerEvictionAndWait(); -// -// Assert.assertEquals(cache.get("key"), null); -// } -// -// /** -// * Checks that -// * {@link HotEntryCache#putIfAbsent(Object, java.util.function.Function) -// * putIfAbsent} is atomic by calling -// * {@link HotEntryCache#putIfAbsent(Object, java.util.function.Function) -// * putIfAbsent} in two threads and asserting that the supplier was only called -// * once. -// * -// * @throws Exception -// */ -// public void testPutIfAbsentIsAtomic() throws Exception { -// final HotEntryCache cache = new HotEntryCache<>(Duration.ofSeconds(10)); -// -// final ExecutorService pool = Executors.newCachedThreadPool(); -// try { -// final CountDownLatch latch = new CountDownLatch(1); -// -// final String key = "key"; -// final String valueA = "A"; -// final String valueB = "B"; -// -// pool.submit(() -> { -// cache.putIfAbsent(key, k -> { -// latch.countDown(); -// sleep(TimeUnit.MILLISECONDS, 20); -// return valueA; -// }); -// return null; -// }); -// pool.submit(() -> { -// waitFor(latch); -// cache.putIfAbsent(key, k -> valueB); -// return null; -// }); -// -// pool.shutdown(); -// pool.awaitTermination(1, TimeUnit.MINUTES); -// -// final String actual = cache.get(key); -// Assert.assertEquals(actual, valueA); -// } finally { -// pool.shutdownNow(); -// } -// } -// -// public void testPutIfAbsentReturnsExistingValue() throws Exception { -// final HotEntryCache cache = new HotEntryCache<>(Duration.ofSeconds(10)); -// -// final String key = "key"; -// final String valueA = "A"; -// final String valueB = "B"; -// -// cache.put(key, valueA); -// -// final String returnedByPutIfAbsent = cache.putIfAbsent(key, k -> valueB); -// Assert.assertEquals(returnedByPutIfAbsent, valueA); -// -// final String actualInCache = cache.get(key); -// Assert.assertEquals(actualInCache, valueA); -// } -// -// public void testPutIfAbsentDoesNotAddNull() throws Exception { -// final HotEntryCache cache = new HotEntryCache<>(Duration.ofSeconds(10)); -// -// final String key = "key"; -// final String returnedByPutIfAbsent = cache.putIfAbsent(key, k -> null); -// Assert.assertNull(returnedByPutIfAbsent, null); -// -// final String actualInCache = cache.get(key); -// Assert.assertEquals(actualInCache, null); -// } -// -// private void sleep(final TimeUnit timeUnit, final long timeout) { -// try { -// timeUnit.sleep(timeout); -// } catch (final InterruptedException e) { -// throw new IllegalStateException(e); -// } -// } -// -// private void waitFor(final CountDownLatch latch) { -// try { -// latch.await(1, TimeUnit.MINUTES); -// } catch (final InterruptedException e) { -// throw new IllegalStateException(e); -// } -// } -// -// public static void main(final String[] args) throws InterruptedException { -// -// Configurator.setRootLevel(Level.TRACE); -// -// final Duration timeToLive = Duration.ofSeconds(1); -// final HotEntryCache cache = new HotEntryCache<>(timeToLive); -// -// cache.addListener(event -> { -// System.out.println(Instant.now() + " evicting: " + event); -// }, EventType.EVICTED); -// cache.put("key", "value that is touched"); -// for (int i = 0; i < 20; i++) { -// -// System.out.println(Instant.now() + " putting value" + i); -// cache.put("key" + i, "value" + i); -// cache.put("key", "value that is touched" + i); -// TimeUnit.MILLISECONDS.sleep(450); -// } -// -// for (int i = 20; i < 23; i++) { -// System.out.println(Instant.now() + " putting value" + i); -// cache.put("key" + i, "value" + i); -// TimeUnit.MILLISECONDS.sleep(Duration.ofSeconds(5).plusMillis(10).toMillis()); -// } -// -// TimeUnit.MILLISECONDS.sleep(Duration.ofSeconds(5).plusMillis(10).toMillis()); -// -// for (int i = 23; i < 27; i++) { -// System.out.println(Instant.now() + " putting value" + i); -// cache.put("key" + i, "value" + i); -// TimeUnit.MILLISECONDS.sleep(Duration.ofSeconds(5).plusMillis(10).toMillis()); -// } -// -// TimeUnit.SECONDS.sleep(300); -// } -//} +package org.lucares.utils.cache; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class HotEntryCacheTest { + + @Test(invocationCount = 1) + public void testRemovalListenerCalledOnExpire() throws InterruptedException + { + final String key = "key"; + final String value ="value"; + final CountDownLatch latch = new CountDownLatch(1); + + final HotEntryCache cache = new HotEntryCache<>(Duration.ofMillis(10), 10); + cache.addListener((k, v) -> { + Assert.assertEquals(k, key); + Assert.assertEquals(v, value); + latch.countDown(); + }); + + cache.put(key, value); + Assert.assertTrue(latch.await(100, TimeUnit.MILLISECONDS), "removal listener called"); + } +}