Added support for dynamic transport client ratio in tests.

Currently tests only run with node clients but eventually we want to
run all tests with randomly choosen node / transport clients. To enable
this during development and on test servers as a transition phase this
commit adds the ability to allow a fraction of the clients used in
tests to be transport clients. By default this is still disabled.
To enable transport clients in tests pass '-Dtests.client.ratio=[0..1]'
where '1.0' will force transport clients and '0.0' completely disables
them. If an empty string is passed the ratio is chosen at random for
each test.
This commit is contained in:
Simon Willnauer 2013-09-22 22:16:53 +02:00
parent ab6715b292
commit 5a365795ec
7 changed files with 57 additions and 44 deletions

View File

@ -34,6 +34,7 @@
<tests.jvms>1</tests.jvms>
<tests.shuffle>true</tests.shuffle>
<tests.output>onerror</tests.output>
<tests.client.ratio>0.0</tests.client.ratio>
<es.logger.level>INFO</es.logger.level>
</properties>
@ -389,6 +390,7 @@
<tests.showSuccess>${tests.showSuccess}</tests.showSuccess>
<tests.integration>${tests.integration}</tests.integration>
<tests.cluster_seed>${tests.cluster_seed}</tests.cluster_seed>
<tests.client.ratio>${tests.client.ratio}</tests.client.ratio>
<es.node.local>${env.ES_TEST_LOCAL}</es.node.local>
<es.node.mode>${es.node.mode}</es.node.mode>
<es.logger.level>${es.logger.level}</es.logger.level>

View File

@ -36,7 +36,7 @@ import org.elasticsearch.index.store.fs.NioFsDirectoryService;
import org.elasticsearch.index.store.fs.SimpleFsDirectoryService;
import org.elasticsearch.index.store.memory.ByteBufferDirectoryService;
import org.elasticsearch.index.store.ram.RamDirectoryService;
import org.elasticsearch.test.ElasticSearchTestCase;
import org.elasticsearch.test.AbstractIntegrationTest;
import java.util.Random;
import java.util.Set;
@ -58,7 +58,7 @@ public class MockDirectoryHelper {
public MockDirectoryHelper(ShardId shardId, Settings indexSettings, ESLogger logger) {
randomIOExceptionRate = indexSettings.getAsDouble(RANDOM_IO_EXCEPTION_RATE, 0.0d);
randomIOExceptionRateOnOpen = indexSettings.getAsDouble(RANDOM_IO_EXCEPTION_RATE_ON_OPEN, 0.0d);
final long seed = indexSettings.getAsLong(ElasticSearchTestCase.INDEX_SEED_SETTING, 0l);
final long seed = indexSettings.getAsLong(AbstractIntegrationTest.INDEX_SEED_SETTING, 0l);
random = new Random(seed);
random.nextInt(shardId.getId() + 1); // some randomness per shard
throttle = Throttling.valueOf(indexSettings.get(RANDOM_THROTTLE, random.nextDouble() < 0.1 ? "SOMETIMES" : "NEVER"));

View File

@ -1,14 +1,13 @@
package org.elasticsearch.junit.listeners;
import org.elasticsearch.test.AbstractIntegrationTest;
import org.elasticsearch.test.ElasticSearchTestCase;
import com.carrotsearch.randomizedtesting.RandomizedContext;
import com.carrotsearch.randomizedtesting.ReproduceErrorMessageBuilder;
import com.carrotsearch.randomizedtesting.SeedUtils;
import com.carrotsearch.randomizedtesting.TraceFormatting;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.test.AbstractIntegrationTest;
import org.elasticsearch.test.ElasticSearchTestCase;
import org.junit.internal.AssumptionViolatedException;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
@ -47,7 +46,7 @@ public class ReproduceInfoPrinter extends RunListener {
b.append("REPRODUCE WITH : mvn test");
ReproduceErrorMessageBuilder builder = new MavenMessageBuilder(b).appendAllOpts(failure.getDescription());
if (AbstractIntegrationTest.class.isAssignableFrom(failure.getDescription().getTestClass())) {
builder.appendOpt("tests.cluster_seed", SeedUtils.formatSeed(ElasticSearchTestCase.SHARED_CLUSTER_SEED));
builder.appendOpt("tests.cluster_seed", SeedUtils.formatSeed(AbstractIntegrationTest.SHARED_CLUSTER_SEED));
}
b.append("\n");

View File

@ -18,6 +18,7 @@
*/
package org.elasticsearch.test;
import com.carrotsearch.randomizedtesting.SeedUtils;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
@ -101,9 +102,17 @@ import static org.hamcrest.Matchers.equalTo;
@Ignore
@IntegrationTests
public abstract class AbstractIntegrationTest extends ElasticSearchTestCase {
public static final String INDEX_SEED_SETTING = "index.tests.seed";
public static final long SHARED_CLUSTER_SEED = clusterSeed();
private static final double TRANSPORT_CLIENT_RATIO = transportClientRatio();
private static final TestCluster globalCluster = new TestCluster(SHARED_CLUSTER_SEED, TestCluster.clusterName("shared", ElasticSearchTestCase.CHILD_VM_ID, SHARED_CLUSTER_SEED));
private static TestCluster currentCluster;
private static final Map<Class<?>, TestCluster> clusters = new IdentityHashMap<Class<?>, TestCluster>();
@Before
@ -122,9 +131,8 @@ public abstract class AbstractIntegrationTest extends ElasticSearchTestCase {
break;
default:
assert false : "Unknonw Scope: [" + currentClusterScope + "]";
}
currentCluster.beforeTest(getRandom());
currentCluster.beforeTest(getRandom(), Double.isNaN(TRANSPORT_CLIENT_RATIO) ? randomDouble() : TRANSPORT_CLIENT_RATIO);
wipeIndices();
wipeTemplates();
randomIndexTemplate();
@ -601,5 +609,21 @@ public abstract class AbstractIntegrationTest extends ElasticSearchTestCase {
Scope scope() default Scope.GLOBAL;
int numNodes() default -1;
}
private static long clusterSeed() {
String property = System.getProperty("tests.cluster_seed");
if (property == null || property.isEmpty()) {
return System.nanoTime();
}
return SeedUtils.parseSeed(property);
}
private static double transportClientRatio() {
String property = System.getProperty("tests.client.ratio");
if (property == null || property.isEmpty()) {
return Double.NaN;
}
return Double.parseDouble(property);
}
}

View File

@ -18,7 +18,6 @@
*/
package org.elasticsearch.test;
import com.carrotsearch.randomizedtesting.SeedUtils;
import com.carrotsearch.randomizedtesting.annotations.*;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
import com.google.common.base.Predicate;
@ -50,18 +49,6 @@ public abstract class ElasticSearchTestCase extends AbstractRandomizedTest {
public static final String CHILD_VM_ID = System.getProperty("junit4.childvm.id", "" + System.currentTimeMillis());
public static final long SHARED_CLUSTER_SEED = clusterSeed();
public static final String INDEX_SEED_SETTING = "index.tests.seed";
private static long clusterSeed() {
String property = System.getProperty("tests.cluster_seed");
if (property == null || property.isEmpty()) {
return System.nanoTime();
}
return SeedUtils.parseSeed(property);
}
public boolean awaitBusy(Predicate<?> breakPredicate) throws InterruptedException {
return awaitBusy(breakPredicate, 10, TimeUnit.SECONDS);
}

View File

@ -89,6 +89,8 @@ public class TestCluster implements Closeable, Iterable<Client> {
* this is important if a node is randomly shut down in a test since the next test relies on a
* fully shared cluster to be more reproducible */
private final long[] sharedNodesSeeds;
private double transportClientRatio = 0.0;
private final Map<Integer, Settings> perNodeSettingsMap;
private static final Map<Integer, Settings> EMPTY = Collections.emptyMap();
@ -418,31 +420,29 @@ public class TestCluster implements Closeable, Iterable<Client> {
@Override
public Client client(Node node, String clusterName, Random random) {
switch (random.nextInt(10)) {
case 5: // disabled for now - will re-enable once tests stabelize
// if (logger.isDebugEnabled()) {
// logger.debug("Using transport client for node [{}] sniff: [{}]", node.settings().get("name"), false);
// }
// return TransportClientFactory.NO_SNIFF_CLIENT_FACTORY.client(node, clusterName, random);
case 3:
// if (logger.isDebugEnabled()) {
// logger.debug("Using transport client for node [{}] sniff: [{}]", node.settings().get("name"), true);
// }
// return TransportClientFactory.SNIFF_CLIENT_FACTORY.client(node, clusterName, random);
default:
if (logger.isDebugEnabled()) {
logger.debug("Using node client for node [{}]", node.settings().get("name"));
}
return node.client();
double nextDouble = random.nextDouble();
if (nextDouble < transportClientRatio) {
if (logger.isDebugEnabled()) {
logger.debug("Using transport client for node [{}] sniff: [{}]", node.settings().get("name"), false);
}
/* no sniff client for now - doesn't work will all tests since it might throw NoNodeAvailableException if nodes are shut down.
* we first need support of transportClientRatio as annotations or so
*/
return TransportClientFactory.NO_SNIFF_CLIENT_FACTORY.client(node, clusterName, random);
} else {
return node.client();
}
}
}
public synchronized void beforeTest(Random random) {
reset(random, true);
public synchronized void beforeTest(Random random, double transportClientRatio) {
reset(random, true, transportClientRatio);
}
private synchronized void reset(Random random, boolean wipeData) {
private synchronized void reset(Random random, boolean wipeData, double transportClientRatio) {
assert transportClientRatio >= 0.0 && transportClientRatio <= 1.0;
logger.debug("Reset test cluster with transport client ratio: [{}]", transportClientRatio);
this.transportClientRatio = transportClientRatio;
this.random = new Random(random.nextLong());
resetClients(); /* reset all clients - each test gets it's own client based on the Random instance created above. */
if (wipeData) {
@ -586,6 +586,7 @@ public class TestCluster implements Closeable, Iterable<Client> {
}
}
public synchronized void stopCurrentMasterNode() {
ensureOpen();
assert numNodes() > 0;
@ -695,7 +696,7 @@ public class TestCluster implements Closeable, Iterable<Client> {
}
public void closeNonSharedNodes(boolean wipeData) {
reset(random, wipeData);
reset(random, wipeData, transportClientRatio);
}

View File

@ -43,7 +43,7 @@ import org.elasticsearch.index.similarity.SimilarityService;
import org.elasticsearch.index.store.Store;
import org.elasticsearch.index.translog.Translog;
import org.elasticsearch.indices.warmer.IndicesWarmer;
import org.elasticsearch.test.ElasticSearchTestCase;
import org.elasticsearch.test.AbstractIntegrationTest;
import org.elasticsearch.threadpool.ThreadPool;
import java.util.Map.Entry;
@ -63,8 +63,8 @@ public final class MockRobinEngine extends RobinEngine implements Engine {
CodecService codecService) throws EngineException {
super(shardId, indexSettings, threadPool, indexSettingsService, indexingService, warmer, store,
deletionPolicy, translog, mergePolicyProvider, mergeScheduler, analysisService, similarityService, codecService);
final long seed = indexSettings.getAsLong(ElasticSearchTestCase.INDEX_SEED_SETTING, 0l);
if (logger.isTraceEnabled()) {
final long seed = indexSettings.getAsLong(AbstractIntegrationTest.INDEX_SEED_SETTING, 0l);
if (logger.isTraceEnabled()){
logger.trace("Using [{}] for shard [{}] seed: [{}]", this.getClass().getName(), shardId, seed);
}
random = new Random(seed);