http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteCacheConfigVariationsAbstractTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteCacheConfigVariationsAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteCacheConfigVariationsAbstractTest.java new file mode 100644 index 0000000..28c6f55 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteCacheConfigVariationsAbstractTest.java @@ -0,0 +1,583 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.testframework.junits; + +import java.util.Map; +import javax.cache.Cache; +import javax.cache.configuration.Factory; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteTransactions; +import org.apache.ignite.Ignition; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMemoryMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.CachePeekMode; +import org.apache.ignite.cache.store.CacheStore; +import org.apache.ignite.cache.store.CacheStoreAdapter; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.configuration.NearCacheConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.util.lang.GridAbsPredicateX; +import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiInClosure; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.configvariations.CacheStartMode; +import org.apache.ignite.transactions.Transaction; +import org.jetbrains.annotations.Nullable; +import org.jsr166.ConcurrentHashMap8; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheMemoryMode.OFFHEAP_TIERED; +import static org.apache.ignite.cache.CacheMemoryMode.ONHEAP_TIERED; + +/** + * Abstract class for cache configuration variations tests. + */ +public abstract class IgniteCacheConfigVariationsAbstractTest extends IgniteConfigVariationsAbstractTest { + /** */ + protected static final int CLIENT_NEAR_ONLY_IDX = 2; + + /** Test timeout. */ + private static final long TEST_TIMEOUT = 30 * 1000; + + /** Store map. */ + protected static final Map<Object, Object> map = new ConcurrentHashMap8<>(); + + /** {@inheritDoc} */ + @Override protected long getTestTimeout() { + return TEST_TIMEOUT; + } + + /** {@inheritDoc} */ + @Override protected final void beforeTestsStarted() throws Exception { + assert testsCfg != null; + assert !testsCfg.withClients() || testsCfg.gridCount() >= 3; + + assert testsCfg.testedNodeIndex() >= 0 : "testedNodeIdx: " + testedNodeIdx; + + testedNodeIdx = testsCfg.testedNodeIndex(); + + if (testsCfg.isStartCache()) { + final CacheStartMode cacheStartMode = testsCfg.cacheStartMode(); + final int cnt = testsCfg.gridCount(); + + if (cacheStartMode == CacheStartMode.STATIC) { + info("All nodes will be stopped, new " + cnt + " nodes will be started."); + + Ignition.stopAll(true); + + for (int i = 0; i < cnt; i++) { + String gridName = getTestGridName(i); + + IgniteConfiguration cfg = optimize(getConfiguration(gridName)); + + if (i != CLIENT_NODE_IDX && i != CLIENT_NEAR_ONLY_IDX) { + CacheConfiguration cc = testsCfg.configurationFactory().cacheConfiguration(gridName); + + cc.setName(cacheName()); + + cfg.setCacheConfiguration(cc); + } + + startGrid(gridName, cfg, null); + } + + if (testsCfg.withClients() && testsCfg.gridCount() > CLIENT_NEAR_ONLY_IDX) + grid(CLIENT_NEAR_ONLY_IDX).createNearCache(cacheName(), new NearCacheConfiguration()); + } + else if (cacheStartMode == null || cacheStartMode == CacheStartMode.DYNAMIC) { + super.beforeTestsStarted(); + + startCachesDinamically(); + } + else + throw new IllegalArgumentException("Unknown cache start mode: " + cacheStartMode); + } + + if (testsCfg.gridCount() > 1) + checkTopology(testsCfg.gridCount()); + + awaitPartitionMapExchange(); + + for (int i = 0; i < gridCount(); i++) + info("Grid " + i + ": " + grid(i).localNode().id()); + + if (testsCfg.withClients()) { + boolean testedNodeNearEnabled = grid(testedNodeIdx).cachex(cacheName()).context().isNear(); + + if (testedNodeIdx != SERVER_NODE_IDX) + assertEquals(testedNodeIdx == CLIENT_NEAR_ONLY_IDX, testedNodeNearEnabled); + + info(">>> Starting set of tests [testedNodeIdx=" + testedNodeIdx + + ", id=" + grid(testedNodeIdx).localNode().id() + + ", isClient=" + grid(testedNodeIdx).configuration().isClientMode() + + ", nearEnabled=" + testedNodeNearEnabled + "]"); + } + } + + /** + * Starts caches dinamically. + */ + private void startCachesDinamically() throws Exception { + for (int i = 0; i < gridCount(); i++) { + info("Starting cache dinamically on grid: " + i); + + IgniteEx grid = grid(i); + + if (i != CLIENT_NODE_IDX && i != CLIENT_NEAR_ONLY_IDX) { + CacheConfiguration cc = testsCfg.configurationFactory().cacheConfiguration(grid.name()); + + cc.setName(cacheName()); + + grid.getOrCreateCache(cc); + } + + if (testsCfg.withClients() && i == CLIENT_NEAR_ONLY_IDX) + grid(CLIENT_NEAR_ONLY_IDX).createNearCache(cacheName(), new NearCacheConfiguration()); + } + + awaitPartitionMapExchange(); + + for (int i = 0; i < gridCount(); i++) + assertNotNull(jcache(i)); + + for (int i = 0; i < gridCount(); i++) + assertEquals("Cache is not empty [idx=" + i + ", entrySet=" + jcache(i).localEntries() + ']', + 0, jcache(i).localSize(CachePeekMode.ALL)); + } + + /** {@inheritDoc} */ + @Override protected boolean expectedClient(String testGridName) { + return getTestGridName(CLIENT_NODE_IDX).equals(testGridName) + || getTestGridName(CLIENT_NEAR_ONLY_IDX).equals(testGridName); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + if (testsCfg.isStopCache()) { + for (int i = 0; i < gridCount(); i++) { + info("Destroing cache on grid: " + i); + + IgniteCache<String, Integer> cache = jcache(i); + + assert i != 0 || cache != null; + + if (cache != null) + cache.destroy(); + } + } + + map.clear(); + + super.afterTestsStopped(); + } + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + awaitPartitionMapExchange(); + + assert jcache().unwrap(Ignite.class).transactions().tx() == null; + + assertEquals(0, jcache().localSize()); + assertEquals(0, jcache().size()); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + Transaction tx = jcache().unwrap(Ignite.class).transactions().tx(); + + if (tx != null) { + tx.close(); + + fail("Cache transaction remained after test completion: " + tx); + } + + String cacheIsNotEmptyMsg = null; + + for (int i = 0; i < gridCount(); i++) { + info("Checking grid: " + i); + + while (true) { + try { + final int fi = i; + + boolean cacheIsEmpty = GridTestUtils.waitForCondition( + // Preloading may happen as nodes leave, so we need to wait. + new GridAbsPredicateX() { + @Override public boolean applyx() throws IgniteCheckedException { + jcache(fi).removeAll(); + + if (jcache(fi).size(CachePeekMode.ALL) > 0) { + for (Cache.Entry<?, ?> k : jcache(fi).localEntries()) + jcache(fi).remove(k.getKey()); + } + + int locSize = jcache(fi).localSize(CachePeekMode.ALL); + + if (locSize != 0) { + info(">>>>> Debug localSize for grid: " + fi + " is " + locSize); + info(">>>>> Debug ONHEAP localSize for grid: " + fi + " is " + + jcache(fi).localSize(CachePeekMode.ONHEAP)); + info(">>>>> Debug OFFHEAP localSize for grid: " + fi + " is " + + jcache(fi).localSize(CachePeekMode.OFFHEAP)); + info(">>>>> Debug PRIMARY localSize for grid: " + fi + " is " + + jcache(fi).localSize(CachePeekMode.PRIMARY)); + info(">>>>> Debug BACKUP localSize for grid: " + fi + " is " + + jcache(fi).localSize(CachePeekMode.BACKUP)); + info(">>>>> Debug NEAR localSize for grid: " + fi + " is " + + jcache(fi).localSize(CachePeekMode.NEAR)); + info(">>>>> Debug SWAP localSize for grid: " + fi + " is " + + jcache(fi).localSize(CachePeekMode.SWAP)); + } + + return locSize == 0; + } + }, 10_000); + + if (cacheIsEmpty) + assertTrue("Cache is not empty: " + " localSize = " + jcache(fi).localSize(CachePeekMode.ALL) + + ", local entries " + entrySet(jcache(fi).localEntries()), cacheIsEmpty); + + int primaryKeySize = jcache(i).localSize(CachePeekMode.PRIMARY); + int keySize = jcache(i).localSize(); + int size = jcache(i).localSize(); + int globalSize = jcache(i).size(); + int globalPrimarySize = jcache(i).size(CachePeekMode.PRIMARY); + + info("Size after [idx=" + i + + ", size=" + size + + ", keySize=" + keySize + + ", primarySize=" + primaryKeySize + + ", globalSize=" + globalSize + + ", globalPrimarySize=" + globalPrimarySize + + ", entrySet=" + jcache(i).localEntries() + ']'); + + if (!cacheIsEmpty) { + cacheIsNotEmptyMsg = "Cache is not empty: localSize = " + + jcache(fi).localSize(CachePeekMode.ALL) + ", local entries " + + entrySet(jcache(fi).localEntries()); + + break; + } + + assertEquals("Cache is not empty [idx=" + i + ", entrySet=" + jcache(i).localEntries() + ']', + 0, jcache(i).localSize(CachePeekMode.ALL)); + + break; + } + catch (Exception e) { + if (X.hasCause(e, ClusterTopologyCheckedException.class)) { + info("Got topology exception while tear down (will retry in 1000ms)."); + + U.sleep(1000); + } + else + throw e; + } + } + + if (cacheIsNotEmptyMsg != null) + break; + + for (Cache.Entry entry : jcache(i).localEntries(CachePeekMode.SWAP)) + jcache(i).remove(entry.getKey()); + } + + assert jcache().unwrap(Ignite.class).transactions().tx() == null; + + if (cacheIsNotEmptyMsg == null) + assertEquals("Cache is not empty", 0, jcache().localSize(CachePeekMode.ALL)); + + resetStore(); + + // Restore cache if current cache has garbage. + if (cacheIsNotEmptyMsg != null) { + for (int i = 0; i < gridCount(); i++) { + info("Destroing cache on grid: " + i); + + IgniteCache<String, Integer> cache = jcache(i); + + assert i != 0 || cache != null; + + if (cache != null) + cache.destroy(); + } + + assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicateX() { + @Override public boolean applyx() { + for (int i = 0; i < gridCount(); i++) { + if (jcache(i) != null) + return false; + } + + return true; + } + }, 10_000)); + + startCachesDinamically(); + + log.warning(cacheIsNotEmptyMsg); + + throw new IllegalStateException(cacheIsNotEmptyMsg); + } + + assertEquals(0, jcache().localSize()); + assertEquals(0, jcache().size()); + } + + /** + * Cleans up cache store. + */ + protected void resetStore() { + map.clear(); + } + + /** + * Put entry to cache store. + * + * @param key Key. + * @param val Value. + */ + protected void putToStore(Object key, Object val) { + if (!storeEnabled()) + throw new IllegalStateException("Failed to put to store because store is disabled."); + + map.put(key, val); + } + + /** + * @return Default cache mode. + */ + protected CacheMode cacheMode() { + CacheMode mode = cacheConfiguration().getCacheMode(); + + return mode == null ? CacheConfiguration.DFLT_CACHE_MODE : mode; + } + + /** + * @return Load previous value flag. + */ + protected boolean isLoadPreviousValue() { + return cacheConfiguration().isLoadPreviousValue(); + } + + /** + * @return Cache atomicity mode. + */ + protected CacheAtomicityMode atomicityMode() { + return cacheConfiguration().getAtomicityMode(); + } + + /** + * @return {@code True} if values should be stored off-heap. + */ + protected CacheMemoryMode memoryMode() { + return cacheConfiguration().getMemoryMode(); + } + + /** + * @return {@code True} if swap should happend after localEvict() call. + */ + protected boolean swapAfterLocalEvict() { + if (memoryMode() == OFFHEAP_TIERED) + return false; + + return memoryMode() == ONHEAP_TIERED ? (!offheapEnabled() && swapEnabled()) : swapEnabled(); + } + + /** + * @return {@code True} if store is enabled. + */ + protected boolean storeEnabled() { + return cacheConfiguration().getCacheStoreFactory() != null; + } + + /** + * @return {@code True} if offheap memory is enabled. + */ + protected boolean offheapEnabled() { + return cacheConfiguration().getOffHeapMaxMemory() >= 0; + } + + /** + * @return {@code True} if swap is enabled. + */ + protected boolean swapEnabled() { + return cacheConfiguration().isSwapEnabled(); + } + + /** + * @return Write through storage emulator. + */ + public static CacheStore<?, ?> cacheStore() { + return new CacheStoreAdapter<Object, Object>() { + @Override public void loadCache(IgniteBiInClosure<Object, Object> clo, + Object... args) { + for (Map.Entry<Object, Object> e : map.entrySet()) + clo.apply(e.getKey(), e.getValue()); + } + + @Override public Object load(Object key) { + return map.get(key); + } + + @Override public void write(Cache.Entry<? extends Object, ? extends Object> e) { + map.put(e.getKey(), e.getValue()); + } + + @Override public void delete(Object key) { + map.remove(key); + } + }; + } + + /** + * @return {@code true} if near cache should be enabled. + */ + protected boolean nearEnabled() { + return grid(testedNodeIdx).cachex(cacheName()).context().isNear(); + } + + /** + * @return {@code True} if transactions are enabled. + * @see #txShouldBeUsed() + */ + protected boolean txEnabled() { + return atomicityMode() == TRANSACTIONAL; + } + + /** + * @return Cache configuration. + */ + protected CacheConfiguration cacheConfiguration() { + return testsCfg.configurationFactory().cacheConfiguration(getTestGridName(testedNodeIdx)); + } + + /** + * @return {@code True} if transactions should be used. + */ + protected boolean txShouldBeUsed() { + return txEnabled() && !isMultiJvm(); + } + + /** + * @return {@code True} if locking is enabled. + */ + protected boolean lockingEnabled() { + return txEnabled(); + } + + /** + * @return Default cache instance. + */ + @SuppressWarnings({"unchecked"}) + @Override protected <K, V> IgniteCache<K, V> jcache() { + return jcache(testedNodeIdx); + } + + /** + * @return A not near-only cache. + */ + protected IgniteCache<String, Integer> serverNodeCache() { + return jcache(SERVER_NODE_IDX); + } + + /** + * @return Cache name. + */ + protected String cacheName() { + return "testcache-" + testsCfg.description().hashCode(); + } + + /** + * @return Transactions instance. + */ + protected IgniteTransactions transactions() { + return grid(0).transactions(); + } + + /** + * @param idx Index of grid. + * @return Default cache. + */ + @SuppressWarnings({"unchecked"}) + @Override protected <K, V> IgniteCache<K, V> jcache(int idx) { + return ignite(idx).cache(cacheName()); + } + + /** + * @param idx Index of grid. + * @return Cache context. + */ + protected GridCacheContext<String, Integer> context(final int idx) { + if (isRemoteJvm(idx) && !isRemoteJvm()) + throw new UnsupportedOperationException("Operation can't be done automatically via proxy. " + + "Send task with this logic on remote jvm instead."); + + return ((IgniteKernal)grid(idx)).<String, Integer>internalCache(cacheName()).context(); + } + + /** + * @param cache Cache. + * @return {@code True} if cache has OFFHEAP_TIERED memory mode. + */ + protected static <K, V> boolean offheapTiered(IgniteCache<K, V> cache) { + return cache.getConfiguration(CacheConfiguration.class).getMemoryMode() == OFFHEAP_TIERED; + } + + /** + * Executes regular peek or peek from swap. + * + * @param cache Cache projection. + * @param key Key. + * @return Value. + */ + @Nullable protected static <K, V> V peek(IgniteCache<K, V> cache, K key) { + return offheapTiered(cache) ? cache.localPeek(key, CachePeekMode.SWAP, CachePeekMode.OFFHEAP) : + cache.localPeek(key, CachePeekMode.ONHEAP); + } + + /** + * @param cache Cache. + * @param key Key. + * @return {@code True} if cache contains given key. + * @throws Exception If failed. + */ + @SuppressWarnings("unchecked") + protected static boolean containsKey(IgniteCache cache, Object key) throws Exception { + return offheapTiered(cache) ? cache.localPeek(key, CachePeekMode.OFFHEAP) != null : cache.containsKey(key); + } + + /** + * Serializable factory. + */ + public static class TestStoreFactory implements Factory<CacheStore> { + @Override public CacheStore create() { + return cacheStore(); + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteConfigVariationsAbstractTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteConfigVariationsAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteConfigVariationsAbstractTest.java new file mode 100644 index 0000000..b22f289 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteConfigVariationsAbstractTest.java @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.testframework.junits; + +import java.io.Externalizable; +import java.io.File; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Serializable; +import org.apache.commons.io.FileUtils; +import org.apache.ignite.Ignition; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.testframework.configvariations.VariationsTestsConfig; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** + * Common abstract test for Ignite tests based on configurations variations. + */ +public abstract class IgniteConfigVariationsAbstractTest extends GridCommonAbstractTest { + /** */ + protected static final int SERVER_NODE_IDX = 0; + + /** */ + protected static final int CLIENT_NODE_IDX = 1; + + /** */ + protected int testedNodeIdx; + + /** */ + private static final File workDir = new File(U.getIgniteHome() + File.separator + "workOfConfigVariationsTests"); + + /** */ + protected VariationsTestsConfig testsCfg; + + /** */ + protected volatile DataMode dataMode; + + /** + * @param testsCfg Tests configuration. + */ + public void setTestsConfiguration(VariationsTestsConfig testsCfg) { + assert this.testsCfg == null : "Test config must be set only once [oldTestCfg=" + this.testsCfg + + ", newTestCfg=" + testsCfg + "]"; + + this.testsCfg = testsCfg; + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + assert testsCfg != null; + + FileUtils.deleteDirectory(workDir); + + info("Ignite's 'work' directory has been cleaned."); + + if (Ignition.allGrids().size() != testsCfg.gridCount()) { + info("All nodes will be stopped, new " + testsCfg.gridCount() + " nodes will be started."); + + Ignition.stopAll(true); + + startGrids(testsCfg.gridCount()); + + for (int i = 0; i < testsCfg.gridCount(); i++) + info("Grid " + i + ": " + grid(i).localNode().id()); + } + + assert testsCfg.testedNodeIndex() >= 0 : "testedNodeIdx: " + testedNodeIdx; + + testedNodeIdx = testsCfg.testedNodeIndex(); + + if (testsCfg.withClients()) { + for (int i = 0; i < gridCount(); i++) + assertEquals("i: " + i, expectedClient(getTestGridName(i)), + (boolean)grid(i).configuration().isClientMode()); + } + } + + /** + * @param testGridName Name. + * @return {@code True} if node is client should be client. + */ + protected boolean expectedClient(String testGridName) { + return getTestGridName(CLIENT_NODE_IDX).equals(testGridName); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + if (testsCfg.isStopNodes()) { + info("Stopping all grids..."); + + stopAllGrids(); + + FileUtils.deleteDirectory(workDir); + + info("Ignite's 'work' directory has been cleaned."); + + memoryUsage(); + + System.gc(); + + memoryUsage(); + } + } + + /** + * Prints memory usage. + */ + private void memoryUsage() { + int mb = 1024 * 1024; + + Runtime runtime = Runtime.getRuntime(); + + info("##### Heap utilization statistics [MB] #####"); + info("Used Memory (mb): " + (runtime.totalMemory() - runtime.freeMemory()) / mb); + info("Free Memory (mb): " + runtime.freeMemory() / mb); + info("Total Memory (mb): " + runtime.totalMemory() / mb); + info("Max Memory (mb): " + runtime.maxMemory() / mb); + } + + /** {@inheritDoc} */ + @Override protected String testClassDescription() { + return super.testClassDescription() + '-' + testsCfg.description() + '-' + testsCfg.gridCount() + "-node(s)"; + } + + /** {@inheritDoc} */ + @Override protected String testDescription() { + return super.testDescription() + '-' + testsCfg.description() + '-' + testsCfg.gridCount() + "-node(s)"; + } + + /** {@inheritDoc} */ + @Override protected final IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(gridName); + + IgniteConfiguration resCfg = testsCfg.configurationFactory().getConfiguration(gridName, cfg); + + resCfg.setWorkDirectory(workDir.getAbsolutePath()); + + if (testsCfg.withClients()) + resCfg.setClientMode(expectedClient(gridName)); + + return resCfg; + } + + /** {@inheritDoc} */ + protected final int gridCount() { + return testsCfg.gridCount(); + } + + /** + * @return Count of clients. + */ + protected int clientsCount() { + int cnt = 0; + + for (int i = 0; i < gridCount(); i++) { + if (grid(i).configuration().isClientMode()) + cnt++; + } + + return cnt; + } + + /** {@inheritDoc} */ + @Override protected IgniteEx grid() { + throw new UnsupportedOperationException("Not supported, grid(int idx) or testedGrid() should be used instead."); + } + + /** + * @return Grid which should be tested. + */ + protected IgniteEx testedGrid() { + return grid(testedNodeIdx); + } + + /** + * Runs in all data modes. + */ + protected void runInAllDataModes(TestRunnable call) throws Exception { + for (int i = 0; i < DataMode.values().length; i++) { + dataMode = DataMode.values()[i]; + + info("Running test in data mode: " + dataMode); + + if (i != 0) + beforeTest(); + + try { + call.run(); + } + finally { + if (i + 1 != DataMode.values().length) + afterTest(); + } + } + } + + /** + * @param keyId Key Id. + * @return Key. + */ + public Object key(int keyId) { + return key(keyId, dataMode); + } + + /** + * @param valId Key Id. + * @return Value. + */ + public Object value(int valId) { + return value(valId, dataMode); + } + + /** + * @param keyId Key Id. + * @param mode Mode. + * @return Key. + */ + public static Object key(int keyId, DataMode mode) { + switch (mode) { + case SERIALIZABLE: + return new SerializableObject(keyId); + case EXTERNALIZABLE: + return new ExternalizableObject(keyId); + case PLANE_OBJECT: + return new TestObject(keyId); + default: + throw new IllegalArgumentException("mode: " + mode); + } + } + + /** + * @param obj Key or value object + * @return Value. + */ + public static int valueOf(Object obj) { + if (obj instanceof TestObject) + return ((TestObject)obj).value(); + else + throw new IllegalStateException(); + } + + /** + * @param idx Index. + * @param mode Mode. + * @return Value. + */ + public static Object value(int idx, DataMode mode) { + switch (mode) { + case SERIALIZABLE: + return new SerializableObject(idx); + case EXTERNALIZABLE: + return new ExternalizableObject(idx); + case PLANE_OBJECT: + return new TestObject(idx); + default: + throw new IllegalArgumentException("mode: " + mode); + } + } + + /** + * + */ + public static class TestObject { + /** */ + protected int val; + + /** */ + protected String strVal; + + /** */ + protected TestEnum enumVal; + + /** + * @param val Value. + */ + TestObject(int val) { + this.val = val; + strVal = "val" + val; + + TestEnum[] values = TestEnum.values(); + enumVal = values[Math.abs(val) % values.length]; + } + + /** + * @return Value. + */ + public int value() { + return val; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (!(o instanceof TestObject)) + return false; + + TestObject val = (TestObject)o; + + return getClass().equals(o.getClass()) && this.val == val.val && enumVal == val.enumVal + && strVal.equals(val.strVal); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return val; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return getClass().getSimpleName() + "[" + + "val=" + val + + ", strVal='" + strVal + '\'' + + ", enumVal=" + enumVal + + ']'; + } + } + + /** + * + */ + protected static class SerializableObject extends TestObject implements Serializable { + /** + * @param val Value. + */ + public SerializableObject(int val) { + super(val); + } + } + + /** + * + */ + private static class ExternalizableObject extends TestObject implements Externalizable { + /** + * Default constructor. + */ + ExternalizableObject() { + super(-1); + } + + /** + * @param val Value. + */ + ExternalizableObject(int val) { + super(val); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(val); + out.writeObject(strVal); + out.writeObject(enumVal); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + val = in.readInt(); + strVal = (String)in.readObject(); + enumVal = (TestEnum)in.readObject(); + } + } + + /** + * Data mode. + */ + public enum DataMode { + /** Serializable objects. */ + SERIALIZABLE, + + /** Externalizable objects. */ + EXTERNALIZABLE, + + /** Objects without Serializable and Externalizable. */ + PLANE_OBJECT + } + + /** + * + */ + private enum TestEnum { + /** */ + TEST_VALUE_1, + + /** */ + TEST_VALUE_2, + + /** */ + TEST_VALUE_3 + } + + /** + * + */ + public static interface TestRunnable { + /** + * @throws Exception If failed. + */ + public void run() throws Exception; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testframework/test/ConfigVariationsTestSuiteBuilderTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/test/ConfigVariationsTestSuiteBuilderTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/test/ConfigVariationsTestSuiteBuilderTest.java new file mode 100644 index 0000000..75e3010 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testframework/test/ConfigVariationsTestSuiteBuilderTest.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.testframework.test; + +import java.util.concurrent.atomic.AtomicInteger; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.testframework.configvariations.ConfigVariationsTestSuiteBuilder; +import org.apache.ignite.testframework.junits.IgniteConfigVariationsAbstractTest; + +/** + * + */ +public class ConfigVariationsTestSuiteBuilderTest extends TestCase { + /** + * @throws Exception If failed. + */ + public void testDefaults() throws Exception { + TestSuite dfltSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class).build(); + + assertEquals(4, dfltSuite.countTestCases()); + + TestSuite dfltCacheSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class) + .withBasicCacheParams().build(); + + assertEquals(4 * 12, dfltCacheSuite.countTestCases()); + + // With clients. + dfltSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class) + .testedNodesCount(2).withClients().build(); + + assertEquals(4 * 2, dfltSuite.countTestCases()); + + dfltCacheSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class) + .withBasicCacheParams().testedNodesCount(3).withClients().build(); + + assertEquals(4 * 12 * 3, dfltCacheSuite.countTestCases()); + } + + /** + * @throws Exception If failed. + */ + @SuppressWarnings("serial") + public void testIgniteConfigFilter() throws Exception { + TestSuite dfltSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class).build(); + + final AtomicInteger cnt = new AtomicInteger(); + + TestSuite filteredSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class) + .withIgniteConfigFilters(new IgnitePredicate<IgniteConfiguration>() { + @Override public boolean apply(IgniteConfiguration configuration) { + return cnt.getAndIncrement() % 2 == 0; + } + }) + .build(); + + assertEquals(dfltSuite.countTestCases() / 2, filteredSuite.countTestCases()); + } + + /** + * @throws Exception If failed. + */ + @SuppressWarnings("serial") + public void testCacheConfigFilter() throws Exception { + TestSuite dfltSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class) + .withBasicCacheParams() + .build(); + + final AtomicInteger cnt = new AtomicInteger(); + + TestSuite filteredSuite = new ConfigVariationsTestSuiteBuilder("testSuite", OneTestCase.class) + .withBasicCacheParams() + .withCacheConfigFilters(new IgnitePredicate<CacheConfiguration>() { + @Override public boolean apply(CacheConfiguration configuration) { + return cnt.getAndIncrement() % 2 == 0; + } + }) + .build(); + + assertEquals(dfltSuite.countTestCases() / 2, filteredSuite.countTestCases()); + } + + /** + * + */ + private static class OneTestCase extends IgniteConfigVariationsAbstractTest { + /** + * @throws Exception If failed. + */ + public void test1() throws Exception { + // No-op. + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testframework/test/ParametersTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/test/ParametersTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/test/ParametersTest.java new file mode 100644 index 0000000..2870b06 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testframework/test/ParametersTest.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.testframework.test; + +import java.util.HashSet; +import java.util.Set; +import junit.framework.TestCase; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.testframework.configvariations.ConfigParameter; +import org.apache.ignite.testframework.configvariations.Parameters; + +/** + * Test. + */ +public class ParametersTest extends TestCase { + /** + * @throws Exception If failed. + */ + public void testEnumVariations() throws Exception { + ConfigParameter<CacheConfiguration>[] modes = Parameters.enumParameters("setCacheMode", CacheMode.class); + + assertEquals(CacheMode.values().length, modes.length); + + Set<CacheMode> res = new HashSet<>(); + + for (ConfigParameter<CacheConfiguration> modeApplier : modes) { + CacheConfiguration cfg = new CacheConfiguration(); + + modeApplier.apply(cfg); + + CacheMode mode = cfg.getCacheMode(); + + res.add(mode); + + System.out.println(">>> " + mode); + } + + assertEquals(modes.length, res.size()); + } + + /** + * @throws Exception If failed. + */ + @SuppressWarnings("unchecked") + public void testEnumVariationsWithNull() throws Exception { + ConfigParameter<CacheConfiguration>[] cfgParam = + Parameters.enumParameters(true, "setCacheMode", CacheMode.class); + + assertEquals(CacheMode.values().length + 1, cfgParam.length); + + cfgParam[0] = null; + + Set<CacheMode> set = new HashSet<>(); + + for (int i = 1; i < cfgParam.length; i++) { + ConfigParameter<CacheConfiguration> modeApplier = cfgParam[i]; + + CacheConfiguration cfg = new CacheConfiguration(); + + modeApplier.apply(cfg); + + CacheMode mode = cfg.getCacheMode(); + + set.add(mode); + + System.out.println(">>> " + mode); + } + + assertEquals(CacheMode.values().length, set.size()); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testframework/test/VariationsIteratorTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/test/VariationsIteratorTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/test/VariationsIteratorTest.java new file mode 100644 index 0000000..d8ac2b3 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testframework/test/VariationsIteratorTest.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.testframework.test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import junit.framework.TestCase; +import org.apache.ignite.testframework.configvariations.VariationsIterator; + +/** + * Test start iterator. + */ +public class VariationsIteratorTest extends TestCase { + /** + * @throws Exception If failed. + */ + public void test1() throws Exception { + Object[][] arr = new Object[][] { + {0, 1}, + {0, 1}, + {0, 1}, + }; + + checkIterator(arr); + } + + /** + * @throws Exception If failed. + */ + @SuppressWarnings("PointlessArithmeticExpression") + public void test2() throws Exception { + Object[][] arr = new Object[][] { + {0}, + {0, 1, 2}, + {0, 1}, + {0, 1, 2, 3, 4, 5}, + }; + + checkIterator(arr); + } + + /** + * @throws Exception If failed. + */ + @SuppressWarnings("PointlessArithmeticExpression") + public void test3() throws Exception { + Object[][] arr = new Object[][] { + {0, 1, 2, 3, 4, 5}, + {0, 1, 2}, + {0, 1}, + {0}, + }; + + checkIterator(arr); + } + + /** + * @throws Exception If failed. + */ + @SuppressWarnings("PointlessArithmeticExpression") + public void test4() throws Exception { + Object[][] arr = new Object[][]{ + {0,1,2}, + {0,1}, + {0,1,2,4}, + {0,1}, + {0}, + {0}, + {0,1,2,4}, + }; + + checkIterator(arr); + } + + /** + * @throws Exception If failed. + */ + public void testSimple() throws Exception { + Object[][] arr = new Object[][] { + {0}, + }; + + checkIterator(arr); + } + + /** + * @throws Exception If failed. + */ + public void testSimple2() throws Exception { + Object[][] arr = new Object[][] { + {0}, + {0}, + }; + + checkIterator(arr); + } + + /** + * @param arr Array. + */ + private void checkIterator(Object[][] arr) { + int expSize = 1; + int significantParamsCnt = 1; + + for (int i = 0; i < arr.length; i++) { + Object[] objects = arr[i]; + + System.out.println(">>> " + i + ": " + objects.length); + + expSize *= objects.length; + + if (objects.length > 1) + significantParamsCnt++; + } + + System.out.println("Iteration info [expSize=" + expSize + ", significantParamsCnt=" + significantParamsCnt + "]"); + + Set<int[]> states = new HashSet<>(); + + int step = 0; + + for (VariationsIterator it = new VariationsIterator(arr); it.hasNext(); ) { + int[] state = it.next(); + + System.out.println(Arrays.toString(state)); + + for (int[] state2 : states) { + if (Arrays.equals(state, state2)) + fail("Got equal states on step " + step + " [state=" + Arrays.toString(state) + + ", state2=" + Arrays.toString(state2)); + } + + states.add(state); + + step++; + } + + assertEquals(expSize, states.size()); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java index 3903910..9e2324c 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java @@ -51,6 +51,9 @@ import org.apache.ignite.messaging.GridMessagingSelfTest; import org.apache.ignite.messaging.IgniteMessagingWithClientTest; import org.apache.ignite.spi.GridSpiLocalHostInjectionTest; import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.test.ConfigVariationsTestSuiteBuilderTest; +import org.apache.ignite.testframework.test.ParametersTest; +import org.apache.ignite.testframework.test.VariationsIteratorTest; /** * Basic test suite. @@ -121,6 +124,11 @@ public class IgniteBasicTestSuite extends TestSuite { GridTestUtils.addTestIfNeeded(suite, DynamicProxySerializationMultiJvmSelfTest.class, ignoredTests); + // Tests against configuration variations framework. + suite.addTestSuite(ParametersTest.class); + suite.addTestSuite(VariationsIteratorTest.class); + suite.addTestSuite(ConfigVariationsTestSuiteBuilderTest.class); + return suite; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/953b575f/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheBasicConfigVariationsFullApiTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheBasicConfigVariationsFullApiTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheBasicConfigVariationsFullApiTestSuite.java new file mode 100644 index 0000000..85a8f59 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheBasicConfigVariationsFullApiTestSuite.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.testsuites; + +import junit.framework.TestSuite; +import org.apache.ignite.internal.processors.cache.IgniteCacheConfigVariationsFullApiTest; +import org.apache.ignite.testframework.configvariations.ConfigVariationsTestSuiteBuilder; + +/** + * Test suite for cache API. + */ +public class IgniteCacheBasicConfigVariationsFullApiTestSuite extends TestSuite { + /** + * @return Cache API test suite. + * @throws Exception If failed. + */ + public static TestSuite suite() throws Exception { + return new ConfigVariationsTestSuiteBuilder( + "Cache New Full API Test Suite", + IgniteCacheConfigVariationsFullApiTest.class) + .withBasicCacheParams() + .gridsCount(5).backups(1) + .testedNodesCount(3).withClients() + .build(); + } +}
