@Test
  public void testBrokenEvictionVeto() throws CacheAccessException {
    TestTimeSource timeSource = new TestTimeSource();
    Expiry<Object, Object> expiry =
        Expirations.timeToIdleExpiration(new Duration(15L, TimeUnit.MILLISECONDS));
    EvictionVeto<String, byte[]> evictionVeto =
        new EvictionVeto<String, byte[]>() {

          @Override
          public boolean test(Cache.Entry<String, byte[]> entry) {
            throw new UnsupportedOperationException("Broken veto!");
          }
        };

    AbstractOffHeapStore<String, byte[]> offHeapStore =
        createAndInitStore(timeSource, expiry, evictionVeto);
    try {
      StoreEventListener<String, byte[]> mock = mock(StoreEventListener.class);
      offHeapStore.enableStoreEventNotifications(mock);

      byte[] value = getBytes(MemoryUnit.KB.toBytes(200));
      offHeapStore.put("key1", value);
      offHeapStore.put("key2", value);
      offHeapStore.put("key3", value);
      offHeapStore.put("key4", value);
      offHeapStore.put("key5", value);
      offHeapStore.put("key6", value);

      verify(mock, atLeast(1)).onEviction(anyString(), any(Store.ValueHolder.class));
    } finally {
      destroyStore(offHeapStore);
    }
  }
  @Test
  public void testIteratorSkipsExpiredEntries() throws Exception {
    TestTimeSource timeSource = new TestTimeSource();
    AbstractOffHeapStore<String, String> offHeapStore =
        createAndInitStore(
            timeSource, Expirations.timeToLiveExpiration(new Duration(10L, TimeUnit.MILLISECONDS)));

    try {
      offHeapStore.put("key1", "value1");
      offHeapStore.put("key2", "value2");

      timeSource.advanceTime(11L);

      offHeapStore.put("key3", "value3");
      offHeapStore.put("key4", "value4");

      final List<String> expiredKeys = new ArrayList<String>();
      offHeapStore.enableStoreEventNotifications(
          new StoreEventListener<String, String>() {

            @Override
            public void onEviction(final String key, final Store.ValueHolder<String> valueHolder) {
              throw new AssertionError("This should not have happened.");
            }

            @Override
            public void onExpiration(
                final String key, final Store.ValueHolder<String> valueHolder) {
              expiredKeys.add(key);
            }
          });

      List<String> iteratedKeys = new ArrayList<String>();
      Store.Iterator<Cache.Entry<String, Store.ValueHolder<String>>> iterator =
          offHeapStore.iterator();
      while (iterator.hasNext()) {
        iteratedKeys.add(iterator.next().getKey());
      }

      assertThat(iteratedKeys, containsInAnyOrder("key3", "key4"));
      assertThat(expiredKeys, containsInAnyOrder("key1", "key2"));
    } finally {
      destroyStore(offHeapStore);
    }
  }
  @Test
  public void testExpiryEventFiredOnExpiredCachedEntry() throws CacheAccessException {
    TestTimeSource timeSource = new TestTimeSource();
    AbstractOffHeapStore<String, String> offHeapStore =
        createAndInitStore(
            timeSource, Expirations.timeToIdleExpiration(new Duration(10L, TimeUnit.MILLISECONDS)));
    try {
      final List<String> expiredKeys = new ArrayList<String>();
      offHeapStore.enableStoreEventNotifications(
          new StoreEventListener<String, String>() {

            @Override
            public void onEviction(final String key, final Store.ValueHolder<String> valueHolder) {
              throw new AssertionError("This should not have happened.");
            }

            @Override
            public void onExpiration(
                final String key, final Store.ValueHolder<String> valueHolder) {
              expiredKeys.add(key);
            }
          });

      offHeapStore.put("key1", "value1");
      offHeapStore.put("key2", "value2");

      offHeapStore.get("key1"); // Bring the entry to the caching tier

      timeSource.advanceTime(11); // Expire the elements

      offHeapStore.get("key1");
      offHeapStore.get("key2");
      assertThat(expiredKeys, containsInAnyOrder("key1", "key2"));
      assertThat(
          getExpirationStatistic(offHeapStore)
              .count(StoreOperationOutcomes.ExpirationOutcome.SUCCESS),
          is(2L));
    } finally {
      destroyStore(offHeapStore);
    }
  }