package org.infinispan.server.hotrod; import static org.infinispan.commons.api.BasicCacheContainer.DEFAULT_CACHE_NAME; import static org.infinispan.server.hotrod.Constants.INTELLIGENCE_HASH_DISTRIBUTION_AWARE; import static org.infinispan.server.hotrod.OperationStatus.Success; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertHashTopology20Received; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertStatus; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.hotRodCacheConfiguration; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.killClient; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.serverPort; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.startHotRodServer; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.partitionhandling.BasePartitionHandlingTest; import org.infinispan.server.core.test.ServerTestingUtil; import org.infinispan.server.hotrod.test.HotRodClient; import org.infinispan.server.hotrod.test.TestResponse; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.TransportFlags; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @Test(groups = "functional", testName = "server.hotrod.HotRodMergeTest") public class HotRodMergeTest extends BasePartitionHandlingTest { private List<HotRodServer> servers = new ArrayList<>(); private HotRodClient client; public HotRodMergeTest() { numMembersInCluster = 2; cacheMode = CacheMode.DIST_SYNC; cleanup = CleanupPhase.AFTER_TEST; } @BeforeClass(alwaysRun = true) @Override public void createBeforeClass() throws Throwable { super.createBeforeClass(); int nextServerPort = serverPort(); for (int i = 0; i < numMembersInCluster; i++) { servers.add(startHotRodServer(cacheManagers.get(i), nextServerPort)); nextServerPort += 50; } client = new HotRodClient("127.0.0.1", servers.get(0).getPort(), "", 60, (byte) 21); TestingUtil.waitForNoRebalance(cache(0), cache(1)); } @AfterClass(alwaysRun = true) @Override protected void destroy() { try { killClient(client); servers.forEach(ServerTestingUtil::killServer); } finally { super.destroy(); } } @Override protected void createCacheManagers() { ConfigurationBuilder dcc = hotRodCacheConfiguration(new ConfigurationBuilder()); dcc.clustering().cacheMode(cacheMode).hash().numOwners(1); createClusteredCaches(numMembersInCluster, dcc, new TransportFlags().withFD(true).withMerge(true)); waitForClusterToForm(); } public void testNewTopologySentAfterCleanMerge(Method m) { TestingUtil.waitForNoRebalance(caches()); int initialTopology = advancedCache(0).getRpcManager().getTopologyId(); expectCompleteTopology(client, initialTopology); PartitionDescriptor p0 = new PartitionDescriptor(0); PartitionDescriptor p1 = new PartitionDescriptor(1); splitCluster(p0.getNodes(), p1.getNodes()); TestingUtil.waitForNoRebalance(cache(p1.node(0))); TestingUtil.waitForNoRebalance(cache(p0.node(0))); expectPartialTopology(client, initialTopology + 1); partition(0).merge(partition(1)); eventuallyExpectCompleteTopology(client, initialTopology + 8); } public void testNewTopologySentAfterOverlappingMerge(Method m) { TestingUtil.waitForNoRebalance(caches()); int initialTopology = advancedCache(0).getRpcManager().getTopologyId(); expectCompleteTopology(client, initialTopology); PartitionDescriptor p1 = new PartitionDescriptor(0); isolatePartition(p1.getNodes()); TestingUtil.waitForNoRebalance(cache(p1.node(0))); eventuallyExpectPartialTopology(client, initialTopology + 1); partition(0).merge(partition(1)); eventuallyExpectCompleteTopology(client, initialTopology + 2); } private void eventuallyExpectCompleteTopology(HotRodClient c, int expectedTopologyId) { eventually(() -> { TestResponse resp = c.ping(INTELLIGENCE_HASH_DISTRIBUTION_AWARE, 0); assertStatus(resp, Success); if (resp.topologyResponse == null || (resp.topologyResponse.topologyId < expectedTopologyId)) { return false; } assertHashTopology20Received(resp.topologyResponse, servers, DEFAULT_CACHE_NAME, expectedTopologyId); return true; }); } private void expectCompleteTopology(HotRodClient c, int expectedTopologyId) { TestResponse resp = c.ping(INTELLIGENCE_HASH_DISTRIBUTION_AWARE, 0); assertStatus(resp, Success); assertHashTopology20Received(resp.topologyResponse, servers, DEFAULT_CACHE_NAME, expectedTopologyId); } private void eventuallyExpectPartialTopology(HotRodClient c, int expectedTopologyId) { eventually(() -> { TestResponse resp = c.ping(INTELLIGENCE_HASH_DISTRIBUTION_AWARE, 0); assertStatus(resp, Success); if (resp.topologyResponse == null || (resp.topologyResponse.topologyId < expectedTopologyId)) { return false; } assertHashTopology20Received(resp.topologyResponse, Arrays.asList(servers.get(0)), DEFAULT_CACHE_NAME, expectedTopologyId); return true; }); } private void expectPartialTopology(HotRodClient c, int expectedTopologyId) { TestResponse resp = c.ping(INTELLIGENCE_HASH_DISTRIBUTION_AWARE, 0); assertStatus(resp, Success); assertHashTopology20Received(resp.topologyResponse, Arrays.asList(servers.get(0)), DEFAULT_CACHE_NAME, expectedTopologyId); } }