package org.infinispan.xsite; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNull; import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.infinispan.commands.VisitableCommand; import org.infinispan.commands.tx.CommitCommand; import org.infinispan.commands.tx.PrepareCommand; import org.infinispan.commands.write.ClearCommand; import org.infinispan.commands.write.PutKeyValueCommand; import org.infinispan.commands.write.PutMapCommand; import org.infinispan.commands.write.RemoveCommand; import org.infinispan.commands.write.ReplaceCommand; import org.infinispan.configuration.cache.BackupConfiguration; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.context.InvocationContext; import org.infinispan.context.impl.TxInvocationContext; import org.infinispan.interceptors.base.CommandInterceptor; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * @author Mircea Markus * @since 5.2 */ @Test(groups = "xsite", testName = "xsite.NonTxAsyncBackupTest") public class NonTxAsyncBackupTest extends AbstractTwoSitesTest { private BlockingInterceptor blockingInterceptor; public NonTxAsyncBackupTest() { super.lonBackupStrategy = BackupConfiguration.BackupStrategy.ASYNC; } @Override protected void createSites() { super.createSites(); blockingInterceptor = new BlockingInterceptor(); backup("LON").getAdvancedCache().addInterceptor(blockingInterceptor, 1); } @Override protected ConfigurationBuilder getNycActiveConfig() { return getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, false); } @Override protected ConfigurationBuilder getLonActiveConfig() { return getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, false); } @BeforeMethod void resetBlockingInterceptor() { blockingInterceptor.reset(); } public void testPut() throws Exception { cache("LON", 0).put("k", "v"); blockingInterceptor.invocationReceivedLatch.await(20000, TimeUnit.MILLISECONDS); assertEquals("v", cache("LON", 0).get("k")); assertEquals("v", cache("LON", 1).get("k")); assertNull(backup("LON").get("k")); blockingInterceptor.waitingLatch.countDown(); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return "v".equals(backup("LON").get("k")); } }); } public void testRemove() throws Exception { doPutWithDisabledBlockingInterceptor(); cache("LON", 1).remove("k"); blockingInterceptor.invocationReceivedLatch.await(20000, TimeUnit.MILLISECONDS); assertNull(cache("LON", 0).get("k")); assertNull(cache("LON", 1).get("k")); assertEquals("v", backup("LON").get("k")); blockingInterceptor.waitingLatch.countDown(); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return backup("LON").get("k") == null; } }); } public void testClear() throws Exception { doPutWithDisabledBlockingInterceptor(); cache("LON", 1).clear(); blockingInterceptor.invocationReceivedLatch.await(20000, TimeUnit.MILLISECONDS); assertNull(cache("LON", 0).get("k")); assertNull(cache("LON", 1).get("k")); assertEquals("v", backup("LON").get("k")); blockingInterceptor.waitingLatch.countDown(); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return backup("LON").get("k") == null; } }); } public void testReplace() throws Exception { doPutWithDisabledBlockingInterceptor(); cache("LON", 1).replace("k", "v2"); blockingInterceptor.invocationReceivedLatch.await(20000, TimeUnit.MILLISECONDS); assertEquals("v2", cache("LON", 0).get("k")); assertEquals("v2", cache("LON", 1).get("k")); assertEquals("v", backup("LON").get("k")); blockingInterceptor.waitingLatch.countDown(); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return "v2".equals(backup("LON").get("k")); } }); } public void testPutAll() throws Exception { cache("LON", 0).putAll(Collections.singletonMap("k", "v")); blockingInterceptor.invocationReceivedLatch.await(20000, TimeUnit.MILLISECONDS); assertEquals("v", cache("LON", 0).get("k")); assertEquals("v", cache("LON", 1).get("k")); assertNull(backup("LON").get("k")); blockingInterceptor.waitingLatch.countDown(); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return "v".equals(backup("LON").get("k")); } }); } private void doPutWithDisabledBlockingInterceptor() { blockingInterceptor.isActive = false; cache("LON", 0).put("k", "v"); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return "v".equals(backup("LON").get("k")); } }); blockingInterceptor.isActive = true; } public static class BlockingInterceptor extends CommandInterceptor { public volatile CountDownLatch invocationReceivedLatch = new CountDownLatch(1); public volatile CountDownLatch waitingLatch = new CountDownLatch(1); public volatile boolean isActive = true; void reset() { invocationReceivedLatch = new CountDownLatch(1); waitingLatch = new CountDownLatch(1); } @Override public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable { return handle(ctx, command); } @Override public Object visitCommitCommand(TxInvocationContext ctx, CommitCommand command) throws Throwable { return handle(ctx, command); } @Override public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable { return handle(ctx, command); } @Override public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable { return handle(ctx, command); } @Override public Object visitReplaceCommand(InvocationContext ctx, ReplaceCommand command) throws Throwable { return handle(ctx, command); } @Override public Object visitClearCommand(InvocationContext ctx, ClearCommand command) throws Throwable { return handle(ctx, command); } @Override public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable { return handle(ctx, command); } protected Object handle(InvocationContext ctx, VisitableCommand command) throws Throwable { if (isActive) { invocationReceivedLatch.countDown(); waitingLatch.await(); } return super.handleDefault(ctx, command); } } }