package org.infinispan.xsite;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
import org.infinispan.commons.api.BasicCacheContainer;
import org.infinispan.commons.api.Lifecycle;
import org.infinispan.commons.marshall.Marshaller;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.Transport;
import org.infinispan.test.AbstractCacheTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.test.fwk.TransportFlags;
import org.infinispan.transaction.impl.TransactionTable;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
/**
* @author Mircea Markus
*/
public abstract class AbstractXSiteTest extends AbstractCacheTest {
List<TestSite> sites = new ArrayList<TestSite>();
private Map<String, Integer> siteName2index = new HashMap<String, Integer>();
@BeforeMethod(alwaysRun = true) // run even for tests in the unstable_xsite group
public void createBeforeMethod() throws Throwable {
if (cleanupAfterMethod()) createSites();
}
@BeforeClass(alwaysRun = true) // run even for tests in the unstable_xsite group
public void createBeforeClass() throws Throwable {
if (cleanupAfterTest()) createSites();
}
@AfterMethod(alwaysRun = true) // run even if the test failed
protected void clearContent() throws Throwable {
if (cleanupAfterTest()) {
clearSites();
} else {
killSites();
}
}
private void clearSites() {
for (TestSite ts : sites) {
clearSite(ts);
}
}
protected void clearSite(TestSite ts) {
TestingUtil.clearContent(ts.cacheManagers);
}
@AfterClass(alwaysRun = true) // run even if the test failed
protected void destroy() {
if (cleanupAfterTest()) {
killSites();
}
}
private void killSites() {
for (TestSite ts : sites) {
killSite(ts);
}
sites.clear();
siteName2index.clear();
}
protected void killSite(TestSite ts) {
ts.cacheManagers.forEach(Lifecycle::stop);
}
protected abstract void createSites();
protected TestSite createSite(String siteName, int numNodes, GlobalConfigurationBuilder gcb, ConfigurationBuilder defaultCacheConfig) {
TestSite testSite = new TestSite(siteName, sites.size());
testSite.createClusteredCaches(numNodes, null, gcb, defaultCacheConfig);
sites.add(testSite);
siteName2index.put(siteName, sites.size() - 1);
return testSite;
}
protected TestSite site(int index) {
return sites.get(index);
}
protected TestSite site(String name) {
return sites.get(siteName2index.get(name));
}
protected <K,V> Cache<K,V> cache(String site, int index) {
return site(site).cache(index);
}
protected <K,V> Cache<K,V> cache(String site, String cacheName, int index) {
return site(site).cache(cacheName, index);
}
protected <K,V> List<Cache<K,V>> caches(String site) {
return caches(site, null);
}
protected <K,V> List<Cache<K,V>> caches(String site, String cacheName) {
return Collections.unmodifiableList(site(site).<K,V>getCaches(cacheName));
}
protected void startCache(String siteName, String cacheName, ConfigurationBuilder configurationBuilder) {
TestSite site = site(siteName);
for (EmbeddedCacheManager ecm : site.cacheManagers) {
Configuration config = configurationBuilder.build();
ecm.defineConfiguration(cacheName, BasicCacheContainer.DEFAULT_CACHE_NAME, config);
}
site.waitForClusterToForm(cacheName);
}
protected final <K, V> void assertInSite(String siteName, AssertCondition<K, V> condition) {
for (Cache<K, V> cache : this.<K, V>caches(siteName)) {
condition.assertInCache(cache);
}
}
protected final <K, V> void assertInSite(String siteName, String cacheName, AssertCondition<K, V> condition) {
for (Cache<K, V> cache : this.<K, V>caches(siteName, cacheName)) {
condition.assertInCache(cache);
}
}
protected final <K, V> void assertEventuallyInSite(final String siteName, final EventuallyAssertCondition<K, V> condition,
long timeout, TimeUnit timeUnit) {
eventually(new Condition() {
@Override
public boolean isSatisfied() throws Exception {
for (Cache<K, V> cache : AbstractXSiteTest.this.<K, V>caches(siteName)) {
if (!condition.assertInCache(cache)) {
return false;
}
}
return true;
}
}, timeUnit.toMillis(timeout));
}
protected final <K, V> void assertEventuallyInSite(final String siteName, final String cacheName, final EventuallyAssertCondition<K, V> condition,
long timeout, TimeUnit timeUnit) {
eventually(new Condition() {
@Override
public boolean isSatisfied() throws Exception {
for (Cache<K, V> cache : AbstractXSiteTest.this.<K, V>caches(siteName, cacheName)) {
if (!condition.assertInCache(cache)) {
return false;
}
}
return true;
}
}, timeUnit.toMillis(timeout));
}
protected static interface AssertCondition<K, V> {
void assertInCache(Cache<K, V> cache);
}
protected static interface EventuallyAssertCondition<K, V> {
boolean assertInCache(Cache<K, V> cache);
}
public static class TestSite {
protected List<EmbeddedCacheManager> cacheManagers = new ArrayList<EmbeddedCacheManager>();
private final String siteName;
private final int siteIndex;
public TestSite(String siteName, int siteIndex) {
this.siteName = siteName;
this.siteIndex = siteIndex;
}
private TransportFlags transportFlags() {
return new TransportFlags().withPortRange(siteIndex).withSiteName(siteName);
}
protected <K, V> List<Cache<K, V>> createClusteredCaches(int numMembersInCluster, String cacheName,
GlobalConfigurationBuilder gcb, ConfigurationBuilder builder) {
List<Cache<K, V>> caches = new ArrayList<Cache<K, V>>(numMembersInCluster);
final TransportFlags flags = transportFlags();
for (int i = 0; i < numMembersInCluster; i++) {
EmbeddedCacheManager cm = addClusterEnabledCacheManager(flags, gcb, builder);
if (cacheName != null)
cm.defineConfiguration(cacheName, builder.build());
Cache<K, V> cache = cacheName == null ? cm.<K,V>getCache() : cm.<K,V>getCache(cacheName);
caches.add(cache);
}
waitForClusterToForm(cacheName);
return caches;
}
protected EmbeddedCacheManager addClusterEnabledCacheManager(TransportFlags flags, GlobalConfigurationBuilder gcb,
ConfigurationBuilder builder) {
GlobalConfigurationBuilder clone = GlobalConfigurationBuilder.defaultClusteredBuilder();
//get the transport here as clone.read below would inject the same transport reference into the clone
// which we don't want
Transport transport = clone.transport().getTransport();
Marshaller marshaller = clone.serialization().getMarshaller();
clone.read(gcb.build());
clone.transport().transport(transport);
clone.serialization().marshaller(marshaller);
clone.transport().clusterName("ISPN(SITE " + siteName + ")");
EmbeddedCacheManager cm = TestCacheManagerFactory.createClusteredCacheManager(clone, builder, flags);
cacheManagers.add(cm);
return cm;
}
public void waitForClusterToForm(String cacheName) {
List<Cache<Object, Object>> caches = getCaches(cacheName);
Cache<Object, Object> cache = caches.get(0);
TestingUtil.blockUntilViewsReceived(10000, caches);
if (cache.getCacheConfiguration().clustering().cacheMode().isDistributed()) {
TestingUtil.waitForNoRebalance(caches);
}
}
public void waitForClusterToForm(String cacheName, long timeout, TimeUnit timeUnit) {
List<Cache<Object, Object>> caches = getCaches(cacheName);
Cache<Object, Object> cache = caches.get(0);
TestingUtil.blockUntilViewsReceived((int) timeUnit.toMillis(timeout), false, caches);
if (cache.getCacheConfiguration().clustering().cacheMode().isDistributed()) {
TestingUtil.waitForNoRebalance(caches);
}
}
public <K,V> List<Cache<K,V>> getCaches(String cacheName) {
List<Cache<K,V>> caches = new ArrayList<Cache<K,V>>(cacheManagers.size());
for (EmbeddedCacheManager cm : cacheManagers) {
caches.add(cacheName == null ? cm.<K,V>getCache() : cm.<K,V>getCache(cacheName));
}
return caches;
}
public void addCache(GlobalConfigurationBuilder gBuilder, ConfigurationBuilder builder) {
addCache(null, gBuilder, builder);
}
public void addCache(String cacheName, GlobalConfigurationBuilder gBuilder, ConfigurationBuilder builder) {
gBuilder.site().localSite(siteName);
EmbeddedCacheManager cm = addClusterEnabledCacheManager(transportFlags(), gBuilder, builder);
if (cacheName != null)
cm.defineConfiguration(cacheName, builder.build());
}
public void kill(int index) {
TestingUtil.killCacheManagers(cacheManagers.remove(index));
}
public <K,V> Cache<K,V> cache(int index) {
return cacheManagers.get(index).getCache();
}
public <K,V> AdvancedCache<K,V> advancedCache(int index) {
Cache<K, V> cache = cache(index);
return cache.getAdvancedCache();
}
public <K, V> Cache<K, V> cache(String cacheName, int index) {
return cacheManagers.get(index).getCache(cacheName);
}
public List<EmbeddedCacheManager> cacheManagers() {
return Collections.unmodifiableList(cacheManagers);
}
}
protected TransactionTable txTable(Cache cache) {
return cache.getAdvancedCache().getComponentRegistry().getComponent(TransactionTable.class);
}
}