/*
* 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.client.cache;
import com.hazelcast.cache.ICache;
import com.hazelcast.cache.impl.CacheService;
import com.hazelcast.cache.impl.HazelcastServerCachingProvider;
import com.hazelcast.cache.impl.event.CachePartitionLostEvent;
import com.hazelcast.cache.impl.event.CachePartitionLostListener;
import com.hazelcast.client.cache.impl.HazelcastClientCachingProvider;
import com.hazelcast.client.test.TestHazelcastFactory;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.spi.EventRegistration;
import com.hazelcast.spi.impl.eventservice.InternalEventService;
import com.hazelcast.spi.partition.IPartitionLostEvent;
import com.hazelcast.test.AssertTask;
import com.hazelcast.test.HazelcastParallelClassRunner;
import com.hazelcast.test.HazelcastTestSupport;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.After;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.spi.CachingProvider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import static com.hazelcast.cache.impl.HazelcastServerCachingProvider.createCachingProvider;
import static com.hazelcast.cache.impl.ICacheService.SERVICE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class ClientCachePartitionLostListenerTest extends HazelcastTestSupport {
private final TestHazelcastFactory hazelcastFactory = new TestHazelcastFactory();
@After
public void tearDown() {
hazelcastFactory.terminateAll();
}
@Test
public void test_cachePartitionLostListener_registered() {
final String cacheName = randomName();
HazelcastInstance instance = hazelcastFactory.newHazelcastInstance();
final HazelcastInstance client = hazelcastFactory.newHazelcastClient();
final CachingProvider cachingProvider = HazelcastClientCachingProvider.createCachingProvider(client);
final CacheManager cacheManager = cachingProvider.getCacheManager();
final CacheConfig<Integer, String> cacheConfig = new CacheConfig<Integer, String>();
final Cache<Integer, String> cache = cacheManager.createCache(cacheName, cacheConfig);
final ICache iCache = cache.unwrap(ICache.class);
iCache.addPartitionLostListener(new CachePartitionLostListener() {
@Override
public void partitionLost(CachePartitionLostEvent event) {
}
});
assertRegistrationsSizeEventually(instance, cacheName, 1);
}
@Test
public void test_cachePartitionLostListener_invoked() {
final String cacheName = randomName();
HazelcastInstance instance = hazelcastFactory.newHazelcastInstance();
final HazelcastInstance client = hazelcastFactory.newHazelcastClient();
final HazelcastServerCachingProvider cachingProvider = createCachingProvider(instance);
final CacheManager cacheManager = cachingProvider.getCacheManager();
final CacheConfig<Integer, String> config = new CacheConfig<Integer, String>();
config.setBackupCount(0);
cacheManager.createCache(cacheName, config);
final CachingProvider clientCachingProvider = HazelcastClientCachingProvider.createCachingProvider(client);
final CacheManager clientCacheManager = clientCachingProvider.getCacheManager();
final Cache<Integer, String> cache = clientCacheManager.getCache(cacheName);
final ICache iCache = cache.unwrap(ICache.class);
final EventCollectingCachePartitionLostListener listener = new EventCollectingCachePartitionLostListener();
iCache.addPartitionLostListener(listener);
final CacheService cacheService = getNode(instance).getNodeEngine().getService(CacheService.SERVICE_NAME);
final int partitionId = 5;
cacheService.onPartitionLost(new IPartitionLostEvent(partitionId, 0, null));
assertCachePartitionLostEventEventually(listener, partitionId);
}
@Test
public void test_cachePartitionLostListener_invoked_fromOtherNode() {
final String cacheName = randomName();
HazelcastInstance instance1 = hazelcastFactory.newHazelcastInstance();
HazelcastInstance instance2 = hazelcastFactory.newHazelcastInstance();
final HazelcastInstance client = hazelcastFactory.newHazelcastClient();
final HazelcastServerCachingProvider cachingProvider = createCachingProvider(instance1);
final CacheManager cacheManager = cachingProvider.getCacheManager();
final CacheConfig<Integer, String> config = new CacheConfig<Integer, String>();
config.setBackupCount(0);
cacheManager.createCache(cacheName, config);
final CachingProvider clientCachingProvider = HazelcastClientCachingProvider.createCachingProvider(client);
final CacheManager clientCacheManager = clientCachingProvider.getCacheManager();
final Cache<Integer, String> cache = clientCacheManager.getCache(cacheName);
final ICache iCache = cache.unwrap(ICache.class);
final EventCollectingCachePartitionLostListener listener = new EventCollectingCachePartitionLostListener();
iCache.addPartitionLostListener(listener);
assertRegistrationsSizeEventually(instance1, cacheName, 1);
assertRegistrationsSizeEventually(instance2, cacheName, 1);
final CacheService cacheService1 = getNode(instance1).getNodeEngine().getService(CacheService.SERVICE_NAME);
final CacheService cacheService2 = getNode(instance2).getNodeEngine().getService(CacheService.SERVICE_NAME);
final int partitionId = 5;
cacheService1.onPartitionLost(new IPartitionLostEvent(partitionId, 0, null));
cacheService2.onPartitionLost(new IPartitionLostEvent(partitionId, 0, null));
assertCachePartitionLostEventEventually(listener, partitionId);
}
@Test
public void test_cachePartitionLostListener_removed() {
final String cacheName = randomName();
HazelcastInstance instance = hazelcastFactory.newHazelcastInstance();
final HazelcastInstance client = hazelcastFactory.newHazelcastClient();
final HazelcastServerCachingProvider cachingProvider = createCachingProvider(instance);
final CacheManager cacheManager = cachingProvider.getCacheManager();
final CacheConfig<Integer, String> config = new CacheConfig<Integer, String>();
config.setBackupCount(0);
cacheManager.createCache(cacheName, config);
final CachingProvider clientCachingProvider = HazelcastClientCachingProvider.createCachingProvider(client);
final CacheManager clientCacheManager = clientCachingProvider.getCacheManager();
final Cache<Integer, String> cache = clientCacheManager.getCache(cacheName);
final ICache iCache = cache.unwrap(ICache.class);
final String registrationId = iCache.addPartitionLostListener(mock(CachePartitionLostListener.class));
assertRegistrationsSizeEventually(instance, cacheName, 1);
assertTrue(iCache.removePartitionLostListener(registrationId));
assertRegistrationsSizeEventually(instance, cacheName, 0);
}
private void assertCachePartitionLostEventEventually(final EventCollectingCachePartitionLostListener listener,
final int partitionId) {
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
final List<CachePartitionLostEvent> events = listener.getEvents();
assertFalse(events.isEmpty());
assertEquals(partitionId, events.get(0).getPartitionId());
}
});
}
private void assertRegistrationsSizeEventually(final HazelcastInstance instance, final String cacheName, final int size) {
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
final InternalEventService eventService = getNode(instance).getNodeEngine().getEventService();
final Collection<EventRegistration> registrations = eventService.getRegistrations(SERVICE_NAME, cacheName);
assertEquals(size, registrations.size());
}
});
}
private static class EventCollectingCachePartitionLostListener
implements CachePartitionLostListener {
private final List<CachePartitionLostEvent> events = Collections.synchronizedList(new LinkedList<CachePartitionLostEvent>());
public EventCollectingCachePartitionLostListener() {
}
@Override
public void partitionLost(CachePartitionLostEvent event) {
this.events.add(event);
}
public List<CachePartitionLostEvent> getEvents() {
synchronized (events) {
return new ArrayList<CachePartitionLostEvent>(events);
}
}
}
}