/* * 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.configvariations; import java.util.Arrays; import junit.framework.TestSuite; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.testframework.junits.IgniteCacheConfigVariationsAbstractTest; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.testframework.junits.IgniteConfigVariationsAbstractTest; import org.jetbrains.annotations.Nullable; /** * Configuration variations test suite builder. */ public class ConfigVariationsTestSuiteBuilder { /** */ private final TestSuite suite; /** */ @SuppressWarnings("unchecked") private ConfigParameter<IgniteConfiguration>[][] igniteParams = ConfigVariations.igniteBasicSet(); /** */ @SuppressWarnings("unchecked") private ConfigParameter<CacheConfiguration>[][] cacheParams; /** */ private CacheStartMode cacheStartMode = CacheStartMode.DYNAMIC; /** */ private boolean withClients; /** */ private int gridsCnt = 3; /** */ private int testedNodeCnt = 1; /** */ private Class<? extends IgniteConfigVariationsAbstractTest> cls; /** */ private int[] specificIgniteParam; /** */ private int[] specificCacheParam; /** */ private int backups = -1; /** */ private IgnitePredicate<IgniteConfiguration>[] igniteCfgFilters; /** */ private IgnitePredicate<CacheConfiguration>[] cacheCfgFilters; /** */ private boolean skipWaitPartMapExchange; /** * @param name Name. * @param cls Test class. */ public ConfigVariationsTestSuiteBuilder(String name, Class<? extends IgniteConfigVariationsAbstractTest> cls) { suite = new TestSuite(name); this.cls = cls; } /** * @return Test suite. */ public TestSuite build() { assert testedNodeCnt > 0; assert gridsCnt > 0; VariationsIterator igniteCfgIter; if (specificIgniteParam == null) igniteCfgIter = new VariationsIterator(igniteParams); else igniteCfgIter = new OneElementVariationsIterator(specificIgniteParam, igniteParams); for (; igniteCfgIter.hasNext(); ) { final int[] igniteCfgVariation = igniteCfgIter.next(); if (!passIgniteConfigFilter(igniteCfgVariation)) continue; if (cacheParams == null) { TestSuite addedSuite = build(igniteCfgVariation, null, true); suite.addTest(addedSuite); } else { VariationsIterator cacheCfgIter; if (specificCacheParam == null) cacheCfgIter = new VariationsIterator(cacheParams); else cacheCfgIter = new OneElementVariationsIterator(specificCacheParam, cacheParams); for (; cacheCfgIter.hasNext(); ) { int[] cacheCfgVariation = cacheCfgIter.next(); if (!passCacheConfigFilter(cacheCfgVariation)) continue; // Stop all grids before starting new ignite configuration. boolean stopNodes = !cacheCfgIter.hasNext(); TestSuite addedSuite = build(igniteCfgVariation, cacheCfgVariation, stopNodes); suite.addTest(addedSuite); } } } return suite; } /** * @param variation Variation. * @return {@code True} if variation pass filters. */ private boolean passIgniteConfigFilter(int[] variation) { ConfigVariationsFactory factory = new ConfigVariationsFactory(igniteParams, variation, null, null); IgniteConfiguration cfg = factory.getConfiguration(null, null); if (igniteCfgFilters != null) { for (IgnitePredicate<IgniteConfiguration> filter : igniteCfgFilters) { if (!filter.apply(cfg)) return false; } } return true; } /** * @param variation Variation. * @return {@code True} if variation pass filters. */ private boolean passCacheConfigFilter(int[] variation) { ConfigVariationsFactory factory = new ConfigVariationsFactory(null, null, cacheParams, variation); CacheConfiguration cfg = factory.cacheConfiguration(null); if (cacheCfgFilters != null) { for (IgnitePredicate<CacheConfiguration> filter : cacheCfgFilters) { if (!filter.apply(cfg)) return false; } } return true; } /** * @param igniteCfgVariation Ignite Variation. * @param cacheCfgVariation Cache Variation. * @param stopNodes Stop nodes. * @return Test suite. */ private TestSuite build(int[] igniteCfgVariation, @Nullable int[] cacheCfgVariation, boolean stopNodes) { ConfigVariationsFactory factory = new ConfigVariationsFactory(igniteParams, igniteCfgVariation, cacheParams, cacheCfgVariation); factory.backups(backups); String clsNameSuffix = "[igniteCfgVariation=" + Arrays.toString(igniteCfgVariation) + ", cacheCfgVariation=" + Arrays.toString(cacheCfgVariation) + ", igniteCfg=" + factory.getIgniteConfigurationDescription() + ", cacheCfg=" + factory.getCacheConfigurationDescription() + "]"; VariationsTestsConfig testCfg = new VariationsTestsConfig(factory, clsNameSuffix, stopNodes, cacheStartMode, gridsCnt, !skipWaitPartMapExchange); TestSuite addedSuite; if (testedNodeCnt > 1) addedSuite = createMultiNodeTestSuite((Class<? extends IgniteCacheConfigVariationsAbstractTest>)cls, testCfg, testedNodeCnt, withClients, skipWaitPartMapExchange); else addedSuite = new IgniteConfigVariationsTestSuite(cls, testCfg); return addedSuite; } /** * @param cls Test class. * @param cfg Configuration. * @param testedNodeCnt Count of tested nodes. */ private static TestSuite createMultiNodeTestSuite(Class<? extends IgniteCacheConfigVariationsAbstractTest> cls, VariationsTestsConfig cfg, int testedNodeCnt, boolean withClients, boolean skipWaitParMapExchange) { TestSuite suite = new TestSuite(); if (cfg.gridCount() < testedNodeCnt) throw new IllegalArgumentException("Failed to initialize test suite [nodeCnt=" + testedNodeCnt + ", cfgGridCnt=" + cfg.gridCount() + "]"); for (int i = 0; i < testedNodeCnt; i++) { boolean stopNodes = cfg.isStopNodes() && i + 1 == testedNodeCnt; boolean startCache = i == 0; boolean stopCache = i + 1 == testedNodeCnt; VariationsTestsConfig cfg0 = new VariationsTestsConfig(cfg.configurationFactory(), cfg.description(), stopNodes, startCache, stopCache, cfg.cacheStartMode(), cfg.gridCount(), i, withClients, !skipWaitParMapExchange); suite.addTest(new IgniteConfigVariationsTestSuite(cls, cfg0)); } return suite; } /** * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder withClients() { if (testedNodeCnt < 2) throw new IllegalStateException("Tested node count should be more than 1: " + testedNodeCnt); withClients = true; return this; } /** * All tests will be run for first {@code testedNodeCnt} grids. For {@code grid(0)}, {@code grid(1)}, ... , * {@code grid(testedNodeCnt - 1)}. * <p> * Usually it needs if you want to execute tests for both client and data nodes (see {@link #withClients()}). * <ul> * <li> If test-class extends {@link IgniteConfigVariationsAbstractTest} then use {@code testedNodesCount(2)}. </li> * <li> if test-class extends {@link IgniteCacheConfigVariationsAbstractTest} then use {@code testedNodesCount(3)}. </li> *</ul> * * @param testedNodeCnt Tested node count. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder testedNodesCount(int testedNodeCnt) { this.testedNodeCnt = testedNodeCnt; return this; } /** * @param cnt Count. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder gridsCount(int cnt) { assert cnt > 0; gridsCnt = cnt; return this; } /** * @param igniteParams New ignite params. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder igniteParams( ConfigParameter<IgniteConfiguration>[][] igniteParams) { this.igniteParams = igniteParams; return this; } /** * @param cacheParams New cache params. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder cacheParams(ConfigParameter<CacheConfiguration>[][] cacheParams) { this.cacheParams = cacheParams; return this; } /** * Sets basic cache params and basic count of backups. * * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder withBasicCacheParams() { cacheParams = ConfigVariations.cacheBasicSet(); backups = 1; return this; } /** * @param backups Backups. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder backups(int backups) { assert backups > 0 : backups; this.backups = backups; return this; } /** * @param singleIgniteParam Param. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder specifyIgniteParam(int... singleIgniteParam) { specificIgniteParam = singleIgniteParam; return this; } /** * @param singleParam Param. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder specifyCacheParam(int... singleParam) { specificCacheParam = singleParam; return this; } /** * @param filters Ignite configuration filters. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder withIgniteConfigFilters(IgnitePredicate<IgniteConfiguration>... filters) { igniteCfgFilters = filters; return this; } public ConfigVariationsTestSuiteBuilder skipWaitPartitionMapExchange() { skipWaitPartMapExchange = true; return this; } /** * @param filters Ignite configuration filters. * @return {@code this} for chaining. */ public ConfigVariationsTestSuiteBuilder withCacheConfigFilters(IgnitePredicate<CacheConfiguration>... filters) { cacheCfgFilters = filters; return this; } /** * */ private static class OneElementVariationsIterator extends VariationsIterator { /** */ private int[] elem; /** */ private boolean hasNext = true; /** * @param elem Element. */ OneElementVariationsIterator(int[] elem, Object[][] params) { super(params); this.elem = elem; } /** {@inheritDoc} */ @Override public boolean hasNext() { return hasNext; } /** {@inheritDoc} */ @Override public int[] next() { hasNext = false; return elem; } } }