/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.cache;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.core.ICompletableFuture;
import com.hazelcast.internal.serialization.impl.DefaultSerializationServiceBuilder;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.spi.serialization.SerializationService;
import com.hazelcast.test.AssertTask;
import com.hazelcast.util.EmptyStatement;
import com.hazelcast.util.SampleableConcurrentHashMap;
import org.junit.Test;
import javax.cache.Cache;
import javax.cache.configuration.FactoryBuilder;
import javax.cache.configuration.MutableCacheEntryListenerConfiguration;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
import javax.cache.expiry.ExpiryPolicy;
import javax.cache.expiry.ModifiedExpiryPolicy;
import javax.cache.processor.EntryProcessor;
import javax.cache.processor.EntryProcessorException;
import javax.cache.processor.EntryProcessorResult;
import javax.cache.processor.MutableEntry;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public abstract class CacheBasicAbstractTest extends CacheTestSupport {
@Test
public void testPutGetRemoveReplace() {
ICache<String, String> cache = createCache();
cache.put("key1", "value1");
assertEquals("value1", cache.get("key1"));
assertEquals("value1", cache.getAndPut("key1", "value2"));
assertEquals(1, cache.size());
assertTrue(cache.remove("key1"));
cache.put("key1", "value3");
assertFalse(cache.remove("key1", "xx"));
assertTrue(cache.remove("key1", "value3"));
assertNull(cache.get("key1"));
assertTrue(cache.putIfAbsent("key1", "value1"));
assertFalse(cache.putIfAbsent("key1", "value1"));
assertEquals("value1", cache.getAndRemove("key1"));
assertNull(cache.get("key1"));
cache.put("key1", "value1");
assertTrue(cache.containsKey("key1"));
assertFalse(cache.replace("key2", "value2"));
assertTrue(cache.replace("key1", "value2"));
assertEquals("value2", cache.get("key1"));
assertFalse(cache.replace("key1", "xx", "value3"));
assertTrue(cache.replace("key1", "value2", "value3"));
assertEquals("value3", cache.get("key1"));
assertEquals("value3", cache.getAndReplace("key1", "value4"));
assertEquals("value4", cache.get("key1"));
}
@Test
public void testAsyncGetPutRemove() throws ExecutionException, InterruptedException {
final ICache<String, String> cache = createCache();
final String key = "key";
cache.put(key, "value1");
Future future = cache.getAsync(key);
assertEquals("value1", future.get());
cache.putAsync(key, "value2");
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertEquals("value2", cache.get(key));
}
});
future = cache.getAndPutAsync(key, "value3");
assertEquals("value2", future.get());
assertEquals("value3", cache.get(key));
future = cache.removeAsync("key2");
assertFalse((Boolean) future.get());
future = cache.removeAsync(key);
assertTrue((Boolean) future.get());
cache.put(key, "value4");
future = cache.getAndRemoveAsync("key2");
assertNull(future.get());
future = cache.getAndRemoveAsync(key);
assertEquals("value4", future.get());
}
@Test
public void testPutIfAbsentAsync_success() throws InterruptedException, ExecutionException {
ICache<String, String> cache = createCache();
String key = randomString();
ICompletableFuture<Boolean> iCompletableFuture = cache.putIfAbsentAsync(key, randomString());
assertTrue(iCompletableFuture.get());
}
@Test
public void testPutIfAbsentAsync_fail() throws ExecutionException, InterruptedException {
ICache<String, String> cache = createCache();
String key = randomString();
cache.put(key, randomString());
ICompletableFuture<Boolean> iCompletableFuture = cache.putIfAbsentAsync(key, randomString());
assertFalse(iCompletableFuture.get());
}
@Test
public void testPutIfAbsentAsync_withExpiryPolicy() {
final ICache<String, String> cache = createCache();
final String key = randomString();
HazelcastExpiryPolicy expiryPolicy = new HazelcastExpiryPolicy(1, 1, 1);
cache.putIfAbsentAsync(key, randomString(), expiryPolicy);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertNull(cache.get(key));
}
});
}
@Test
public void testGetAndReplaceAsync() throws InterruptedException, ExecutionException {
ICache<String, String> cache = createCache();
String key = randomString();
String oldValue = randomString();
String newValue = randomString();
cache.put(key, oldValue);
ICompletableFuture<String> iCompletableFuture = cache.getAndReplaceAsync(key, newValue);
assertEquals(iCompletableFuture.get(), oldValue);
assertEquals(cache.get(key), newValue);
}
@Test
public void testGetAll_withEmptySet() {
ICache<String, String> cache = createCache();
Map<String, String> map = cache.getAll(Collections.<String>emptySet());
assertEquals(0, map.size());
}
@Test
public void testClear() {
ICache<String, String> cache = createCache();
for (int i = 0; i < 10; i++) {
cache.put("key" + i, "value" + i);
}
cache.clear();
assertEquals(0, cache.size());
}
@Test
public void testRemoveAll() {
ICache<String, String> cache = createCache();
for (int i = 0; i < 10; i++) {
cache.put("key" + i, "value" + i);
}
cache.removeAll();
assertEquals(0, cache.size());
}
protected ExpiryPolicy ttlToExpiryPolicy(long ttl, TimeUnit timeUnit) {
return new ModifiedExpiryPolicy(new Duration(timeUnit, ttl));
}
@Test
public void testPutWithTtl() throws ExecutionException, InterruptedException {
final ICache<String, String> cache = createCache();
final String key = "key";
cache.put(key, "value1", ttlToExpiryPolicy(1, TimeUnit.SECONDS));
assertTrueEventually(new AssertTask() {
public void run() throws Exception {
assertNull(cache.get(key));
}
});
assertEquals(0, cache.size());
cache.putAsync(key, "value1", ttlToExpiryPolicy(1, TimeUnit.SECONDS));
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertNull(cache.get(key));
}
});
assertEquals(0, cache.size());
cache.put(key, "value2");
String value = cache.getAndPut(key, "value3", ttlToExpiryPolicy(1, TimeUnit.SECONDS));
assertEquals("value2", value);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertNull(cache.get(key));
}
});
assertEquals(0, cache.size());
cache.put(key, "value4");
Future future = cache.getAndPutAsync(key, "value5", ttlToExpiryPolicy(1, TimeUnit.SECONDS));
assertEquals("value4", future.get());
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertNull(cache.get(key));
}
});
assertEquals(0, cache.size());
}
@Test
@SuppressWarnings("WhileLoopReplaceableByForEach")
public void testIterator() {
ICache<Integer, Integer> cache = createCache();
int size = 1111;
int multiplier = 11;
for (int i = 0; i < size; i++) {
cache.put(i, i * multiplier);
}
int[] keys = new int[size];
int keyIndex = 0;
Iterator<Cache.Entry<Integer, Integer>> iterator = cache.iterator();
while (iterator.hasNext()) {
Cache.Entry<Integer, Integer> e = iterator.next();
int key = e.getKey();
int value = e.getValue();
assertEquals(key * multiplier, value);
keys[keyIndex++] = key;
}
assertEquals(size, keyIndex);
Arrays.sort(keys);
for (int i = 0; i < size; i++) {
assertEquals(i, keys[i]);
}
}
@Test
public void testIteratorRemove() {
ICache<Integer, Integer> cache = createCache();
int size = 1111;
for (int i = 0; i < size; i++) {
cache.put(i, i);
}
Iterator<Cache.Entry<Integer, Integer>> iterator = cache.iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
assertEquals(0, cache.size());
}
@Test(expected = IllegalStateException.class)
public void testIteratorIllegalRemove() {
ICache<Integer, Integer> cache = createCache();
int size = 10;
for (int i = 0; i < size; i++) {
cache.put(i, i);
}
Iterator<Cache.Entry<Integer, Integer>> iterator = cache.iterator();
if (iterator.hasNext()) {
iterator.remove();
}
}
@SuppressWarnings("WhileLoopReplaceableByForEach")
private void testIteratorDuringInsertion(boolean withoutEviction) {
final int MAX_SIZE = withoutEviction ? 1000000 : 1000;
final CacheConfig<Integer, Integer> config = getCacheConfigWithMaxSize(MAX_SIZE);
final ICache<Integer, Integer> cache = createCache(config);
final int maxSize = withoutEviction
? getMaxCacheSizeWithoutEviction(config)
: getMaxCacheSizeWithEviction(config);
// we prefill the cache with half of the max size, so there will be new inserts from the AbstractCacheWorker
int prefillSize = maxSize / 2;
for (int i = 0; i < prefillSize; i++) {
cache.put(i, i);
}
AbstractCacheWorker worker = new AbstractCacheWorker() {
@Override
void doRun(Random random) {
int i = random.nextInt(maxSize);
cache.put(i, i);
}
};
worker.awaitFirstIteration();
try {
int i = 0;
Iterator<Cache.Entry<Integer, Integer>> iterator = cache.iterator();
while (iterator.hasNext()) {
Cache.Entry<Integer, Integer> e = iterator.next();
Integer key = e.getKey();
Integer value = e.getValue();
assertEquals(key, value);
i++;
}
if (withoutEviction) {
assertTrue("should have iterated over at least " + prefillSize + " entries, but was " + i, i >= prefillSize);
assertThatNoCacheEvictionHappened(cache);
}
} catch (NoSuchElementException e) {
if (withoutEviction) {
fail("Without eviction, there should not be `NoSuchElementException`: " + e);
}
} finally {
worker.shutdown();
}
}
@Test
public void testIteratorDuringInsertion_withoutEviction() {
testIteratorDuringInsertion(true);
}
@Test
public void testIteratorDuringInsertion_withEviction() {
testIteratorDuringInsertion(false);
}
@SuppressWarnings("WhileLoopReplaceableByForEach")
private void testIteratorDuringUpdate(boolean withoutEviction) {
final int MAX_SIZE = withoutEviction ? 1000000 : 1000;
final CacheConfig<Integer, Integer> config = getCacheConfigWithMaxSize(MAX_SIZE);
final ICache<Integer, Integer> cache = createCache(config);
final int maxSize = withoutEviction
? getMaxCacheSizeWithoutEviction(config)
: getMaxCacheSizeWithEviction(config);
for (int i = 0; i < maxSize; i++) {
cache.put(i, i);
}
AbstractCacheWorker worker = new AbstractCacheWorker() {
@Override
void doRun(Random random) {
int i = random.nextInt(maxSize);
cache.put(i, -i);
}
};
worker.awaitFirstIteration();
try {
int i = 0;
Iterator<Cache.Entry<Integer, Integer>> iterator = cache.iterator();
while (iterator.hasNext()) {
Cache.Entry<Integer, Integer> e = iterator.next();
Integer key = e.getKey();
Integer value = e.getValue();
assertTrue("key: " + key + ", value: " + value, key == Math.abs(value));
i++;
}
if (withoutEviction) {
assertEquals("should have iterated over all " + maxSize + " entries", maxSize, i);
assertThatNoCacheEvictionHappened(cache);
}
} catch (NoSuchElementException e) {
if (withoutEviction) {
fail("Without eviction, there should not be `NoSuchElementException`: " + e);
}
} finally {
worker.shutdown();
}
}
@Test
public void testIteratorDuringUpdate_withoutEviction() {
testIteratorDuringUpdate(true);
}
@Test
public void testIteratorDuringUpdate_withEviction() {
testIteratorDuringUpdate(true);
}
@SuppressWarnings("WhileLoopReplaceableByForEach")
private void testIteratorDuringRemoval(boolean withoutEviction) {
final int MAX_SIZE = withoutEviction ? 1000000 : 1000;
final CacheConfig<Integer, Integer> config = getCacheConfigWithMaxSize(MAX_SIZE);
final ICache<Integer, Integer> cache = createCache(config);
final int maxSize = withoutEviction
? getMaxCacheSizeWithoutEviction(config)
: getMaxCacheSizeWithEviction(config);
for (int i = 0; i < maxSize; i++) {
cache.put(i, i);
}
AbstractCacheWorker worker = new AbstractCacheWorker() {
@Override
void doRun(Random random) {
int i = random.nextInt(maxSize);
cache.remove(i);
}
};
worker.awaitFirstIteration();
try {
int i = 0;
Iterator<Cache.Entry<Integer, Integer>> iterator = cache.iterator();
while (iterator.hasNext()) {
Cache.Entry<Integer, Integer> e = iterator.next();
Integer key = e.getKey();
Integer value = e.getValue();
assertEquals(key, value);
i++;
}
if (withoutEviction) {
assertTrue("should have iterated over at most " + maxSize + " entries, but was " + i, i <= maxSize);
assertThatNoCacheEvictionHappened(cache);
}
} catch (NoSuchElementException e) {
// `NoSuchElementException` is expected because while iterating over entries,
// last element might be removed by worker thread in the test and since there is no more element,
// `NoSuchElementException` is thrown which is normal behaviour.
} finally {
worker.shutdown();
}
}
@Test
public void testIteratorDuringRemoval_withoutEviction() {
testIteratorDuringRemoval(true);
}
@Test
public void testIteratorDuringRemoval_withEviction() {
testIteratorDuringRemoval(false);
}
@Test
public void testRemoveAsync() throws ExecutionException, InterruptedException {
ICache<String, String> cache = createCache();
String key = randomString();
String value = randomString();
cache.put(key, value);
ICompletableFuture<Boolean> future = cache.removeAsync(key);
assertTrue(future.get());
}
@Test
public void testRemoveAsyncWhenEntryNotFound() throws ExecutionException, InterruptedException {
ICache<String, String> cache = createCache();
ICompletableFuture<Boolean> future = cache.removeAsync(randomString());
assertFalse(future.get());
}
@Test
public void testRemoveAsync_withOldValue() throws ExecutionException, InterruptedException {
ICache<String, String> cache = createCache();
String key = randomString();
String value = randomString();
cache.put(key, value);
ICompletableFuture<Boolean> future = cache.removeAsync(key, value);
assertTrue(future.get());
}
@Test
public void testRemoveAsyncWhenEntryNotFound_withOldValue() throws ExecutionException, InterruptedException {
ICache<String, String> cache = createCache();
ICompletableFuture<Boolean> future = cache.removeAsync(randomString(), randomString());
assertFalse(future.get());
}
@Test
public void testRemovingSameEntryTwiceShouldTriggerEntryListenerOnlyOnce() {
String cacheName = randomString();
CacheConfig<Integer, String> config = createCacheConfig();
final CacheFromDifferentNodesTest.SimpleEntryListener<Integer, String> listener =
new CacheFromDifferentNodesTest.SimpleEntryListener<Integer, String>();
MutableCacheEntryListenerConfiguration<Integer, String> listenerConfiguration =
new MutableCacheEntryListenerConfiguration<Integer, String>(
FactoryBuilder.factoryOf(listener), null, true, true);
config.addCacheEntryListenerConfiguration(listenerConfiguration);
Cache<Integer, String> cache = cacheManager.createCache(cacheName, config);
assertNotNull(cache);
Integer key = 1;
String value = "value";
cache.put(key, value);
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
assertEquals(1, listener.created.get());
}
});
cache.removeAll();
cache.removeAll();
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
assertEquals(1, listener.removed.get());
}
});
}
@Test
public void testCompletionEvent() {
String cacheName = randomString();
CacheConfig<Integer, String> config = createCacheConfig();
final CacheFromDifferentNodesTest.SimpleEntryListener<Integer, String> listener =
new CacheFromDifferentNodesTest.SimpleEntryListener<Integer, String>();
MutableCacheEntryListenerConfiguration<Integer, String> listenerConfiguration =
new MutableCacheEntryListenerConfiguration<Integer, String>(
FactoryBuilder.factoryOf(listener), null, true, true);
config.addCacheEntryListenerConfiguration(listenerConfiguration);
Cache<Integer, String> cache = cacheManager.createCache(cacheName, config);
assertNotNull(cache);
Integer key1 = 1;
String value1 = "value1";
cache.put(key1, value1);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertEquals(1, listener.created.get());
}
});
Integer key2 = 2;
String value2 = "value2";
cache.put(key2, value2);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertEquals(2, listener.created.get());
}
});
Set<Integer> keys = new HashSet<Integer>();
keys.add(key1);
keys.add(key2);
cache.removeAll(keys);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
assertEquals(2, listener.removed.get());
}
});
}
@Test
public void testJSRCreateDestroyCreate() {
String cacheName = randomString();
assertNull(cacheManager.getCache(cacheName));
CacheConfig<Integer, String> config = new CacheConfig<Integer, String>();
Cache<Integer, String> cache = cacheManager.createCache(cacheName, config);
assertNotNull(cache);
Integer key = 1;
String value1 = "value";
cache.put(key, value1);
String value2 = cache.get(key);
assertEquals(value1, value2);
cache.remove(key);
assertNull(cache.get(key));
cacheManager.destroyCache(cacheName);
assertNull(cacheManager.getCache(cacheName));
Cache<Integer, String> cacheAfterDestroy = cacheManager.createCache(cacheName, config);
assertNotNull(cacheAfterDestroy);
}
@Test
public void testCaches_NotEmpty() {
ArrayList<String> expected = new ArrayList<String>();
ArrayList<String> real = new ArrayList<String>();
cacheManager.createCache("c1", new MutableConfiguration());
cacheManager.createCache("c2", new MutableConfiguration());
cacheManager.createCache("c3", new MutableConfiguration());
expected.add(cacheManager.getCache("c1").getName());
expected.add(cacheManager.getCache("c2").getName());
expected.add(cacheManager.getCache("c3").getName());
Iterable<String> cacheNames = cacheManager.getCacheNames();
for (String cacheName : cacheNames) {
real.add(cacheName);
}
expected.removeAll(real);
assertTrue(expected.isEmpty());
}
@Test
public void testInitableIterator() {
int testSize = 3007;
SerializationService serializationService = new DefaultSerializationServiceBuilder().build();
for (int fetchSize = 1; fetchSize < 102; fetchSize++) {
SampleableConcurrentHashMap<Data, String> map = new SampleableConcurrentHashMap<Data, String>(1000);
for (int i = 0; i < testSize; i++) {
Integer key = i;
Data data = serializationService.toData(key);
String value1 = "value" + i;
map.put(data, value1);
}
int nextTableIndex = Integer.MAX_VALUE;
int total = 0;
int remaining = testSize;
while (remaining > 0 && nextTableIndex > 0) {
int size = (remaining > fetchSize ? fetchSize : remaining);
List<Data> keys = new ArrayList<Data>(size);
nextTableIndex = map.fetchKeys(nextTableIndex, size, keys);
remaining -= keys.size();
total += keys.size();
}
assertEquals(testSize, total);
}
}
@Test
public void testCachesTypedConfig() {
CacheConfig<Integer, Long> config = createCacheConfig();
String cacheName = randomString();
config.setName(cacheName);
config.setTypes(Integer.class, Long.class);
Cache<Integer, Long> cache = cacheManager.createCache(cacheName, config);
Cache<Integer, Long> cache2 = cacheManager.getCache(cacheName, config.getKeyType(), config.getValueType());
assertNotNull(cache);
assertNotNull(cache2);
}
@Test
public void getAndOperateOnCacheAfterClose() {
String cacheName = randomString();
ICache<Integer, Integer> cache = createCache(cacheName);
cache.close();
assertTrue(cache.isClosed());
assertFalse(cache.isDestroyed());
Cache<Object, Object> cacheAfterClose = cacheManager.getCache(cacheName);
assertNotNull(cacheAfterClose);
assertFalse(cacheAfterClose.isClosed());
cache.put(1, 1);
}
@Test
public void getButCantOperateOnCacheAfterDestroy() {
String cacheName = randomString();
ICache<Integer, Integer> cache = createCache(cacheName);
cache.destroy();
assertTrue(cache.isClosed());
assertTrue(cache.isDestroyed());
Cache<Object, Object> cacheAfterDestroy = cacheManager.getCache(cacheName);
assertNull(cacheAfterDestroy);
assertTrue(cache.isClosed());
assertTrue(cache.isDestroyed());
try {
cache.put(1, 1);
fail("Since cache is destroyed, operation on cache must with failed with 'IllegalStateException'");
} catch (IllegalStateException e) {
// expect this exception since cache is closed and destroyed
} catch (Throwable t) {
t.printStackTrace();
fail("Since cache is destroyed, operation on cache must with failed with 'IllegalStateException', "
+ "not with " + t.getMessage());
}
}
@Test
public void testEntryProcessor_invoke() {
ICache<String, String> cache = createCache();
String value = randomString();
String key = randomString();
String postFix = randomString();
cache.put(key, value);
String result = cache.invoke(key, new AppendEntryProcessor(), postFix);
String expectedResult = value + postFix;
assertEquals(expectedResult, result);
assertEquals(expectedResult, cache.get(key));
}
@Test
public void testEntryProcessor_invokeAll() {
ICache<String, String> cache = createCache();
int entryCount = 10;
Map<String, String> localMap = new HashMap<String, String>();
for (int i = 0; i < entryCount; i++) {
localMap.put(randomString(), randomString());
}
cache.putAll(localMap);
String postFix = randomString();
Map<String, EntryProcessorResult<String>> resultMap
= cache.invokeAll(localMap.keySet(), new AppendEntryProcessor(), postFix);
for (Map.Entry<String, String> localEntry : localMap.entrySet()) {
EntryProcessorResult<String> entryProcessorResult = resultMap.get(localEntry.getKey());
assertEquals(localEntry.getValue() + postFix, entryProcessorResult.get());
assertEquals(localEntry.getValue() + postFix, cache.get(localEntry.getKey()));
}
}
public static class AppendEntryProcessor implements EntryProcessor<String, String, String>, Serializable {
private static final long serialVersionUID = -396575576353368113L;
@Override
public String process(MutableEntry<String, String> entry, Object... arguments) throws EntryProcessorException {
String postFix = (String) arguments[0];
String value = entry.getValue();
String result = value + postFix;
entry.setValue(result);
return result;
}
}
private static abstract class AbstractCacheWorker {
private final Random random = new Random();
private final CountDownLatch firstIterationDone = new CountDownLatch(1);
private final AtomicBoolean isRunning = new AtomicBoolean(true);
private final CacheWorkerThread thread = new CacheWorkerThread();
public AbstractCacheWorker() {
thread.start();
}
public void awaitFirstIteration() {
try {
firstIterationDone.await();
} catch (InterruptedException e) {
fail("CacheWorkerThread did not start! " + e.getMessage());
}
}
public void shutdown() {
isRunning.set(false);
try {
thread.join();
} catch (InterruptedException e) {
fail("CacheWorkerThread did not stop! " + e.getMessage());
}
}
private class CacheWorkerThread extends Thread {
public void run() {
try {
doRun(random);
LockSupport.parkNanos(1);
} catch (Exception e) {
EmptyStatement.ignore(e);
}
firstIterationDone.countDown();
while (isRunning.get()) {
try {
doRun(random);
LockSupport.parkNanos(1);
} catch (Exception e) {
EmptyStatement.ignore(e);
}
}
}
}
abstract void doRun(Random random);
}
// https://github.com/hazelcast/hazelcast/issues/7236
@Test
public void expiryTimeShouldNotBeChangedOnUpdateWhenCreatedExpiryPolicyIsUsed() {
final int CREATED_EXPIRY_TIME_IN_MSEC = 100;
Duration duration = new Duration(TimeUnit.MILLISECONDS, CREATED_EXPIRY_TIME_IN_MSEC);
CacheConfig<Integer, String> cacheConfig = new CacheConfig<Integer, String>();
cacheConfig.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(duration));
Cache<Integer, String> cache = createCache(cacheConfig);
cache.put(1, "value");
cache.put(1, "value");
sleepAtLeastMillis(CREATED_EXPIRY_TIME_IN_MSEC + 1);
assertNull(cache.get(1));
}
@Test
public void removeCacheFromOwnerCacheManagerWhenCacheIsDestroyed() {
ICache cache = createCache();
assertTrue(isCacheExist(cache));
cache.destroy();
assertFalse(isCacheExist(cache));
}
private boolean isCacheExist(ICache cache) {
Iterator<String> cacheNamesIter = cacheManager.getCacheNames().iterator();
while (cacheNamesIter.hasNext()) {
String cacheName = cacheNamesIter.next();
if (cacheName.equals(cache.getName())) {
return true;
}
}
return false;
}
@Test
public void entryShouldNotBeExpiredWhenTimeUnitIsNullAndDurationIsZero() {
Duration duration = new Duration(null, 0);
CacheConfig<Integer, String> cacheConfig = new CacheConfig<Integer, String>();
cacheConfig.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(duration));
Cache<Integer, String> cache = createCache(cacheConfig);
cache.put(1, "value");
sleepAtLeastMillis(1);
assertNotNull(cache.get(1));
}
}