package org.infinispan.commands;
import static org.infinispan.test.TestingUtil.extractComponent;
import static org.infinispan.test.TestingUtil.replaceComponent;
import static org.infinispan.test.TestingUtil.wrapComponent;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.infinispan.commands.remote.ClusteredGetAllCommand;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.distribution.MagicKey;
import org.infinispan.remoting.rpc.RpcManager;
import org.infinispan.statetransfer.StateConsumer;
import org.infinispan.statetransfer.StateTransferLock;
import org.infinispan.test.MultipleCacheManagersTest;
import org.infinispan.tx.dld.ControlledRpcManager;
import org.testng.annotations.Test;
@Test(groups = "functional", testName = "commands.GetAllCommandNodeCrashTest")
public class GetAllCommandNodeCrashTest extends MultipleCacheManagersTest {
@Override
protected void createCacheManagers() throws Throwable {
createClusteredCaches(3, getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC));
}
public void test() throws Exception {
MagicKey key = new MagicKey(cache(0), cache(1));
cache(2).put(key, "value");
ControlledRpcManager rpcManager = wrapComponent(cache(2), RpcManager.class, ControlledRpcManager::new);
rpcManager.blockBefore(ClusteredGetAllCommand.class);
CountDownLatch blockTopologyUpdate = new CountDownLatch(1);
StateConsumer stateConsumerMock = spy(extractComponent(cache(2), StateConsumer.class));
doAnswer(invocation -> {
assertTrue(blockTopologyUpdate.await(10, TimeUnit.SECONDS));
return invocation.callRealMethod();
}).when(stateConsumerMock).onTopologyUpdate(any(), anyBoolean());
replaceComponent(cache(2), StateConsumer.class, stateConsumerMock, true);
StateTransferLock stateTransferLockMock = spy(extractComponent(cache(2), StateTransferLock.class));
doAnswer(invocation -> {
blockTopologyUpdate.countDown();
return invocation.callRealMethod();
}).when(stateTransferLockMock).topologyFuture(anyInt());
replaceComponent(cache(2), StateTransferLock.class, stateTransferLockMock, true);
Future<Map<Object, Object>> f = fork(() -> cache(2).getAdvancedCache().getAll(Collections.singleton(key)));
rpcManager.waitForCommandToBlock();
// it's necessary to stop whole cache manager, not just cache, because otherwise the exception would have
// suspect node defined
cacheManagers.get(0).stop();
rpcManager.stopBlocking();
try {
Map<Object, Object> map = f.get(10, TimeUnit.SECONDS);
assertNotNull(map);
assertFalse(map.isEmpty());
assertEquals("value", map.get(key));
} finally {
blockTopologyUpdate.countDown();
}
}
}