added REST test suites runner
The REST layer can now be tested through tests that are shared between all the elasticsearch official clients. The tests are based on REST specification that can be found on the elasticsearch-rest-api-spec project and consist of YAML files that describe the operations to be executed and the obtained results that need to be tested. REST tests can be executed through the ElasticsearchRestTests class, which relies on the rest-spec git submodule that contains the rest spec and tests pulled from the elasticsearch-rest-spec-api project. The rest-spec submodule gets automatically initialized and updated through maven (generate-test-resources phase). The REST runner and the needed classes are distributed within the test artifact. The following are the options supported by the REST tests runner: - tests.rest[true|false|host:port]: determines whether the REST tests need to be run and if so whether to rely on an external cluster (providing host and port) or fire a test cluster (default) - tests.rest.suite: comma separated paths of the test suites to be run (by default loaded from /rest-spec/test classpath). it is possible to run only a subset of the tests providing a sub-folder or even a single yaml file (the default /rest-spec/test prefix is optional when files are loaded from classpath) e.g. -Dtests.rest.suite=index,get,create/10_with_id - tests.rest.spec: REST spec path (default /rest-spec/api from classpath) - tests.iters: runs multiple iterations - tests.seed: seed to base the random behaviours on - tests.appendseed[true|false]: enables adding the seed to each test section's description (default false) - tests.cluster_seed: seed used to create the test cluster (if enabled) Closes #4469
This commit is contained in:
parent
3fed65e486
commit
d97a00d4a7
|
@ -0,0 +1,3 @@
|
|||
[submodule "rest-spec"]
|
||||
path = rest-spec
|
||||
url = git@github.com:elasticsearch/elasticsearch-rest-api-spec.git
|
|
@ -166,3 +166,45 @@ even if tests are passing.
|
|||
------------------------------
|
||||
mvn test -Dtests.output=always
|
||||
------------------------------
|
||||
|
||||
== Testing the REST layer
|
||||
|
||||
The available integration tests make use of the java API to communicate with
|
||||
the elasticsearch nodes, using the internal binary transport (port 9300 by
|
||||
default).
|
||||
The REST layer is tested through specific tests that are shared between all
|
||||
the elasticsearch official clients and can be found on the
|
||||
https://github.com/elasticsearch/elasticsearch-rest-api-spec[elasticsearch-rest-api-spec project].
|
||||
They consist of
|
||||
https://github.com/elasticsearch/elasticsearch-rest-api-spec/tree/master/test[YAML files]
|
||||
that describe the operations to be executed and the obtained results that
|
||||
need to be tested.
|
||||
|
||||
`ElasticsearchRestTests` is the executable test class that runs all the
|
||||
yaml suites available through a git submodule within the `rest-spec` folder.
|
||||
The submodule gets automatically initialized through maven right before
|
||||
running tests (generate-test-resources phase).
|
||||
The REST tests cannot be run without the files pulled from the submodule,
|
||||
thus if the `rest-spec` folder is empty on your working copy, it means
|
||||
that it needs to be initialized with the following command:
|
||||
|
||||
------------------------------
|
||||
git submodule update --init
|
||||
------------------------------
|
||||
|
||||
The following are the options supported by the REST tests runner:
|
||||
|
||||
* `tests.rest[true|false|host:port]`: determines whether the REST tests need
|
||||
to be run and if so whether to rely on an external cluster (providing host
|
||||
and port) or fire a test cluster (default)
|
||||
* `tests.rest.suite`: comma separated paths of the test suites to be run
|
||||
(by default loaded from /rest-spec/test). It is possible to run only a subset
|
||||
of the tests providing a sub-folder or even a single yaml file (the default
|
||||
/rest-spec/test prefix is optional when files are loaded from classpath)
|
||||
e.g. -Dtests.rest.suite=index,get,create/10_with_id
|
||||
* `tests.rest.spec`: REST spec path (default /rest-spec/api)
|
||||
* `tests.iters`: runs multiple iterations
|
||||
* `tests.seed`: seed to base the random behaviours on
|
||||
* `tests.appendseed[true|false]`: enables adding the seed to each test
|
||||
section's description (default false)
|
||||
* `tests.cluster_seed`: seed used to create the test cluster (if enabled)
|
75
pom.xml
75
pom.xml
|
@ -35,6 +35,8 @@
|
|||
<tests.shuffle>true</tests.shuffle>
|
||||
<tests.output>onerror</tests.output>
|
||||
<tests.client.ratio></tests.client.ratio>
|
||||
<rest.pull.skip>false</rest.pull.skip>
|
||||
<rest.init.skip>false</rest.init.skip>
|
||||
<es.logger.level>INFO</es.logger.level>
|
||||
</properties>
|
||||
|
||||
|
@ -65,6 +67,12 @@
|
|||
<version>${lucene.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
|
@ -313,6 +321,14 @@
|
|||
<include>**/*.*</include>
|
||||
</includes>
|
||||
</testResource>
|
||||
<testResource>
|
||||
<directory>${basedir}/rest-spec</directory>
|
||||
<targetPath>rest-spec</targetPath>
|
||||
<includes>
|
||||
<include>api/*.json</include>
|
||||
<include>test/**/*.yaml</include>
|
||||
</includes>
|
||||
</testResource>
|
||||
</testResources>
|
||||
|
||||
<plugins>
|
||||
|
@ -396,6 +412,7 @@
|
|||
<systemProperties>
|
||||
<!-- RandomizedTesting library system properties -->
|
||||
<tests.jvm.argline>${tests.jvm.argline}</tests.jvm.argline>
|
||||
<tests.appendseed>${tests.appendseed}</tests.appendseed>
|
||||
<tests.iters>${tests.iters}</tests.iters>
|
||||
<tests.maxfailures>${tests.maxfailures}</tests.maxfailures>
|
||||
<tests.failfast>${tests.failfast}</tests.failfast>
|
||||
|
@ -412,6 +429,9 @@
|
|||
<tests.integration>${tests.integration}</tests.integration>
|
||||
<tests.cluster_seed>${tests.cluster_seed}</tests.cluster_seed>
|
||||
<tests.client.ratio>${tests.client.ratio}</tests.client.ratio>
|
||||
<tests.rest>${tests.rest}</tests.rest>
|
||||
<tests.rest.suite>${tests.rest.suite}</tests.rest.suite>
|
||||
<tests.rest.spec>${tests.rest.spec}</tests.rest.spec>
|
||||
<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>
|
||||
|
@ -1002,14 +1022,50 @@
|
|||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-version</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>Init Rest Spec</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<skip>${rest.init.skip}</skip>
|
||||
<executable>git</executable>
|
||||
<arguments>
|
||||
<argument>submodule</argument>
|
||||
<argument>update</argument>
|
||||
<argument>--init</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>Pull Rest Spec</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<skip>${rest.pull.skip}</skip>
|
||||
<executable>git</executable>
|
||||
<arguments>
|
||||
<argument>submodule</argument>
|
||||
<argument>foreach</argument>
|
||||
<argument>git</argument>
|
||||
<argument>pull</argument>
|
||||
<argument>origin</argument>
|
||||
<argument>master</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-version</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
@ -1026,7 +1082,14 @@
|
|||
<include>org/elasticsearch/test/**/*</include>
|
||||
<include>org/apache/lucene/util/AbstractRandomizedTest.class</include>
|
||||
<include>org/apache/lucene/util/AbstractRandomizedTest$*.class</include> <!-- inner classes -->
|
||||
<include>com/carrotsearch/randomizedtesting/StandaloneRandomizedContext.class</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<!-- we only distribute the REST tests runner, not the executable test -->
|
||||
<exclude>org/elasticsearch/test/rest/ElasticsearchRestTests.class</exclude>
|
||||
<!-- unit tests for yaml suite parser & rest spec parser need to be excluded -->
|
||||
<exclude>org/elasticsearch/test/rest/test/**/*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2f5f78f24d8fbacf69c83ab7545654c83965e846
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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 com.carrotsearch.randomizedtesting;
|
||||
|
||||
/**
|
||||
* Exposes methods that allow to use a {@link RandomizedContext} without using a {@link RandomizedRunner}
|
||||
* This was specifically needed by the REST tests since they run with a custom junit runner ({@link org.elasticsearch.test.rest.junit.RestTestSuiteRunner})
|
||||
*/
|
||||
public final class StandaloneRandomizedContext {
|
||||
|
||||
private StandaloneRandomizedContext() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link RandomizedContext} associated to the current thread
|
||||
*/
|
||||
public static void createRandomizedContext(Class<?> testClass, Randomness runnerRandomness) {
|
||||
//the randomized runner is passed in as null, which is fine as long as we don't try to access it afterwards
|
||||
RandomizedContext randomizedContext = RandomizedContext.create(Thread.currentThread().getThreadGroup(), testClass, null);
|
||||
randomizedContext.push(runnerRandomness.clone(Thread.currentThread()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the {@link RandomizedContext} associated to the current thread
|
||||
*/
|
||||
public static void disposeRandomizedContext() {
|
||||
RandomizedContext.current().dispose();
|
||||
}
|
||||
|
||||
public static void pushRandomness(Randomness randomness) {
|
||||
RandomizedContext.current().push(randomness);
|
||||
}
|
||||
|
||||
public static void popAndDestroy() {
|
||||
RandomizedContext.current().popAndDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string formatted seed associated to the current thread's randomized context
|
||||
*/
|
||||
public static String getSeedAsString() {
|
||||
return SeedUtils.formatSeed(RandomizedContext.current().getRandomness().getSeed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Util method to extract the seed out of a {@link Randomness} instance
|
||||
*/
|
||||
public static long getSeed(Randomness randomness) {
|
||||
return randomness.getSeed();
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package org.elasticsearch.test;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.SeedUtils;
|
||||
import com.google.common.base.Joiner;
|
||||
import org.apache.lucene.util.AbstractRandomizedTest;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
|
@ -68,6 +67,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.elasticsearch.test.TestCluster.SHARED_CLUSTER_SEED;
|
||||
import static org.elasticsearch.test.TestCluster.clusterName;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.hamcrest.Matchers.emptyIterable;
|
||||
|
@ -123,7 +124,7 @@ import static org.hamcrest.Matchers.equalTo;
|
|||
* This class supports the following system properties (passed with -Dkey=value to the application)
|
||||
* <ul>
|
||||
* <li>-D{@value #TESTS_CLIENT_RATIO} - a double value in the interval [0..1] which defines the ration between node and transport clients used</li>
|
||||
* <li>-D{@value #TESTS_CLUSTER_SEED} - a random seed used to initialize the clusters random context.
|
||||
* <li>-D{@value TestCluster#TESTS_CLUSTER_SEED} - a random seed used to initialize the clusters random context.
|
||||
* <li>-D{@value #INDEX_SEED_SETTING} - a random seed used to initialize the index random context.
|
||||
* </ul>
|
||||
* </p>
|
||||
|
@ -132,24 +133,13 @@ import static org.hamcrest.Matchers.equalTo;
|
|||
@AbstractRandomizedTest.IntegrationTests
|
||||
public abstract class ElasticsearchIntegrationTest extends ElasticsearchTestCase {
|
||||
|
||||
|
||||
/**
|
||||
* The random seed for the shared test cluster used in the current JVM.
|
||||
*/
|
||||
public static final long SHARED_CLUSTER_SEED = clusterSeed();
|
||||
|
||||
private static final TestCluster GLOBAL_CLUSTER = new TestCluster(SHARED_CLUSTER_SEED, TestCluster.clusterName("shared", ElasticsearchTestCase.CHILD_VM_ID, SHARED_CLUSTER_SEED));
|
||||
private static final TestCluster GLOBAL_CLUSTER = new TestCluster(SHARED_CLUSTER_SEED, clusterName("shared", ElasticsearchTestCase.CHILD_VM_ID, SHARED_CLUSTER_SEED));
|
||||
|
||||
/**
|
||||
* Key used to set the transport client ratio via the commandline -D{@value #TESTS_CLIENT_RATIO}
|
||||
*/
|
||||
public static final String TESTS_CLIENT_RATIO = "tests.client.ratio";
|
||||
|
||||
/**
|
||||
* Key used to set the shared cluster random seed via the commandline -D{@value #TESTS_CLUSTER_SEED}
|
||||
*/
|
||||
public static final String TESTS_CLUSTER_SEED = "tests.cluster_seed";
|
||||
|
||||
/**
|
||||
* Key used to retrieve the index random seed from the index settings on a running node.
|
||||
* The value of this seed can be used to initialize a random context for a specific index.
|
||||
|
@ -830,7 +820,7 @@ public abstract class ElasticsearchIntegrationTest extends ElasticsearchTestCase
|
|||
};
|
||||
}
|
||||
|
||||
return new TestCluster(currentClusterSeed, numNodes, TestCluster.clusterName(scope.name(), ElasticsearchTestCase.CHILD_VM_ID, currentClusterSeed), nodeSettingsSource);
|
||||
return new TestCluster(currentClusterSeed, numNodes, clusterName(scope.name(), ElasticsearchTestCase.CHILD_VM_ID, currentClusterSeed), nodeSettingsSource);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -859,14 +849,6 @@ public abstract class ElasticsearchIntegrationTest extends ElasticsearchTestCase
|
|||
double transportClientRatio() 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client ratio configured via
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.elasticsearch.cluster.ClusterState;
|
|||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.cluster.routing.ShardRouting;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.FileSystemUtils;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
@ -78,6 +79,24 @@ public final class TestCluster implements Iterable<Client> {
|
|||
|
||||
private final ESLogger logger = Loggers.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* The random seed for the shared test cluster used in the current JVM.
|
||||
*/
|
||||
public static final long SHARED_CLUSTER_SEED = clusterSeed();
|
||||
|
||||
/**
|
||||
* Key used to set the shared cluster random seed via the commandline -D{@value #TESTS_CLUSTER_SEED}
|
||||
*/
|
||||
public static final String TESTS_CLUSTER_SEED = "tests.cluster_seed";
|
||||
|
||||
private static long clusterSeed() {
|
||||
String property = System.getProperty(TESTS_CLUSTER_SEED);
|
||||
if (!Strings.hasLength(property)) {
|
||||
return System.nanoTime();
|
||||
}
|
||||
return SeedUtils.parseSeed(property);
|
||||
}
|
||||
|
||||
/* sorted map to make traverse order reproducible */
|
||||
private final TreeMap<String, NodeAndClient> nodes = newTreeMap();
|
||||
|
||||
|
@ -109,6 +128,10 @@ public final class TestCluster implements Iterable<Client> {
|
|||
this(clusterSeed, -1, clusterName, NodeSettingsSource.EMPTY);
|
||||
}
|
||||
|
||||
public TestCluster(long clusterSeed, int numNodes, String clusterName) {
|
||||
this(clusterSeed, numNodes, clusterName, NodeSettingsSource.EMPTY);
|
||||
}
|
||||
|
||||
TestCluster(long clusterSeed, int numNodes, String clusterName, NodeSettingsSource nodeSettingsSource) {
|
||||
this.clusterName = clusterName;
|
||||
Random random = new Random(clusterSeed);
|
||||
|
@ -164,7 +187,7 @@ public final class TestCluster implements Iterable<Client> {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
static String clusterName(String prefix, String childVMId, long clusterSeed) {
|
||||
public static String clusterName(String prefix, String childVMId, long clusterSeed) {
|
||||
StringBuilder builder = new StringBuilder(prefix);
|
||||
builder.append('-').append(NetworkUtils.getLocalAddress().getHostName());
|
||||
builder.append("-CHILD_VM=[").append(childVMId).append(']');
|
||||
|
@ -379,7 +402,7 @@ public final class TestCluster implements Iterable<Client> {
|
|||
return null;
|
||||
}
|
||||
|
||||
void close() {
|
||||
public void close() {
|
||||
ensureOpen();
|
||||
if (this.open.compareAndSet(true, false)) {
|
||||
IOUtils.closeWhileHandlingException(nodes.values());
|
||||
|
@ -554,7 +577,7 @@ public final class TestCluster implements Iterable<Client> {
|
|||
/**
|
||||
* This method should be executed before each test to reset the cluster to it's initial state.
|
||||
*/
|
||||
synchronized void beforeTest(Random random, double transportClientRatio) {
|
||||
public synchronized void beforeTest(Random random, double transportClientRatio) {
|
||||
reset(random, true, transportClientRatio);
|
||||
}
|
||||
|
||||
|
@ -619,7 +642,7 @@ public final class TestCluster implements Iterable<Client> {
|
|||
/**
|
||||
* This method should be executed during tearDown
|
||||
*/
|
||||
synchronized void afterTest() {
|
||||
public synchronized void afterTest() {
|
||||
wipeDataDirectories();
|
||||
resetClients(); /* reset all clients - each test gets its own client based on the Random instance created above. */
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.carrotsearch.randomizedtesting.RandomizedContext;
|
|||
import com.carrotsearch.randomizedtesting.ReproduceErrorMessageBuilder;
|
||||
import com.carrotsearch.randomizedtesting.SeedUtils;
|
||||
import com.carrotsearch.randomizedtesting.TraceFormatting;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
|
@ -13,9 +14,9 @@ import org.junit.runner.Description;
|
|||
import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunListener;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import static com.carrotsearch.randomizedtesting.SysGlobals.SYSPROP_ITERATIONS;
|
||||
import static org.elasticsearch.test.TestCluster.SHARED_CLUSTER_SEED;
|
||||
import static org.elasticsearch.test.TestCluster.TESTS_CLUSTER_SEED;
|
||||
|
||||
/**
|
||||
* A {@link RunListener} that emits to {@link System#err} a string with command
|
||||
|
@ -46,26 +47,44 @@ public class ReproduceInfoPrinter extends RunListener {
|
|||
final StringBuilder b = new StringBuilder();
|
||||
b.append("FAILURE : ").append(d.getDisplayName()).append("\n");
|
||||
b.append("REPRODUCE WITH : mvn test");
|
||||
ReproduceErrorMessageBuilder builder = new MavenMessageBuilder(b).appendAllOpts(failure.getDescription());
|
||||
if (ElasticsearchIntegrationTest.class.isAssignableFrom(failure.getDescription().getTestClass())) {
|
||||
builder.appendOpt("tests.cluster_seed", SeedUtils.formatSeed(ElasticsearchIntegrationTest.SHARED_CLUSTER_SEED));
|
||||
ReproduceErrorMessageBuilder builder = reproduceErrorMessageBuilder(b).appendAllOpts(failure.getDescription());
|
||||
|
||||
if (mustAppendClusterSeed(failure)) {
|
||||
appendClusterSeed(builder);
|
||||
}
|
||||
|
||||
b.append("\n");
|
||||
b.append("Throwable:\n");
|
||||
if (failure.getException() != null) {
|
||||
TraceFormatting traces = new TraceFormatting();
|
||||
try {
|
||||
traces = RandomizedContext.current().getRunner().getTraceFormatting();
|
||||
} catch (IllegalStateException e) {
|
||||
// Ignore if no context.
|
||||
}
|
||||
traces.formatThrowable(b, failure.getException());
|
||||
traces().formatThrowable(b, failure.getException());
|
||||
}
|
||||
|
||||
logger.error(b.toString());
|
||||
}
|
||||
|
||||
private static class MavenMessageBuilder extends ReproduceErrorMessageBuilder {
|
||||
protected boolean mustAppendClusterSeed(Failure failure) {
|
||||
return ElasticsearchIntegrationTest.class.isAssignableFrom(failure.getDescription().getTestClass());
|
||||
}
|
||||
|
||||
protected void appendClusterSeed(ReproduceErrorMessageBuilder builder) {
|
||||
builder.appendOpt(TESTS_CLUSTER_SEED, SeedUtils.formatSeed(SHARED_CLUSTER_SEED));
|
||||
}
|
||||
|
||||
protected ReproduceErrorMessageBuilder reproduceErrorMessageBuilder(StringBuilder b) {
|
||||
return new MavenMessageBuilder(b);
|
||||
}
|
||||
|
||||
protected TraceFormatting traces() {
|
||||
TraceFormatting traces = new TraceFormatting();
|
||||
try {
|
||||
traces = RandomizedContext.current().getRunner().getTraceFormatting();
|
||||
} catch (IllegalStateException e) {
|
||||
// Ignore if no context.
|
||||
}
|
||||
return traces;
|
||||
}
|
||||
|
||||
protected static class MavenMessageBuilder extends ReproduceErrorMessageBuilder {
|
||||
|
||||
public MavenMessageBuilder(StringBuilder b) {
|
||||
super(b);
|
||||
|
@ -80,28 +99,34 @@ public class ReproduceInfoPrinter extends RunListener {
|
|||
/**
|
||||
* Append a single VM option.
|
||||
*/
|
||||
@Override
|
||||
public ReproduceErrorMessageBuilder appendOpt(String sysPropName, String value) {
|
||||
if (sysPropName.equals("tests.iters")) { // we don't want the iters to be in there!
|
||||
if (sysPropName.equals(SYSPROP_ITERATIONS())) { // we don't want the iters to be in there!
|
||||
return this;
|
||||
}
|
||||
if (value != null && !value.isEmpty()) {
|
||||
if (Strings.hasLength(value)) {
|
||||
return super.appendOpt(sysPropName, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReproduceErrorMessageBuilder appendESProperties() {
|
||||
for (String sysPropName : Arrays.asList(
|
||||
"es.logger.level", "es.node.mode", "es.node.local")) {
|
||||
if (System.getProperty(sysPropName) != null && !System.getProperty(sysPropName).isEmpty()) {
|
||||
appendOpt(sysPropName, System.getProperty(sysPropName));
|
||||
}
|
||||
}
|
||||
appendProperties("es.logger.level", "es.node.mode", "es.node.local");
|
||||
|
||||
if (System.getProperty("tests.jvm.argline") != null && !System.getProperty("tests.jvm.argline").isEmpty()) {
|
||||
appendOpt("tests.jvm.argline", "\"" + System.getProperty("tests.jvm.argline") + "\"");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected ReproduceErrorMessageBuilder appendProperties(String... properties) {
|
||||
for (String sysPropName : properties) {
|
||||
if (Strings.hasLength(System.getProperty(sysPropName))) {
|
||||
appendOpt(sysPropName, System.getProperty(sysPropName));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest;
|
||||
|
||||
import org.elasticsearch.test.rest.junit.RestTestSuiteRunner;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.apache.lucene.util.LuceneTestCase.Slow;
|
||||
|
||||
/**
|
||||
* Runs the clients test suite against an elasticsearch node, which can be an external node or an automatically created cluster.
|
||||
* Communicates with elasticsearch exclusively via REST layer.
|
||||
*
|
||||
* @see RestTestSuiteRunner for extensive documentation and all the supported options
|
||||
*/
|
||||
@Slow
|
||||
@RunWith(RestTestSuiteRunner.class)
|
||||
public class ElasticsearchRestTests {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.test.rest.client.RestClient;
|
||||
import org.elasticsearch.test.rest.client.RestException;
|
||||
import org.elasticsearch.test.rest.client.RestResponse;
|
||||
import org.elasticsearch.test.rest.spec.RestSpec;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Execution context passed across the REST tests.
|
||||
* Holds the REST client used to communicate with elasticsearch.
|
||||
* Caches the last obtained test response and allows to stash part of it within variables
|
||||
* that can be used as input values in following requests.
|
||||
*/
|
||||
public class RestTestExecutionContext implements Closeable {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(RestTestExecutionContext.class);
|
||||
|
||||
private final RestClient restClient;
|
||||
|
||||
private final String esVersion;
|
||||
|
||||
private final Map<String, Object> stash = Maps.newHashMap();
|
||||
|
||||
private RestResponse response;
|
||||
|
||||
public RestTestExecutionContext(String host, int port, RestSpec restSpec) throws RestException, IOException {
|
||||
|
||||
this.restClient = new RestClient(host, port, restSpec);
|
||||
this.esVersion = restClient.getEsVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an elasticsearch api with the parameters and request body provided as arguments.
|
||||
* Saves the obtained response in the execution context.
|
||||
* @throws RestException if the returned status code is non ok
|
||||
*/
|
||||
public RestResponse callApi(String apiName, Map<String, String> params, String body) throws IOException, RestException {
|
||||
//makes a copy of the parameters before modifying them for this specific request
|
||||
HashMap<String, String> requestParams = Maps.newHashMap(params);
|
||||
for (Map.Entry<String, String> entry : requestParams.entrySet()) {
|
||||
if (isStashed(entry.getValue())) {
|
||||
entry.setValue(unstash(entry.getValue()).toString());
|
||||
}
|
||||
}
|
||||
try {
|
||||
return response = callApiInternal(apiName, requestParams, body);
|
||||
} catch(RestException e) {
|
||||
response = e.restResponse();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an elasticsearch api internally without saving the obtained response in the context.
|
||||
* Useful for internal calls (e.g. delete index during teardown)
|
||||
* @throws RestException if the returned status code is non ok
|
||||
*/
|
||||
public RestResponse callApiInternal(String apiName, String... params) throws IOException, RestException {
|
||||
return restClient.callApi(apiName, params);
|
||||
}
|
||||
|
||||
private RestResponse callApiInternal(String apiName, Map<String, String> params, String body) throws IOException, RestException {
|
||||
return restClient.callApi(apiName, params, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a specific value from the last saved response
|
||||
*/
|
||||
public Object response(String path) throws IOException {
|
||||
return response.evaluate(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the last obtained response and the stashed fields
|
||||
*/
|
||||
public void clear() {
|
||||
logger.debug("resetting response and stash");
|
||||
response = null;
|
||||
stash.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a particular value needs to be looked up in the stash
|
||||
* The stash contains fields eventually extracted from previous responses that can be reused
|
||||
* as arguments for following requests (e.g. scroll_id)
|
||||
*/
|
||||
public boolean isStashed(Object key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
String stashKey = key.toString();
|
||||
return Strings.hasLength(stashKey) && stashKey.startsWith("$");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a value from the current stash
|
||||
* The stash contains fields eventually extracted from previous responses that can be reused
|
||||
* as arguments for following requests (e.g. scroll_id)
|
||||
*/
|
||||
public Object unstash(String value) {
|
||||
Object stashedValue = stash.get(value.substring(1));
|
||||
if (stashedValue == null) {
|
||||
throw new IllegalArgumentException("stashed value not found for key [" + value + "]");
|
||||
}
|
||||
return stashedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to saved a specific field in the stash as key-value pair
|
||||
*/
|
||||
public void stash(String key, Object value) {
|
||||
logger.debug("stashing [{}]=[{}]", key, value);
|
||||
Object old = stash.put(key, value);
|
||||
if (old != null && old != value) {
|
||||
logger.trace("replaced stashed value [{}] with same key [{}]", old, key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current es version as a string
|
||||
*/
|
||||
public String esVersion() {
|
||||
return esVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the execution context and releases the underlying resources
|
||||
*/
|
||||
public void close() {
|
||||
this.restClient.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.RandomizedTest;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
|
||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
||||
import org.elasticsearch.test.rest.spec.RestApi;
|
||||
import org.elasticsearch.test.rest.spec.RestSpec;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* REST client used to test the elasticsearch REST layer
|
||||
* Holds the {@link RestSpec} used to translate api calls into REST calls
|
||||
*/
|
||||
public class RestClient implements Closeable {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(RestClient.class);
|
||||
|
||||
private final RestSpec restSpec;
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
private final String esVersion;
|
||||
|
||||
public RestClient(String host, int port, RestSpec restSpec) throws IOException, RestException {
|
||||
this.restSpec = restSpec;
|
||||
this.httpClient = createHttpClient();
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.esVersion = readVersion();
|
||||
logger.info("REST client initialized [{}:{}], elasticsearch version: [{}]", host, port, esVersion);
|
||||
}
|
||||
|
||||
private String readVersion() throws IOException, RestException {
|
||||
//we make a manual call here without using callApi method, mainly because we are initializing
|
||||
//and the randomized context doesn't exist for the current thread (would be used to choose the method otherwise)
|
||||
RestApi restApi = restApi("info");
|
||||
assert restApi.getPaths().size() == 1;
|
||||
assert restApi.getMethods().size() == 1;
|
||||
RestResponse restResponse = new RestResponse(httpRequestBuilder()
|
||||
.path(restApi.getPaths().get(0))
|
||||
.method(restApi.getMethods().get(0)).execute());
|
||||
checkStatusCode(restResponse);
|
||||
Object version = restResponse.evaluate("version.number");
|
||||
if (version == null) {
|
||||
throw new RuntimeException("elasticsearch version not found in the response");
|
||||
}
|
||||
return version.toString();
|
||||
}
|
||||
|
||||
public String getEsVersion() {
|
||||
return esVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an api with the provided parameters
|
||||
* @throws RestException if the obtained status code is non ok, unless the specific error code needs to be ignored
|
||||
* according to the ignore parameter received as input (which won't get sent to elasticsearch)
|
||||
*/
|
||||
public RestResponse callApi(String apiName, String... params) throws IOException, RestException {
|
||||
if (params.length % 2 != 0) {
|
||||
throw new IllegalArgumentException("The number of params passed must be even but was [" + params.length + "]");
|
||||
}
|
||||
|
||||
Map<String, String> paramsMap = Maps.newHashMap();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
paramsMap.put(params[i++], params[i]);
|
||||
}
|
||||
|
||||
return callApi(apiName, paramsMap, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an api with the provided parameters and body
|
||||
* @throws RestException if the obtained status code is non ok, unless the specific error code needs to be ignored
|
||||
* according to the ignore parameter received as input (which won't get sent to elasticsearch)
|
||||
*/
|
||||
public RestResponse callApi(String apiName, Map<String, String> params, String body) throws IOException, RestException {
|
||||
|
||||
List<Integer> ignores = Lists.newArrayList();
|
||||
Map<String, String> requestParams = null;
|
||||
if (params != null) {
|
||||
//makes a copy of the parameters before modifying them for this specific request
|
||||
requestParams = Maps.newHashMap(params);
|
||||
//ignore is a special parameter supported by the clients, shouldn't be sent to es
|
||||
String ignoreString = requestParams.remove("ignore");
|
||||
if (Strings.hasLength(ignoreString)) {
|
||||
try {
|
||||
ignores.add(Integer.valueOf(ignoreString));
|
||||
} catch(NumberFormatException e) {
|
||||
throw new IllegalArgumentException("ignore value should be a number, found [" + ignoreString + "] instead");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpRequestBuilder httpRequestBuilder = callApiBuilder(apiName, requestParams, body);
|
||||
logger.debug("calling api [{}]", apiName);
|
||||
HttpResponse httpResponse = httpRequestBuilder.execute();
|
||||
|
||||
//http HEAD doesn't support response body
|
||||
// For the few api (exists class of api) that use it we need to accept 404 too
|
||||
if (!httpResponse.supportsBody()) {
|
||||
ignores.add(404);
|
||||
}
|
||||
|
||||
RestResponse restResponse = new RestResponse(httpResponse);
|
||||
checkStatusCode(restResponse, ignores);
|
||||
return restResponse;
|
||||
}
|
||||
|
||||
private void checkStatusCode(RestResponse restResponse, List<Integer> ignores) throws RestException {
|
||||
//ignore is a catch within the client, to prevent the client from throwing error if it gets non ok codes back
|
||||
if (ignores.contains(restResponse.getStatusCode())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ignored non ok status codes {} as requested", ignores);
|
||||
}
|
||||
return;
|
||||
}
|
||||
checkStatusCode(restResponse);
|
||||
}
|
||||
|
||||
private void checkStatusCode(RestResponse restResponse) throws RestException {
|
||||
if (restResponse.isError()) {
|
||||
throw new RestException("non ok status code [" + restResponse.getStatusCode() + "] returned", restResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpRequestBuilder callApiBuilder(String apiName, Map<String, String> params, String body) {
|
||||
RestApi restApi = restApi(apiName);
|
||||
|
||||
HttpRequestBuilder httpRequestBuilder = httpRequestBuilder().body(body);
|
||||
|
||||
//divide params between ones that go within query string and ones that go within path
|
||||
Map<String, String> pathParts = Maps.newHashMap();
|
||||
if (params != null) {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
if (restApi.getPathParts().contains(entry.getKey())) {
|
||||
pathParts.put(entry.getKey(), entry.getValue());
|
||||
} else {
|
||||
httpRequestBuilder.addParam(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//the http method is randomized (out of the available ones with the chosen api)
|
||||
return httpRequestBuilder.method(RandomizedTest.randomFrom(restApi.getSupportedMethods(pathParts.keySet())))
|
||||
.path(restApi.getFinalPath(pathParts));
|
||||
}
|
||||
|
||||
private RestApi restApi(String apiName) {
|
||||
RestApi restApi = restSpec.getApi(apiName);
|
||||
if (restApi == null) {
|
||||
throw new IllegalArgumentException("rest api [" + apiName + "] doesn't exist in the rest spec");
|
||||
}
|
||||
return restApi;
|
||||
}
|
||||
|
||||
protected HttpRequestBuilder httpRequestBuilder() {
|
||||
return new HttpRequestBuilder(httpClient).host(host).port(port);
|
||||
}
|
||||
|
||||
protected CloseableHttpClient createHttpClient() {
|
||||
return HttpClients.createDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the REST client and the underlying http client
|
||||
*/
|
||||
public void close() {
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch(IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client;
|
||||
|
||||
/**
|
||||
* Thrown when a status code that holds an error is received (unless needs to be ignored)
|
||||
* Holds the original {@link RestResponse}
|
||||
*/
|
||||
public class RestException extends Exception {
|
||||
|
||||
private final RestResponse restResponse;
|
||||
|
||||
public RestException(String message, RestResponse restResponse) {
|
||||
super(message);
|
||||
this.restResponse = restResponse;
|
||||
}
|
||||
|
||||
public RestResponse restResponse() {
|
||||
return restResponse;
|
||||
}
|
||||
|
||||
public int statusCode() {
|
||||
return restResponse.getStatusCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client;
|
||||
|
||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
||||
import org.elasticsearch.test.rest.json.JsonPath;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Response obtained from a REST call
|
||||
* Supports parsing the response body as json when needed and returning specific values extracted from it
|
||||
*/
|
||||
public class RestResponse {
|
||||
|
||||
private final HttpResponse response;
|
||||
private JsonPath parsedResponse;
|
||||
|
||||
RestResponse(HttpResponse response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return response.getStatusCode();
|
||||
}
|
||||
|
||||
public String getReasonPhrase() {
|
||||
return response.getReasonPhrase();
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return response.isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response body as json and extracts a specific value from it (identified by the provided path)
|
||||
*/
|
||||
public Object evaluate(String path) throws IOException {
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonPath jsonPath = parsedResponse();
|
||||
|
||||
if (jsonPath == null) {
|
||||
//special case: api that don't support body (e.g. exists) return true if 200, false if 404, even if no body
|
||||
//is_true: '' means the response had no body but the client returned true (caused by 200)
|
||||
//is_false: '' means the response had no body but the client returned false (caused by 404)
|
||||
if ("".equals(path) && !response.supportsBody()) {
|
||||
return !response.isError();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return jsonPath.evaluate(path);
|
||||
}
|
||||
|
||||
private JsonPath parsedResponse() throws IOException {
|
||||
if (parsedResponse != null) {
|
||||
return parsedResponse;
|
||||
}
|
||||
if (response == null || !response.hasBody()) {
|
||||
return null;
|
||||
}
|
||||
return parsedResponse = new JsonPath(response.getBody());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client.http;
|
||||
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* Allows to send DELETE requests providing a body (not supported out of the box)
|
||||
*/
|
||||
public class HttpDeleteWithEntity extends HttpEntityEnclosingRequestBase {
|
||||
|
||||
public final static String METHOD_NAME = "DELETE";
|
||||
|
||||
public HttpDeleteWithEntity(final URI uri) {
|
||||
setURI(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return METHOD_NAME;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client.http;
|
||||
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* Allows to send GET requests providing a body (not supported out of the box)
|
||||
*/
|
||||
public class HttpGetWithEntity extends HttpEntityEnclosingRequestBase {
|
||||
|
||||
public final static String METHOD_NAME = "GET";
|
||||
|
||||
public HttpGetWithEntity(final URI uri) {
|
||||
setURI(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return METHOD_NAME;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client.http;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Executable builder for an http request
|
||||
* Holds an {@link org.apache.http.client.HttpClient} that is used to send the built http request
|
||||
*/
|
||||
public class HttpRequestBuilder {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(HttpRequestBuilder.class);
|
||||
|
||||
static final Charset DEFAULT_CHARSET = Charset.forName("utf-8");
|
||||
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
private String host;
|
||||
|
||||
private int port;
|
||||
|
||||
private String path = "";
|
||||
|
||||
private final Map<String, String> params = Maps.newHashMap();
|
||||
|
||||
private String method = HttpGetWithEntity.METHOD_NAME;
|
||||
|
||||
private String body;
|
||||
|
||||
public HttpRequestBuilder(CloseableHttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public HttpRequestBuilder host(String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpRequestBuilder port(int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpRequestBuilder path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpRequestBuilder addParam(String name, String value) {
|
||||
this.params.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpRequestBuilder method(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpRequestBuilder body(String body) {
|
||||
if (Strings.hasLength(body)) {
|
||||
this.body = body;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpResponse execute() throws IOException {
|
||||
CloseableHttpResponse closeableHttpResponse = null;
|
||||
try {
|
||||
HttpUriRequest httpUriRequest = buildRequest();
|
||||
if (logger.isTraceEnabled()) {
|
||||
StringBuilder stringBuilder = new StringBuilder(httpUriRequest.getMethod()).append(" ").append(httpUriRequest.getURI());
|
||||
if (Strings.hasLength(body)) {
|
||||
stringBuilder.append("\n").append(body);
|
||||
}
|
||||
logger.trace("sending request \n{}", stringBuilder.toString());
|
||||
}
|
||||
closeableHttpResponse = httpClient.execute(httpUriRequest);
|
||||
HttpResponse httpResponse = new HttpResponse(httpUriRequest, closeableHttpResponse);
|
||||
logger.trace("got response \n{}\n{}", closeableHttpResponse, httpResponse.hasBody() ? httpResponse.getBody() : "");
|
||||
return httpResponse;
|
||||
} finally {
|
||||
try {
|
||||
IOUtils.close(closeableHttpResponse);
|
||||
} catch (IOException e) {
|
||||
logger.error("error closing http response", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HttpUriRequest buildRequest() {
|
||||
|
||||
if (HttpGetWithEntity.METHOD_NAME.equalsIgnoreCase(method)) {
|
||||
return addOptionalBody(new HttpGetWithEntity(buildUri()));
|
||||
}
|
||||
|
||||
if (HttpHead.METHOD_NAME.equalsIgnoreCase(method)) {
|
||||
checkBodyNotSupported();
|
||||
return new HttpHead(buildUri());
|
||||
}
|
||||
|
||||
if (HttpDeleteWithEntity.METHOD_NAME.equalsIgnoreCase(method)) {
|
||||
return addOptionalBody(new HttpDeleteWithEntity(buildUri()));
|
||||
}
|
||||
|
||||
if (HttpPut.METHOD_NAME.equalsIgnoreCase(method)) {
|
||||
return addOptionalBody(new HttpPut(buildUri()));
|
||||
}
|
||||
|
||||
if (HttpPost.METHOD_NAME.equalsIgnoreCase(method)) {
|
||||
return addOptionalBody(new HttpPost(buildUri()));
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("method [" + method + "] not supported");
|
||||
}
|
||||
|
||||
private URI buildUri() {
|
||||
String query;
|
||||
if (params.size() == 0) {
|
||||
query = null;
|
||||
} else {
|
||||
query = Joiner.on('&').withKeyValueSeparator("=").join(params);
|
||||
}
|
||||
try {
|
||||
return new URI("http", null, host, port, path, query, null);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpEntityEnclosingRequestBase addOptionalBody(HttpEntityEnclosingRequestBase requestBase) {
|
||||
if (Strings.hasText(body)) {
|
||||
requestBase.setEntity(new StringEntity(body, DEFAULT_CHARSET));
|
||||
}
|
||||
return requestBase;
|
||||
}
|
||||
|
||||
private void checkBodyNotSupported() {
|
||||
if (Strings.hasText(body)) {
|
||||
throw new IllegalArgumentException("request body not supported with head request");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder(method).append(" '")
|
||||
.append(host).append(":").append(port).append(path).append("'");
|
||||
if (!params.isEmpty()) {
|
||||
stringBuilder.append(", params=").append(params);
|
||||
}
|
||||
if (Strings.hasLength(body)) {
|
||||
stringBuilder.append(", body=\n").append(body);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.client.http;
|
||||
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpHead;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Response obtained from an http request
|
||||
* Always consumes the whole response body loading it entirely into a string
|
||||
*/
|
||||
public class HttpResponse {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(HttpResponse.class);
|
||||
|
||||
private final HttpUriRequest httpRequest;
|
||||
private final int statusCode;
|
||||
private final String reasonPhrase;
|
||||
private final String body;
|
||||
|
||||
HttpResponse(HttpUriRequest httpRequest, CloseableHttpResponse httpResponse) {
|
||||
this.httpRequest = httpRequest;
|
||||
this.statusCode = httpResponse.getStatusLine().getStatusCode();
|
||||
this.reasonPhrase = httpResponse.getStatusLine().getReasonPhrase();
|
||||
if (httpResponse.getEntity() != null) {
|
||||
try {
|
||||
this.body = EntityUtils.toString(httpResponse.getEntity(), HttpRequestBuilder.DEFAULT_CHARSET);
|
||||
} catch (IOException e) {
|
||||
EntityUtils.consumeQuietly(httpResponse.getEntity());
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
httpResponse.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.body = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return statusCode >= 400;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public String getReasonPhrase() {
|
||||
return reasonPhrase;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public boolean hasBody() {
|
||||
return body != null;
|
||||
}
|
||||
|
||||
public boolean supportsBody() {
|
||||
return !HttpHead.METHOD_NAME.equals(httpRequest.getMethod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder(statusCode).append(" ").append(reasonPhrase);
|
||||
if (hasBody()) {
|
||||
stringBuilder.append("\n").append(body);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.json;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds a json object and allows to extract specific values from it
|
||||
*/
|
||||
public class JsonPath {
|
||||
|
||||
final String json;
|
||||
final Map<String, Object> jsonMap;
|
||||
|
||||
public JsonPath(String json) throws IOException {
|
||||
this.json = json;
|
||||
this.jsonMap = convertToMap(json);
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertToMap(String json) throws IOException {
|
||||
return JsonXContent.jsonXContent.createParser(json).mapOrderedAndClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object corresponding to the provided path if present, null otherwise
|
||||
*/
|
||||
public Object evaluate(String path) {
|
||||
String[] parts = parsePath(path);
|
||||
Object object = jsonMap;
|
||||
for (String part : parts) {
|
||||
object = evaluate(part, object);
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object evaluate(String key, Object object) {
|
||||
if (object instanceof Map) {
|
||||
return ((Map<String, Object>) object).get(key);
|
||||
}
|
||||
if (object instanceof List) {
|
||||
List<Object> list = (List<Object>) object;
|
||||
try {
|
||||
return list.get(Integer.valueOf(key));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("element was a list, but [" + key + "] was not numeric", e);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("element was a list with " + list.size() + " elements, but [" + key + "] was out of bounds", e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("no object found for [" + key + "] within object of class [" + object.getClass() + "]");
|
||||
}
|
||||
|
||||
private String[] parsePath(String path) {
|
||||
List<String> list = Lists.newArrayList();
|
||||
StringBuilder current = new StringBuilder();
|
||||
boolean escape = false;
|
||||
for (int i = 0; i < path.length(); i++) {
|
||||
char c = path.charAt(i);
|
||||
if (c == '\\') {
|
||||
escape = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '.') {
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else {
|
||||
if (current.length() > 0) {
|
||||
list.add(current.toString());
|
||||
current.setLength(0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
current.append(c);
|
||||
}
|
||||
|
||||
if (current.length() > 0) {
|
||||
list.add(current.toString());
|
||||
}
|
||||
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.junit;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import org.elasticsearch.test.rest.section.RestTestSuite;
|
||||
import org.elasticsearch.test.rest.section.TestSection;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper that knows how to assign proper junit {@link Description}s to each of the node in the tests tree
|
||||
*/
|
||||
public final class DescriptionHelper {
|
||||
|
||||
private DescriptionHelper() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
The following generated ids need to be unique throughout a tests run.
|
||||
Ids are also shown by IDEs (with junit 4.11 unique ids can be different from what gets shown, not yet in 4.10).
|
||||
Some tricks are applied to control what gets shown in IDEs in order to keep the ids unique and nice to see at the same time.
|
||||
*/
|
||||
|
||||
static Description createRootDescription(String name) {
|
||||
return Description.createSuiteDescription(name);
|
||||
}
|
||||
|
||||
static Description createApiDescription(String api) {
|
||||
return Description.createSuiteDescription(api);
|
||||
}
|
||||
|
||||
static Description createTestSuiteDescription(RestTestSuite restTestSuite) {
|
||||
//e.g. "indices_open (10_basic)", which leads to 10_basic being returned by Description#getDisplayName
|
||||
String name = restTestSuite.getApi() + " (" + restTestSuite.getName() + ")";
|
||||
return Description.createSuiteDescription(name);
|
||||
}
|
||||
|
||||
static Description createTestSectionWithRepetitionsDescription(RestTestSuite restTestSuite, TestSection testSection) {
|
||||
//e.g. "indices_open/10_basic (Basic test for index open/close)", which leads to
|
||||
//"Basic test for index open/close" being returned by Description#getDisplayName
|
||||
String name = restTestSuite.getDescription() + " (" + testSection.getName() + ")";
|
||||
return Description.createSuiteDescription(name);
|
||||
}
|
||||
|
||||
static Description createTestSectionIterationDescription(RestTestSuite restTestSuite, TestSection testSection, Map<String, Object> args) {
|
||||
//e.g. "Basic test for index open/close {#0} (indices_open/10_basic)" some IDEs might strip out the part between parentheses
|
||||
String name = testSection.getName() + formatMethodArgs(args) + " (" + restTestSuite.getDescription() + ")";
|
||||
return Description.createSuiteDescription(name);
|
||||
}
|
||||
|
||||
private static String formatMethodArgs(Map<String, Object> args) {
|
||||
if (args == null || args.isEmpty()) return "";
|
||||
|
||||
StringBuilder b = new StringBuilder(" {");
|
||||
Joiner.on(" ").withKeyValueSeparator("").appendTo(b, args);
|
||||
b.append("}");
|
||||
|
||||
return b.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.junit;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.ReproduceErrorMessageBuilder;
|
||||
import com.carrotsearch.randomizedtesting.StandaloneRandomizedContext;
|
||||
import com.carrotsearch.randomizedtesting.TraceFormatting;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.test.junit.listeners.ReproduceInfoPrinter;
|
||||
import org.elasticsearch.test.rest.ElasticsearchRestTests;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runner.notification.Failure;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.SysGlobals.SYSPROP_RANDOM_SEED;
|
||||
import static com.carrotsearch.randomizedtesting.SysGlobals.SYSPROP_TESTCLASS;
|
||||
import static org.elasticsearch.test.rest.junit.RestTestSuiteRunner.*;
|
||||
|
||||
/**
|
||||
* A {@link org.junit.runner.notification.RunListener} that emits to {@link System#err} a string with command
|
||||
* line parameters allowing quick REST test re-run under MVN command line.
|
||||
*/
|
||||
class RestReproduceInfoPrinter extends ReproduceInfoPrinter {
|
||||
|
||||
protected static final ESLogger logger = Loggers.getLogger(RestReproduceInfoPrinter.class);
|
||||
|
||||
@Override
|
||||
protected boolean mustAppendClusterSeed(Failure failure) {
|
||||
return isTestCluster();
|
||||
}
|
||||
|
||||
private static boolean isTestCluster() {
|
||||
return runMode() == RunMode.TEST_CLUSTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceFormatting traces() {
|
||||
return new TraceFormatting(
|
||||
Arrays.asList(
|
||||
"org.junit.",
|
||||
"junit.framework.",
|
||||
"sun.",
|
||||
"java.lang.reflect.",
|
||||
"com.carrotsearch.randomizedtesting.",
|
||||
"org.elasticsearch.test.rest.junit."
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReproduceErrorMessageBuilder reproduceErrorMessageBuilder(StringBuilder b) {
|
||||
return new MavenMessageBuilder(b);
|
||||
}
|
||||
|
||||
private static class MavenMessageBuilder extends ReproduceInfoPrinter.MavenMessageBuilder {
|
||||
|
||||
public MavenMessageBuilder(StringBuilder b) {
|
||||
super(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReproduceErrorMessageBuilder appendAllOpts(Description description) {
|
||||
|
||||
try {
|
||||
appendOpt(SYSPROP_RANDOM_SEED(), StandaloneRandomizedContext.getSeedAsString());
|
||||
} catch (IllegalStateException e) {
|
||||
logger.warn("No context available when dumping reproduce options?");
|
||||
}
|
||||
|
||||
//we know that ElasticsearchRestTests is the only one that runs with RestTestSuiteRunner
|
||||
appendOpt(SYSPROP_TESTCLASS(), ElasticsearchRestTests.class.getName());
|
||||
|
||||
if (description.getClassName() != null) {
|
||||
appendOpt(REST_TESTS_SUITE, description.getClassName());
|
||||
}
|
||||
|
||||
appendRunnerProperties();
|
||||
appendEnvironmentSettings();
|
||||
|
||||
appendProperties("es.logger.level");
|
||||
|
||||
if (isTestCluster()) {
|
||||
appendProperties("es.node.mode", "es.node.local");
|
||||
}
|
||||
|
||||
appendRestTestsProperties();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReproduceErrorMessageBuilder appendRestTestsProperties() {
|
||||
return appendProperties(REST_TESTS_MODE, REST_TESTS_SPEC);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.junit;
|
||||
|
||||
import org.elasticsearch.test.rest.section.RestTestSuite;
|
||||
import org.elasticsearch.test.rest.section.SetupSection;
|
||||
import org.elasticsearch.test.rest.section.TestSection;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
/**
|
||||
* Wraps {@link org.elasticsearch.test.rest.section.TestSection}s ready to be run,
|
||||
* properly enriched with the needed execution information.
|
||||
* The tests tree structure gets flattened to the leaves (test sections)
|
||||
*/
|
||||
public class RestTestCandidate {
|
||||
|
||||
private final RestTestSuite restTestSuite;
|
||||
private final Description suiteDescription;
|
||||
private final TestSection testSection;
|
||||
private final Description testDescription;
|
||||
private final long seed;
|
||||
|
||||
static RestTestCandidate empty(RestTestSuite restTestSuite, Description suiteDescription) {
|
||||
return new RestTestCandidate(restTestSuite, suiteDescription, null, null, -1);
|
||||
}
|
||||
|
||||
RestTestCandidate(RestTestSuite restTestSuite, Description suiteDescription,
|
||||
TestSection testSection, Description testDescription, long seed) {
|
||||
this.restTestSuite = restTestSuite;
|
||||
this.suiteDescription = suiteDescription;
|
||||
this.testSection = testSection;
|
||||
this.testDescription = testDescription;
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
public String getApi() {
|
||||
return restTestSuite.getApi();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return restTestSuite.getName();
|
||||
}
|
||||
|
||||
public String getSuiteDescription() {
|
||||
return restTestSuite.getDescription();
|
||||
}
|
||||
|
||||
public Description describeSuite() {
|
||||
return suiteDescription;
|
||||
}
|
||||
|
||||
public Description describeTest() {
|
||||
return testDescription;
|
||||
}
|
||||
|
||||
public SetupSection getSetupSection() {
|
||||
return restTestSuite.getSetupSection();
|
||||
}
|
||||
|
||||
public TestSection getTestSection() {
|
||||
return testSection;
|
||||
}
|
||||
|
||||
public long getSeed() {
|
||||
return seed;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,546 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.junit;
|
||||
|
||||
import com.carrotsearch.hppc.hash.MurmurHash3;
|
||||
import com.carrotsearch.randomizedtesting.RandomizedTest;
|
||||
import com.carrotsearch.randomizedtesting.Randomness;
|
||||
import com.carrotsearch.randomizedtesting.SeedUtils;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.TestCluster;
|
||||
import org.elasticsearch.test.rest.RestTestExecutionContext;
|
||||
import org.elasticsearch.test.rest.client.RestException;
|
||||
import org.elasticsearch.test.rest.client.RestResponse;
|
||||
import org.elasticsearch.test.rest.parser.RestTestParseException;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParser;
|
||||
import org.elasticsearch.test.rest.section.DoSection;
|
||||
import org.elasticsearch.test.rest.section.ExecutableSection;
|
||||
import org.elasticsearch.test.rest.section.RestTestSuite;
|
||||
import org.elasticsearch.test.rest.section.TestSection;
|
||||
import org.elasticsearch.test.rest.spec.RestSpec;
|
||||
import org.elasticsearch.test.rest.support.FileUtils;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
import org.junit.runners.ParentRunner;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.SeedUtils.parseSeedChain;
|
||||
import static com.carrotsearch.randomizedtesting.StandaloneRandomizedContext.*;
|
||||
import static com.carrotsearch.randomizedtesting.SysGlobals.*;
|
||||
import static org.elasticsearch.test.TestCluster.SHARED_CLUSTER_SEED;
|
||||
import static org.elasticsearch.test.TestCluster.clusterName;
|
||||
import static org.elasticsearch.test.rest.junit.DescriptionHelper.*;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* JUnit runner for elasticsearch REST tests
|
||||
*
|
||||
* Supports the following options provided as system properties:
|
||||
* - tests.rest[true|false|host:port]: determines whether the REST tests need to be run and if so
|
||||
* whether to rely on an external cluster (providing host and port) or fire a test cluster (default)
|
||||
* - tests.rest.suite: comma separated paths of the test suites to be run (by default loaded from /rest-spec/test)
|
||||
* it is possible to run only a subset of the tests providing a directory or a single yaml file
|
||||
* (the default /rest-spec/test prefix is optional when files are loaded from classpath)
|
||||
* - tests.rest.spec: REST spec path (default /rest-spec/api)
|
||||
* - tests.iters: runs multiple iterations
|
||||
* - tests.seed: seed to base the random behaviours on
|
||||
* - tests.appendseed[true|false]: enables adding the seed to each test section's description (default false)
|
||||
* - tests.cluster_seed: seed used to create the test cluster (if enabled)
|
||||
*
|
||||
*/
|
||||
public class RestTestSuiteRunner extends ParentRunner<RestTestCandidate> {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(RestTestSuiteRunner.class);
|
||||
|
||||
public static final String REST_TESTS_MODE = "tests.rest";
|
||||
public static final String REST_TESTS_SUITE = "tests.rest.suite";
|
||||
public static final String REST_TESTS_SPEC = "tests.rest.spec";
|
||||
|
||||
private static final String DEFAULT_TESTS_PATH = "/rest-spec/test";
|
||||
private static final String DEFAULT_SPEC_PATH = "/rest-spec/api";
|
||||
private static final int DEFAULT_ITERATIONS = 1;
|
||||
|
||||
private static final String PATHS_SEPARATOR = ",";
|
||||
|
||||
private final RestTestExecutionContext restTestExecutionContext;
|
||||
private final List<RestTestCandidate> restTestCandidates;
|
||||
private final Description rootDescription;
|
||||
|
||||
private final RunMode runMode;
|
||||
|
||||
private final TestCluster testCluster;
|
||||
|
||||
private static final AtomicInteger sequencer = new AtomicInteger();
|
||||
|
||||
/** The runner's seed (master). */
|
||||
private final Randomness runnerRandomness;
|
||||
|
||||
/**
|
||||
* If {@link com.carrotsearch.randomizedtesting.SysGlobals#SYSPROP_RANDOM_SEED} property is used with two arguments
|
||||
* (master:test_section) then this field contains test section level override.
|
||||
*/
|
||||
private final Randomness testSectionRandomnessOverride;
|
||||
|
||||
enum RunMode {
|
||||
NO, TEST_CLUSTER, EXTERNAL_CLUSTER
|
||||
}
|
||||
|
||||
static RunMode runMode() {
|
||||
String mode = System.getProperty(REST_TESTS_MODE);
|
||||
if (!Strings.hasLength(mode)) {
|
||||
//default true: we run the tests starting our own test cluster
|
||||
mode = Boolean.TRUE.toString();
|
||||
}
|
||||
|
||||
if (Boolean.FALSE.toString().equalsIgnoreCase(mode)) {
|
||||
return RunMode.NO;
|
||||
}
|
||||
if (Boolean.TRUE.toString().equalsIgnoreCase(mode)) {
|
||||
return RunMode.TEST_CLUSTER;
|
||||
}
|
||||
return RunMode.EXTERNAL_CLUSTER;
|
||||
}
|
||||
|
||||
public RestTestSuiteRunner(Class<?> testClass) throws InitializationError {
|
||||
super(testClass);
|
||||
|
||||
this.runMode = runMode();
|
||||
|
||||
if (runMode == RunMode.NO) {
|
||||
//the tests won't be run. the run method will be called anyway but we'll just mark the whole suite as ignored
|
||||
//no need to go ahead and parse the test suites then
|
||||
this.runnerRandomness = null;
|
||||
this.testSectionRandomnessOverride = null;
|
||||
this.restTestExecutionContext = null;
|
||||
this.restTestCandidates = null;
|
||||
this.rootDescription = createRootDescription(getRootSuiteTitle());
|
||||
this.rootDescription.addChild(createApiDescription("empty suite"));
|
||||
this.testCluster = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//the REST test suite is supposed to be run only once per jvm against either an external es node or a self started one
|
||||
if (sequencer.getAndIncrement() > 0) {
|
||||
throw new InitializationError("only one instance of RestTestSuiteRunner can be created per jvm");
|
||||
}
|
||||
|
||||
//either read the seed from system properties (first one in the chain) or generate a new one
|
||||
final String globalSeed = System.getProperty(SYSPROP_RANDOM_SEED());
|
||||
final long initialSeed;
|
||||
Randomness randomnessOverride = null;
|
||||
if (Strings.hasLength(globalSeed)) {
|
||||
final long[] seedChain = parseSeedChain(globalSeed);
|
||||
if (seedChain.length == 0 || seedChain.length > 2) {
|
||||
throw new IllegalArgumentException("Invalid system property "
|
||||
+ SYSPROP_RANDOM_SEED() + " specification: " + globalSeed);
|
||||
}
|
||||
if (seedChain.length > 1) {
|
||||
//read the test section level seed if present
|
||||
randomnessOverride = new Randomness(seedChain[1]);
|
||||
}
|
||||
initialSeed = seedChain[0];
|
||||
} else {
|
||||
initialSeed = MurmurHash3.hash(System.nanoTime());
|
||||
}
|
||||
this.runnerRandomness = new Randomness(initialSeed);
|
||||
this.testSectionRandomnessOverride = randomnessOverride;
|
||||
logger.info("Master seed: {}", SeedUtils.formatSeed(initialSeed));
|
||||
|
||||
String host;
|
||||
int port;
|
||||
if (runMode == RunMode.TEST_CLUSTER) {
|
||||
this.testCluster = new TestCluster(SHARED_CLUSTER_SEED, 1, clusterName("REST-tests", ElasticsearchTestCase.CHILD_VM_ID, SHARED_CLUSTER_SEED));
|
||||
this.testCluster.beforeTest(runnerRandomness.getRandom(), 0.0f);
|
||||
HttpServerTransport httpServerTransport = testCluster.getInstance(HttpServerTransport.class);
|
||||
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) httpServerTransport.boundAddress().publishAddress();
|
||||
host = inetSocketTransportAddress.address().getHostName();
|
||||
port = inetSocketTransportAddress.address().getPort();
|
||||
} else {
|
||||
this.testCluster = null;
|
||||
String testsMode = System.getProperty(REST_TESTS_MODE);
|
||||
String[] split = testsMode.split(":");
|
||||
if (split.length < 2) {
|
||||
throw new InitializationError("address [" + testsMode + "] not valid");
|
||||
}
|
||||
host = split[0];
|
||||
try {
|
||||
port = Integer.valueOf(split[1]);
|
||||
} catch(NumberFormatException e) {
|
||||
throw new InitializationError("port is not valid, expected number but was [" + split[1] + "]");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String[] specPaths = resolvePathsProperty(REST_TESTS_SPEC, DEFAULT_SPEC_PATH);
|
||||
RestSpec restSpec = RestSpec.parseFrom(DEFAULT_SPEC_PATH, specPaths);
|
||||
|
||||
this.restTestExecutionContext = new RestTestExecutionContext(host, port, restSpec);
|
||||
this.rootDescription = createRootDescription(getRootSuiteTitle());
|
||||
this.restTestCandidates = collectTestCandidates(rootDescription);
|
||||
} catch (Throwable e) {
|
||||
stopTestCluster();
|
||||
throw new InitializationError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the test suites and creates the test candidates to be run, together with their junit descriptions.
|
||||
* The descriptions will be part of a tree containing api/yaml file/test section/eventual multiple iterations.
|
||||
* The test candidates will be instead flattened out to the leaves level (iterations), the part that needs to be run.
|
||||
*/
|
||||
protected List<RestTestCandidate> collectTestCandidates(Description rootDescription)
|
||||
throws RestTestParseException, IOException {
|
||||
|
||||
String[] paths = resolvePathsProperty(REST_TESTS_SUITE, DEFAULT_TESTS_PATH);
|
||||
Map<String, Set<File>> yamlSuites = FileUtils.findYamlSuites(DEFAULT_TESTS_PATH, paths);
|
||||
|
||||
int iterations = determineTestSectionIterationCount();
|
||||
boolean appendSeedParameter = RandomizedTest.systemPropertyAsBoolean(SYSPROP_APPEND_SEED(), false);
|
||||
|
||||
//we iterate over the files and we shuffle them (grouped by api, and by yaml file)
|
||||
//meanwhile we create the junit descriptions and test candidates (one per iteration)
|
||||
|
||||
//yaml suites are grouped by directory (effectively by api)
|
||||
List<String> apis = Lists.newArrayList(yamlSuites.keySet());
|
||||
Collections.shuffle(apis, runnerRandomness.getRandom());
|
||||
|
||||
final boolean fixedSeed = testSectionRandomnessOverride != null;
|
||||
final boolean hasRepetitions = iterations > 1;
|
||||
|
||||
List<RestTestCandidate> testCandidates = Lists.newArrayList();
|
||||
RestTestSuiteParser restTestSuiteParser = new RestTestSuiteParser();
|
||||
for (String api : apis) {
|
||||
|
||||
Description apiDescription = createApiDescription(api);
|
||||
rootDescription.addChild(apiDescription);
|
||||
|
||||
List<File> yamlFiles = Lists.newArrayList(yamlSuites.get(api));
|
||||
Collections.shuffle(yamlFiles, runnerRandomness.getRandom());
|
||||
|
||||
for (File yamlFile : yamlFiles) {
|
||||
RestTestSuite restTestSuite = restTestSuiteParser.parse(restTestExecutionContext.esVersion(), api, yamlFile);
|
||||
Description testSuiteDescription = createTestSuiteDescription(restTestSuite);
|
||||
apiDescription.addChild(testSuiteDescription);
|
||||
|
||||
if (restTestSuite.getTestSections().size() == 0) {
|
||||
assert restTestSuite.getSetupSection().getSkipSection().skipVersion(restTestExecutionContext.esVersion());
|
||||
testCandidates.add(RestTestCandidate.empty(restTestSuite, testSuiteDescription));
|
||||
continue;
|
||||
}
|
||||
|
||||
Collections.shuffle(restTestSuite.getTestSections(), runnerRandomness.getRandom());
|
||||
|
||||
for (TestSection testSection : restTestSuite.getTestSections()) {
|
||||
|
||||
//no need to generate seed if we are going to skip the test section
|
||||
if (testSection.getSkipSection().skipVersion(restTestExecutionContext.esVersion())) {
|
||||
Description testSectionDescription = createTestSectionIterationDescription(restTestSuite, testSection, null);
|
||||
testSuiteDescription.addChild(testSectionDescription);
|
||||
testCandidates.add(new RestTestCandidate(restTestSuite, testSuiteDescription, testSection, testSectionDescription, -1));
|
||||
continue;
|
||||
}
|
||||
|
||||
Description parentDescription;
|
||||
if (hasRepetitions) {
|
||||
//additional level to group multiple iterations under the same test section's node
|
||||
parentDescription = createTestSectionWithRepetitionsDescription(restTestSuite, testSection);
|
||||
testSuiteDescription.addChild(parentDescription);
|
||||
} else {
|
||||
parentDescription = testSuiteDescription;
|
||||
}
|
||||
|
||||
final long testSectionSeed = determineTestSectionSeed(restTestSuite.getDescription() + "/" + testSection.getName());
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
//test section name argument needs to be unique here
|
||||
long thisSeed = (fixedSeed ? testSectionSeed : testSectionSeed ^ MurmurHash3.hash((long) i));
|
||||
|
||||
final LinkedHashMap<String, Object> args = new LinkedHashMap<String, Object>();
|
||||
if (hasRepetitions) {
|
||||
args.put("#", i);
|
||||
}
|
||||
if (hasRepetitions || appendSeedParameter) {
|
||||
args.put("seed=", SeedUtils.formatSeedChain(runnerRandomness, new Randomness(thisSeed)));
|
||||
}
|
||||
|
||||
Description testSectionDescription = createTestSectionIterationDescription(restTestSuite, testSection, args);
|
||||
parentDescription.addChild(testSectionDescription);
|
||||
testCandidates.add(new RestTestCandidate(restTestSuite, testSuiteDescription, testSection, testSectionDescription, thisSeed));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return testCandidates;
|
||||
}
|
||||
|
||||
protected String getRootSuiteTitle() {
|
||||
if (runMode == RunMode.NO) {
|
||||
return "elasticsearch REST Tests - not run";
|
||||
}
|
||||
if (runMode == RunMode.TEST_CLUSTER) {
|
||||
return String.format(Locale.ROOT, "elasticsearch REST Tests - test cluster %s", SeedUtils.formatSeed(SHARED_CLUSTER_SEED));
|
||||
}
|
||||
if (runMode == RunMode.EXTERNAL_CLUSTER) {
|
||||
return String.format(Locale.ROOT, "elasticsearch REST Tests - external cluster %s", System.getProperty(REST_TESTS_MODE));
|
||||
}
|
||||
throw new UnsupportedOperationException("runMode [" + runMode + "] not supported");
|
||||
}
|
||||
|
||||
private int determineTestSectionIterationCount() {
|
||||
int iterations = RandomizedTest.systemPropertyAsInt(SYSPROP_ITERATIONS(), DEFAULT_ITERATIONS);
|
||||
if (iterations < 1) {
|
||||
throw new IllegalArgumentException("System property " + SYSPROP_ITERATIONS() + " must be >= 1 but was [" + iterations + "]");
|
||||
}
|
||||
return iterations;
|
||||
}
|
||||
|
||||
protected static String[] resolvePathsProperty(String propertyName, String defaultValue) {
|
||||
String property = System.getProperty(propertyName);
|
||||
if (!Strings.hasLength(property)) {
|
||||
return new String[]{defaultValue};
|
||||
} else {
|
||||
return property.split(PATHS_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a given test section's initial random seed
|
||||
*/
|
||||
private long determineTestSectionSeed(String testSectionName) {
|
||||
if (testSectionRandomnessOverride != null) {
|
||||
return getSeed(testSectionRandomnessOverride);
|
||||
}
|
||||
|
||||
// We assign each test section a different starting hash based on the global seed
|
||||
// and a hash of their name (so that the order of sections does not matter, only their names)
|
||||
return getSeed(runnerRandomness) ^ MurmurHash3.hash((long) testSectionName.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<RestTestCandidate> getChildren() {
|
||||
return restTestCandidates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description getDescription() {
|
||||
return rootDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Description describeChild(RestTestCandidate child) {
|
||||
return child.describeTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Statement classBlock(RunNotifier notifier) {
|
||||
//we remove support for @BeforeClass & @AfterClass and JUnit Rules (as we don't call super)
|
||||
Statement statement = childrenInvoker(notifier);
|
||||
statement = withExecutionContextClose(statement);
|
||||
if (testCluster != null) {
|
||||
return withTestClusterClose(statement);
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
protected Statement withExecutionContextClose(Statement statement) {
|
||||
return new RunAfter(statement, new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
restTestExecutionContext.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Statement withTestClusterClose(Statement statement) {
|
||||
return new RunAfter(statement, new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
stopTestCluster();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final RunNotifier notifier) {
|
||||
|
||||
if (runMode == RunMode.NO) {
|
||||
notifier.fireTestIgnored(rootDescription.getChildren().get(0));
|
||||
return;
|
||||
}
|
||||
|
||||
notifier.addListener(new RestReproduceInfoPrinter());
|
||||
|
||||
//the test suite gets run on a separate thread as the randomized context is per thread
|
||||
//once the randomized context is disposed it's not possible to create it again on the same thread
|
||||
final Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
createRandomizedContext(getTestClass().getJavaClass(), runnerRandomness);
|
||||
RestTestSuiteRunner.super.run(notifier);
|
||||
} finally {
|
||||
disposeRandomizedContext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
thread.start();
|
||||
try {
|
||||
thread.join();
|
||||
} catch (InterruptedException e) {
|
||||
notifier.fireTestFailure(new Failure(getDescription(),
|
||||
new RuntimeException("Interrupted while waiting for the suite runner? Weird.", e)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runChild(RestTestCandidate testCandidate, RunNotifier notifier) {
|
||||
|
||||
//if the while suite needs to be skipped, no test sections were loaded, only an empty one that we need to mark as ignored
|
||||
if (testCandidate.getSetupSection().getSkipSection().skipVersion(restTestExecutionContext.esVersion())) {
|
||||
logger.info("skipped test suite [{}]\nreason: {}\nskip versions: {} (current version: {})",
|
||||
testCandidate.getSuiteDescription(), testCandidate.getSetupSection().getSkipSection().getReason(),
|
||||
testCandidate.getSetupSection().getSkipSection().getVersion(), restTestExecutionContext.esVersion());
|
||||
|
||||
notifier.fireTestIgnored(testCandidate.describeSuite());
|
||||
return;
|
||||
}
|
||||
|
||||
//from now on no more empty test candidates are expected
|
||||
assert testCandidate.getTestSection() != null;
|
||||
|
||||
if (testCandidate.getTestSection().getSkipSection().skipVersion(restTestExecutionContext.esVersion())) {
|
||||
logger.info("skipped test [{}/{}]\nreason: {}\nskip versions: {} (current version: {})",
|
||||
testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName(),
|
||||
testCandidate.getTestSection().getSkipSection().getReason(),
|
||||
testCandidate.getTestSection().getSkipSection().getVersion(), restTestExecutionContext.esVersion());
|
||||
|
||||
notifier.fireTestIgnored(testCandidate.describeTest());
|
||||
return;
|
||||
}
|
||||
|
||||
runLeaf(methodBlock(testCandidate), testCandidate.describeTest(), notifier);
|
||||
}
|
||||
|
||||
protected Statement methodBlock(final RestTestCandidate testCandidate) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
final String testThreadName = "TEST-" + testCandidate.getSuiteDescription() +
|
||||
"." + testCandidate.getTestSection().getName() + "-seed#" + SeedUtils.formatSeedChain(runnerRandomness);
|
||||
// This has a side effect of setting up a nested context for the test thread.
|
||||
final String restoreName = Thread.currentThread().getName();
|
||||
try {
|
||||
Thread.currentThread().setName(testThreadName);
|
||||
pushRandomness(new Randomness(testCandidate.getSeed()));
|
||||
runTestSection(testCandidate);
|
||||
} finally {
|
||||
Thread.currentThread().setName(restoreName);
|
||||
popAndDestroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void runTestSection(RestTestCandidate testCandidate)
|
||||
throws IOException, RestException {
|
||||
|
||||
//let's check that there is something to run, otherwise there might be a problem with the test section
|
||||
if (testCandidate.getTestSection().getExecutableSections().size() == 0) {
|
||||
throw new IllegalArgumentException("No executable sections loaded for ["
|
||||
+ testCandidate.getSuiteDescription() + "/" + testCandidate.getTestSection().getName() + "]");
|
||||
}
|
||||
|
||||
logger.info("cleaning up before test [{}: {}]", testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName());
|
||||
tearDown();
|
||||
|
||||
logger.info("start test [{}: {}]", testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName());
|
||||
|
||||
if (!testCandidate.getSetupSection().isEmpty()) {
|
||||
logger.info("start setup test [{}: {}]", testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName());
|
||||
for (DoSection doSection : testCandidate.getSetupSection().getDoSections()) {
|
||||
doSection.execute(restTestExecutionContext);
|
||||
}
|
||||
logger.info("end setup test [{}: {}]", testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName());
|
||||
}
|
||||
|
||||
restTestExecutionContext.clear();
|
||||
|
||||
for (ExecutableSection executableSection : testCandidate.getTestSection().getExecutableSections()) {
|
||||
executableSection.execute(restTestExecutionContext);
|
||||
}
|
||||
|
||||
logger.info("end test [{}: {}]", testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName());
|
||||
|
||||
logger.info("cleaning up after test [{}: {}]", testCandidate.getSuiteDescription(), testCandidate.getTestSection().getName());
|
||||
tearDown();
|
||||
}
|
||||
|
||||
private void tearDown() throws IOException, RestException {
|
||||
wipeIndices();
|
||||
wipeTemplates();
|
||||
restTestExecutionContext.clear();
|
||||
}
|
||||
|
||||
private void wipeIndices() throws IOException, RestException {
|
||||
logger.debug("deleting all indices");
|
||||
RestResponse restResponse = restTestExecutionContext.callApiInternal("indices.delete", "index", "_all");
|
||||
assertThat(restResponse.getStatusCode(), equalTo(200));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void wipeTemplates() throws IOException, RestException {
|
||||
logger.debug("deleting all templates");
|
||||
//delete templates by wildcard was only added in 0.90.6
|
||||
//httpResponse = restTestExecutionContext.callApi("indices.delete_template", "name", "*");
|
||||
RestResponse restResponse = restTestExecutionContext.callApiInternal("cluster.state", "filter_nodes", "true",
|
||||
"filter_routing_table", "true", "filter_blocks", "true");
|
||||
assertThat(restResponse.getStatusCode(), equalTo(200));
|
||||
Object object = restResponse.evaluate("metadata.templates");
|
||||
assertThat(object, instanceOf(Map.class));
|
||||
Set<String> templates = ((Map<String, Object>) object).keySet();
|
||||
for (String template : templates) {
|
||||
restResponse = restTestExecutionContext.callApiInternal("indices.delete_template", "name", template);
|
||||
assertThat(restResponse.getStatusCode(), equalTo(200));
|
||||
}
|
||||
}
|
||||
|
||||
private void stopTestCluster() {
|
||||
if (runMode == RunMode.TEST_CLUSTER) {
|
||||
assert testCluster != null;
|
||||
testCluster.afterTest();
|
||||
testCluster.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.junit;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.runners.model.MultipleFailureException;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link Statement} that allows to run a specific statement after another one
|
||||
*/
|
||||
public class RunAfter extends Statement {
|
||||
|
||||
private final Statement next;
|
||||
private final Statement after;
|
||||
|
||||
public RunAfter(Statement next, Statement after) {
|
||||
this.next = next;
|
||||
this.after = after;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
List<Throwable> errors = Lists.newArrayList();
|
||||
try {
|
||||
next.evaluate();
|
||||
} catch (Throwable e) {
|
||||
errors.add(e);
|
||||
} finally {
|
||||
try {
|
||||
after.evaluate();
|
||||
} catch (Throwable e) {
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
MultipleFailureException.assertEmpty(errors);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.rest.section.ApiCallSection;
|
||||
import org.elasticsearch.test.rest.section.DoSection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Parser for do sections
|
||||
*/
|
||||
public class DoSectionParser implements RestTestFragmentParser<DoSection> {
|
||||
|
||||
@Override
|
||||
public DoSection parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
|
||||
DoSection doSection = new DoSection();
|
||||
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("catch".equals(currentFieldName)) {
|
||||
doSection.setCatch(parser.text());
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if (currentFieldName != null) {
|
||||
ApiCallSection apiCallSection = new ApiCallSection(currentFieldName);
|
||||
String paramName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
paramName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("body".equals(paramName)) {
|
||||
apiCallSection.addBody(parser.text());
|
||||
} else {
|
||||
apiCallSection.addParam(paramName, parser.text());
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if ("body".equals(paramName)) {
|
||||
Map<String,Object> map = parser.mapOrdered();
|
||||
XContentBuilder contentBuilder = XContentFactory.jsonBuilder().map(map);
|
||||
apiCallSection.addBody(contentBuilder.string());
|
||||
}
|
||||
}
|
||||
}
|
||||
doSection.setApiCallSection(apiCallSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
|
||||
if (doSection.getApiCallSection() == null) {
|
||||
throw new RestTestParseException("client call section is mandatory within a do section");
|
||||
}
|
||||
|
||||
return doSection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.test.rest.section.GreaterThanAssertion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for gt assert sections
|
||||
*/
|
||||
public class GreaterThanParser implements RestTestFragmentParser<GreaterThanAssertion> {
|
||||
|
||||
@Override
|
||||
public GreaterThanAssertion parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
Tuple<String,Object> stringObjectTuple = parseContext.parseTuple();
|
||||
if (! (stringObjectTuple.v2() instanceof Comparable) ) {
|
||||
throw new RestTestParseException("gt section can only be used with objects that support natural ordering, found " + stringObjectTuple.v2().getClass().getSimpleName());
|
||||
}
|
||||
return new GreaterThanAssertion(stringObjectTuple.v1(), stringObjectTuple.v2());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.test.rest.section.IsFalseAssertion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for is_false assert sections
|
||||
*/
|
||||
public class IsFalseParser implements RestTestFragmentParser<IsFalseAssertion> {
|
||||
|
||||
@Override
|
||||
public IsFalseAssertion parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
return new IsFalseAssertion(parseContext.parseField());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.test.rest.section.IsTrueAssertion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for is_true assert sections
|
||||
*/
|
||||
public class IsTrueParser implements RestTestFragmentParser<IsTrueAssertion> {
|
||||
|
||||
@Override
|
||||
public IsTrueAssertion parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
return new IsTrueAssertion(parseContext.parseField());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.test.rest.section.LengthAssertion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for length assert sections
|
||||
*/
|
||||
public class LengthParser implements RestTestFragmentParser<LengthAssertion> {
|
||||
|
||||
@Override
|
||||
public LengthAssertion parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
Tuple<String,Object> stringObjectTuple = parseContext.parseTuple();
|
||||
assert stringObjectTuple.v2() != null;
|
||||
int value;
|
||||
if (stringObjectTuple.v2() instanceof Number) {
|
||||
value = ((Number) stringObjectTuple.v2()).intValue();
|
||||
} else {
|
||||
try {
|
||||
value = Integer.valueOf(stringObjectTuple.v2().toString());
|
||||
} catch(NumberFormatException e) {
|
||||
throw new RestTestParseException("length is not a valid number", e);
|
||||
}
|
||||
|
||||
}
|
||||
return new LengthAssertion(stringObjectTuple.v1(), value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.test.rest.section.LessThanAssertion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for lt assert sections
|
||||
*/
|
||||
public class LessThanParser implements RestTestFragmentParser<LessThanAssertion> {
|
||||
|
||||
@Override
|
||||
public LessThanAssertion parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
Tuple<String,Object> stringObjectTuple = parseContext.parseTuple();
|
||||
if (! (stringObjectTuple.v2() instanceof Comparable) ) {
|
||||
throw new RestTestParseException("lt section can only be used with objects that support natural ordering, found " + stringObjectTuple.v2().getClass().getSimpleName());
|
||||
}
|
||||
return new LessThanAssertion(stringObjectTuple.v1(), stringObjectTuple.v2());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.test.rest.section.MatchAssertion;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for match assert sections
|
||||
*/
|
||||
public class MatchParser implements RestTestFragmentParser<MatchAssertion> {
|
||||
|
||||
@Override
|
||||
public MatchAssertion parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
Tuple<String,Object> stringObjectTuple = parseContext.parseTuple();
|
||||
return new MatchAssertion(stringObjectTuple.v1(), stringObjectTuple.v2());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base parser for a REST test suite fragment
|
||||
* @param <T> the test fragment's type that gets parsed and returned
|
||||
*/
|
||||
public interface RestTestFragmentParser<T> {
|
||||
|
||||
/**
|
||||
* Parses a test fragment given the current {@link RestTestSuiteParseContext}
|
||||
*/
|
||||
T parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
/**
|
||||
* Exception thrown whenever there is a problem parsing any of the REST test suite fragment
|
||||
*/
|
||||
public class RestTestParseException extends Exception {
|
||||
|
||||
RestTestParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
RestTestParseException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.rest.section.TestSection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for a complete test section
|
||||
*
|
||||
* Depending on the elasticsearch version the tests are going to run against, test sections might need to get skipped
|
||||
* In that case the relevant test sections parsing is entirely skipped
|
||||
*/
|
||||
public class RestTestSectionParser implements RestTestFragmentParser<TestSection> {
|
||||
|
||||
@Override
|
||||
public TestSection parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
parseContext.advanceToFieldName();
|
||||
TestSection testSection = new TestSection(parser.currentName());
|
||||
parser.nextToken();
|
||||
testSection.setSkipSection(parseContext.parseSkipSection());
|
||||
|
||||
boolean skip = testSection.getSkipSection().skipVersion(parseContext.getCurrentVersion());
|
||||
|
||||
while ( parser.currentToken() != XContentParser.Token.END_ARRAY) {
|
||||
if (skip) {
|
||||
//if there was a skip section, there was a setup section as well, which means that we are sure
|
||||
// the current token is at the beginning of a new object
|
||||
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
|
||||
//we need to be at the beginning of an object to be able to skip children
|
||||
parser.skipChildren();
|
||||
//after skipChildren we are at the end of the skipped object, need to move on
|
||||
parser.nextToken();
|
||||
} else {
|
||||
parseContext.advanceToFieldName();
|
||||
testSection.addExecutableSection(parseContext.parseExecutableSection());
|
||||
}
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
assert parser.currentToken() == XContentParser.Token.END_OBJECT;
|
||||
parser.nextToken();
|
||||
|
||||
return testSection;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.rest.section.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Context shared across the whole tests parse phase.
|
||||
* Provides shared parse methods and holds information needed to parse the test sections (e.g. es version)
|
||||
*/
|
||||
public class RestTestSuiteParseContext {
|
||||
|
||||
private static final SetupSectionParser SETUP_SECTION_PARSER = new SetupSectionParser();
|
||||
private static final RestTestSectionParser TEST_SECTION_PARSER = new RestTestSectionParser();
|
||||
private static final SkipSectionParser SKIP_SECTION_PARSER = new SkipSectionParser();
|
||||
private static final DoSectionParser DO_SECTION_PARSER = new DoSectionParser();
|
||||
private static final Map<String, RestTestFragmentParser<? extends ExecutableSection>> EXECUTABLE_SECTIONS_PARSERS = Maps.newHashMap();
|
||||
static {
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("do", DO_SECTION_PARSER);
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("set", new SetSectionParser());
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("match", new MatchParser());
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("is_true", new IsTrueParser());
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("is_false", new IsFalseParser());
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("gt", new GreaterThanParser());
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("lt", new LessThanParser());
|
||||
EXECUTABLE_SECTIONS_PARSERS.put("length", new LengthParser());
|
||||
}
|
||||
|
||||
private final String api;
|
||||
private final String suiteName;
|
||||
private final XContentParser parser;
|
||||
private final String currentVersion;
|
||||
|
||||
public RestTestSuiteParseContext(String api, String suiteName, XContentParser parser, String currentVersion) {
|
||||
this.api = api;
|
||||
this.suiteName = suiteName;
|
||||
this.parser = parser;
|
||||
this.currentVersion = currentVersion;
|
||||
}
|
||||
|
||||
public String getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
public String getSuiteName() {
|
||||
return suiteName;
|
||||
}
|
||||
|
||||
public XContentParser parser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
public String getCurrentVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
public SetupSection parseSetupSection() throws IOException, RestTestParseException {
|
||||
|
||||
advanceToFieldName();
|
||||
|
||||
if ("setup".equals(parser.currentName())) {
|
||||
parser.nextToken();
|
||||
SetupSection setupSection = SETUP_SECTION_PARSER.parse(this);
|
||||
parser.nextToken();
|
||||
return setupSection;
|
||||
}
|
||||
|
||||
return SetupSection.EMPTY;
|
||||
}
|
||||
|
||||
public TestSection parseTestSection() throws IOException, RestTestParseException {
|
||||
return TEST_SECTION_PARSER.parse(this);
|
||||
}
|
||||
|
||||
public SkipSection parseSkipSection() throws IOException, RestTestParseException {
|
||||
|
||||
advanceToFieldName();
|
||||
|
||||
if ("skip".equals(parser.currentName())) {
|
||||
SkipSection skipSection = SKIP_SECTION_PARSER.parse(this);
|
||||
parser.nextToken();
|
||||
return skipSection;
|
||||
}
|
||||
|
||||
return SkipSection.EMPTY;
|
||||
}
|
||||
|
||||
public ExecutableSection parseExecutableSection() throws IOException, RestTestParseException {
|
||||
advanceToFieldName();
|
||||
String section = parser.currentName();
|
||||
RestTestFragmentParser<? extends ExecutableSection> execSectionParser = EXECUTABLE_SECTIONS_PARSERS.get(section);
|
||||
if (execSectionParser == null) {
|
||||
throw new RestTestParseException("no parser found for executable section [" + section + "]");
|
||||
}
|
||||
ExecutableSection executableSection = execSectionParser.parse(this);
|
||||
parser.nextToken();
|
||||
return executableSection;
|
||||
}
|
||||
|
||||
public DoSection parseDoSection() throws IOException, RestTestParseException {
|
||||
return DO_SECTION_PARSER.parse(this);
|
||||
}
|
||||
|
||||
public void advanceToFieldName() throws IOException, RestTestParseException {
|
||||
XContentParser.Token token = parser.currentToken();
|
||||
//we are in the beginning, haven't called nextToken yet
|
||||
if (token == null) {
|
||||
token = parser.nextToken();
|
||||
}
|
||||
if (token == XContentParser.Token.START_ARRAY) {
|
||||
token = parser.nextToken();
|
||||
}
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
token = parser.nextToken();
|
||||
}
|
||||
if (token != XContentParser.Token.FIELD_NAME) {
|
||||
throw new RestTestParseException("malformed test section: field suiteName expected but found " + token);
|
||||
}
|
||||
}
|
||||
|
||||
public String parseField() throws IOException, RestTestParseException {
|
||||
parser.nextToken();
|
||||
assert parser.currentToken().isValue();
|
||||
String field = parser.text();
|
||||
parser.nextToken();
|
||||
return field;
|
||||
}
|
||||
|
||||
public Tuple<String, Object> parseTuple() throws IOException, RestTestParseException {
|
||||
parser.nextToken();
|
||||
advanceToFieldName();
|
||||
Map<String,Object> map = parser.map();
|
||||
assert parser.currentToken() == XContentParser.Token.END_OBJECT;
|
||||
parser.nextToken();
|
||||
|
||||
if (map.size() != 1) {
|
||||
throw new RestTestParseException("expected key value pair but found " + map.size() + " ");
|
||||
}
|
||||
|
||||
Map.Entry<String, Object> entry = map.entrySet().iterator().next();
|
||||
return Tuple.tuple(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.section.RestTestSuite;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for a complete test suite (yaml file)
|
||||
*
|
||||
* Depending on the elasticsearch version the tests are going to run against, a whole test suite might need to get skipped
|
||||
* In that case the relevant test sections parsing is entirely skipped
|
||||
*/
|
||||
public class RestTestSuiteParser implements RestTestFragmentParser<RestTestSuite> {
|
||||
|
||||
public RestTestSuite parse(String currentVersion, String api, File file) throws IOException, RestTestParseException {
|
||||
|
||||
if (!file.isFile()) {
|
||||
throw new IllegalArgumentException(file.getAbsolutePath() + " is not a file");
|
||||
}
|
||||
|
||||
XContentParser parser = YamlXContent.yamlXContent.createParser(new FileInputStream(file));
|
||||
try {
|
||||
String filename = file.getName();
|
||||
//remove the file extension
|
||||
int i = filename.lastIndexOf('.');
|
||||
if (i > 0) {
|
||||
filename = filename.substring(0, i);
|
||||
}
|
||||
RestTestSuiteParseContext testParseContext = new RestTestSuiteParseContext(api, filename, parser, currentVersion);
|
||||
return parse(testParseContext);
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestTestSuite parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
parser.nextToken();
|
||||
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
|
||||
|
||||
RestTestSuite restTestSuite = new RestTestSuite(parseContext.getApi(), parseContext.getSuiteName());
|
||||
|
||||
restTestSuite.setSetupSection(parseContext.parseSetupSection());
|
||||
|
||||
boolean skip = restTestSuite.getSetupSection().getSkipSection().skipVersion(parseContext.getCurrentVersion());
|
||||
|
||||
while(true) {
|
||||
//the "---" section separator is not understood by the yaml parser. null is returned, same as when the parser is closed
|
||||
//we need to somehow distinguish between a null in the middle of a test ("---")
|
||||
// and a null at the end of the file (at least two consecutive null tokens)
|
||||
if(parser.currentToken() == null) {
|
||||
if (parser.nextToken() == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
//if there was a skip section, there was a setup section as well, which means that we are sure
|
||||
// the current token is at the beginning of a new object
|
||||
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
|
||||
//we need to be at the beginning of an object to be able to skip children
|
||||
parser.skipChildren();
|
||||
//after skipChildren we are at the end of the skipped object, need to move on
|
||||
parser.nextToken();
|
||||
} else {
|
||||
restTestSuite.addTestSection(parseContext.parseTestSection());
|
||||
}
|
||||
}
|
||||
|
||||
return restTestSuite;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.rest.section.SetSection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for set sections
|
||||
*/
|
||||
public class SetSectionParser implements RestTestFragmentParser<SetSection> {
|
||||
|
||||
@Override
|
||||
public SetSection parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
|
||||
SetSection setSection = new SetSection();
|
||||
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
setSection.addSet(currentFieldName, parser.text());
|
||||
}
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
|
||||
if (setSection.getStash().isEmpty()) {
|
||||
throw new RestTestParseException("set section must set at least a value");
|
||||
}
|
||||
|
||||
return setSection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.rest.section.SetupSection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for setup sections
|
||||
*/
|
||||
public class SetupSectionParser implements RestTestFragmentParser<SetupSection> {
|
||||
|
||||
@Override
|
||||
public SetupSection parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
SetupSection setupSection = new SetupSection();
|
||||
setupSection.setSkipSection(parseContext.parseSkipSection());
|
||||
|
||||
boolean skip = setupSection.getSkipSection().skipVersion(parseContext.getCurrentVersion());
|
||||
|
||||
while (parser.currentToken() != XContentParser.Token.END_ARRAY) {
|
||||
if (skip) {
|
||||
//if there was a skip section, there was a setup section as well, which means that we are sure
|
||||
// the current token is at the beginning of a new object
|
||||
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
|
||||
//we need to be at the beginning of an object to be able to skip children
|
||||
parser.skipChildren();
|
||||
//after skipChildren we are at the end of the skipped object, need to move on
|
||||
parser.nextToken();
|
||||
} else {
|
||||
parseContext.advanceToFieldName();
|
||||
if (!"do".equals(parser.currentName())) {
|
||||
throw new RestTestParseException("section [" + parser.currentName() + "] not supported within setup section");
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
setupSection.addDoSection(parseContext.parseDoSection());
|
||||
parser.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
|
||||
return setupSection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.parser;
|
||||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.rest.section.SkipSection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for skip sections
|
||||
*/
|
||||
public class SkipSectionParser implements RestTestFragmentParser<SkipSection> {
|
||||
|
||||
@Override
|
||||
public SkipSection parse(RestTestSuiteParseContext parseContext) throws IOException, RestTestParseException {
|
||||
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
String version = null;
|
||||
String reason = null;
|
||||
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("version".equals(currentFieldName)) {
|
||||
version = parser.text();
|
||||
} else if ("reason".equals(currentFieldName)) {
|
||||
reason = parser.text();
|
||||
} else {
|
||||
throw new RestTestParseException("field " + currentFieldName + " not supported within skip section");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
|
||||
if (!Strings.hasLength(version)) {
|
||||
throw new RestTestParseException("version is mandatory within skip section");
|
||||
}
|
||||
if (!Strings.hasLength(reason)) {
|
||||
throw new RestTestParseException("reason is mandatory within skip section");
|
||||
}
|
||||
|
||||
return new SkipSection(version, reason);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a test fragment that contains the information needed to call an api
|
||||
*/
|
||||
public class ApiCallSection {
|
||||
|
||||
private final String api;
|
||||
private final Map<String, String> params = Maps.newHashMap();
|
||||
private final List<String> bodies = Lists.newArrayList();
|
||||
|
||||
private static final String EMPTY_BODY = "";
|
||||
|
||||
public ApiCallSection(String api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
public String getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
//make sure we never modify the parameters once returned
|
||||
return ImmutableMap.copyOf(params);
|
||||
}
|
||||
|
||||
public void addParam(String key, String value) {
|
||||
String existingValue = params.get(key);
|
||||
if (existingValue != null) {
|
||||
value = Joiner.on(",").join(existingValue, value);
|
||||
}
|
||||
this.params.put(key, value);
|
||||
}
|
||||
|
||||
public List<String> getBodiesAsList() {
|
||||
return ImmutableList.copyOf(bodies);
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
if (bodies.size() == 0) {
|
||||
return EMPTY_BODY;
|
||||
}
|
||||
|
||||
if (bodies.size() == 1) {
|
||||
return bodies.get(0);
|
||||
}
|
||||
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
for (String body : bodies) {
|
||||
bodyBuilder.append(body).append("\n");
|
||||
}
|
||||
return bodyBuilder.toString();
|
||||
}
|
||||
|
||||
public void addBody(String body) {
|
||||
this.bodies.add(body);
|
||||
}
|
||||
|
||||
public boolean hasBody() {
|
||||
return bodies.size() > 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.test.rest.RestTestExecutionContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base class for executable sections that hold assertions
|
||||
*/
|
||||
public abstract class Assertion implements ExecutableSection {
|
||||
|
||||
private final String field;
|
||||
private final Object expectedValue;
|
||||
|
||||
protected Assertion(String field, Object expectedValue) {
|
||||
this.field = field;
|
||||
this.expectedValue = expectedValue;
|
||||
}
|
||||
|
||||
public final String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public final Object getExpectedValue() {
|
||||
return expectedValue;
|
||||
}
|
||||
|
||||
protected final Object resolveExpectedValue(RestTestExecutionContext executionContext) {
|
||||
if (executionContext.isStashed(expectedValue)) {
|
||||
return executionContext.unstash(expectedValue.toString());
|
||||
}
|
||||
return expectedValue;
|
||||
}
|
||||
|
||||
protected final Object getActualValue(RestTestExecutionContext executionContext) throws IOException {
|
||||
return executionContext.response(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(RestTestExecutionContext executionContext) throws IOException {
|
||||
doAssert(getActualValue(executionContext), resolveExpectedValue(executionContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the assertion comparing the actual value (parsed from the response) with the expected one
|
||||
*/
|
||||
protected abstract void doAssert(Object actualValue, Object expectedValue);
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.test.rest.RestTestExecutionContext;
|
||||
import org.elasticsearch.test.rest.client.RestException;
|
||||
import org.elasticsearch.test.rest.client.RestResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Represents a do section:
|
||||
*
|
||||
* - do:
|
||||
* catch: missing
|
||||
* update:
|
||||
* index: test_1
|
||||
* type: test
|
||||
* id: 1
|
||||
* body: { doc: { foo: bar } }
|
||||
*
|
||||
*/
|
||||
public class DoSection implements ExecutableSection {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(DoSection.class);
|
||||
|
||||
private String catchParam;
|
||||
private ApiCallSection apiCallSection;
|
||||
|
||||
public String getCatch() {
|
||||
return catchParam;
|
||||
}
|
||||
|
||||
public void setCatch(String catchParam) {
|
||||
this.catchParam = catchParam;
|
||||
}
|
||||
|
||||
public ApiCallSection getApiCallSection() {
|
||||
return apiCallSection;
|
||||
}
|
||||
|
||||
public void setApiCallSection(ApiCallSection apiCallSection) {
|
||||
this.apiCallSection = apiCallSection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(RestTestExecutionContext executionContext) throws IOException {
|
||||
|
||||
try {
|
||||
executionContext.callApi(apiCallSection.getApi(), apiCallSection.getParams(), apiCallSection.getBody());
|
||||
|
||||
} catch(RestException e) {
|
||||
if (!Strings.hasLength(catchParam)) {
|
||||
fail(formatStatusCodeMessage(e.restResponse(), "2xx"));
|
||||
}
|
||||
|
||||
if ("param".equals(catchParam)) {
|
||||
//client should throw validation error before sending request
|
||||
//lets just return without doing anything as we don't have any client to test here
|
||||
logger.info("found [catch: param], no request sent");
|
||||
} else if ("missing".equals(catchParam)) {
|
||||
assertThat(formatStatusCodeMessage(e.restResponse(), "404"), e.statusCode(), equalTo(404));
|
||||
} else if ("conflict".equals(catchParam)) {
|
||||
assertThat(formatStatusCodeMessage(e.restResponse(), "409"), e.statusCode(), equalTo(409));
|
||||
} else if ("forbidden".equals(catchParam)) {
|
||||
assertThat(formatStatusCodeMessage(e.restResponse(), "403"), e.statusCode(), equalTo(403));
|
||||
} else if ("request".equals(catchParam)) {
|
||||
//generic error response from ES
|
||||
assertThat(formatStatusCodeMessage(e.restResponse(), "4xx|5xx"), e.statusCode(), greaterThanOrEqualTo(400));
|
||||
} else if (catchParam.startsWith("/") && catchParam.endsWith("/")) {
|
||||
//the text of the error message matches regular expression
|
||||
assertThat(formatStatusCodeMessage(e.restResponse(), "4xx|5xx"), e.statusCode(), greaterThanOrEqualTo(400));
|
||||
Object error = executionContext.response("error");
|
||||
assertThat("error was expected in the response", error, notNullValue());
|
||||
//remove delimiters from regex
|
||||
String regex = catchParam.substring(1, catchParam.length() - 1);
|
||||
String errorMessage = error.toString();
|
||||
Matcher matcher = Pattern.compile(regex).matcher(errorMessage);
|
||||
assertThat("error message [" + errorMessage + "] was expected to match [" + catchParam + "] but didn't",
|
||||
matcher.find(), equalTo(true));
|
||||
} else {
|
||||
throw new UnsupportedOperationException("catch value [" + catchParam + "] not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String formatStatusCodeMessage(RestResponse restResponse, String expected) {
|
||||
return "expected [" + expected + "] status code but api [" + apiCallSection.getApi() + "] returned ["
|
||||
+ restResponse.getStatusCode() + " " + restResponse.getReasonPhrase() + "] [" + restResponse.getBody() + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.test.rest.RestTestExecutionContext;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents a test fragment that can be executed (e.g. api call, assertion)
|
||||
*/
|
||||
public interface ExecutableSection {
|
||||
|
||||
/**
|
||||
* Executes the section passing in the execution context
|
||||
*/
|
||||
void execute(RestTestExecutionContext executionContext) throws IOException;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Represents a gt assert section:
|
||||
*
|
||||
* - gt: { fields._ttl: 0}
|
||||
*
|
||||
*/
|
||||
public class GreaterThanAssertion extends Assertion {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(GreaterThanAssertion.class);
|
||||
|
||||
public GreaterThanAssertion(String field, Object expectedValue) {
|
||||
super(field, expectedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void doAssert(Object actualValue, Object expectedValue) {
|
||||
logger.trace("assert that [{}] is greater than [{}]", actualValue, expectedValue);
|
||||
assertThat(actualValue, instanceOf(Comparable.class));
|
||||
assertThat(expectedValue, instanceOf(Comparable.class));
|
||||
assertThat(errorMessage(), (Comparable)actualValue, greaterThan((Comparable) expectedValue));
|
||||
}
|
||||
|
||||
private String errorMessage() {
|
||||
return "field [" + getField() + "] is not greater than [" + getExpectedValue() + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Represents an is_false assert section:
|
||||
*
|
||||
* - is_false: get.fields.bar
|
||||
*
|
||||
*/
|
||||
public class IsFalseAssertion extends Assertion {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(IsFalseAssertion.class);
|
||||
|
||||
public IsFalseAssertion(String field) {
|
||||
super(field, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void doAssert(Object actualValue, Object expectedValue) {
|
||||
logger.trace("assert that [{}] doesn't have a true value", actualValue);
|
||||
|
||||
if (actualValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String actualString = actualValue.toString();
|
||||
assertThat(errorMessage(), actualString, anyOf(
|
||||
equalTo(""),
|
||||
equalToIgnoringCase(Boolean.FALSE.toString()),
|
||||
equalTo("0")
|
||||
));
|
||||
}
|
||||
|
||||
private String errorMessage() {
|
||||
return "field [" + getField() + "] has a true value but it shouldn't";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Represents an is_true assert section:
|
||||
*
|
||||
* - is_true: get.fields.bar
|
||||
*
|
||||
*/
|
||||
public class IsTrueAssertion extends Assertion {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(IsTrueAssertion.class);
|
||||
|
||||
public IsTrueAssertion(String field) {
|
||||
super(field, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAssert(Object actualValue, Object expectedValue) {
|
||||
logger.trace("assert that [{}] has a true value", actualValue);
|
||||
String errorMessage = errorMessage();
|
||||
assertThat(errorMessage, actualValue, notNullValue());
|
||||
String actualString = actualValue.toString();
|
||||
assertThat(errorMessage, actualString, not(equalTo("")));
|
||||
assertThat(errorMessage, actualString, not(equalToIgnoringCase(Boolean.FALSE.toString())));
|
||||
assertThat(errorMessage, actualString, not(equalTo("0")));
|
||||
}
|
||||
|
||||
private String errorMessage() {
|
||||
return "field [" + getField() + "] doesn't have a true value";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Represents a length assert section:
|
||||
*
|
||||
* - length: { hits.hits: 1 }
|
||||
*
|
||||
*/
|
||||
public class LengthAssertion extends Assertion {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(LengthAssertion.class);
|
||||
|
||||
public LengthAssertion(String field, Object expectedValue) {
|
||||
super(field, expectedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAssert(Object actualValue, Object expectedValue) {
|
||||
logger.trace("assert that [{}] has length [{}]", actualValue, expectedValue);
|
||||
assertThat(expectedValue, instanceOf(Number.class));
|
||||
int length = ((Number) expectedValue).intValue();
|
||||
if (actualValue instanceof String) {
|
||||
assertThat(errorMessage(), ((String) actualValue).length(), equalTo(length));
|
||||
} else if (actualValue instanceof List) {
|
||||
assertThat(errorMessage(), ((List) actualValue).size(), equalTo(length));
|
||||
} else if (actualValue instanceof Map) {
|
||||
assertThat(errorMessage(), ((Map) actualValue).keySet().size(), equalTo(length));
|
||||
} else {
|
||||
throw new UnsupportedOperationException("value is of unsupported type [" + actualValue.getClass().getSimpleName() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private String errorMessage() {
|
||||
return "field [" + getField() + "] doesn't have length [" + getExpectedValue() + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Represents a lt assert section:
|
||||
*
|
||||
* - lt: { fields._ttl: 20000}
|
||||
*
|
||||
*/
|
||||
public class LessThanAssertion extends Assertion {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(LessThanAssertion.class);
|
||||
|
||||
public LessThanAssertion(String field, Object expectedValue) {
|
||||
super(field, expectedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void doAssert(Object actualValue, Object expectedValue) {
|
||||
logger.trace("assert that [{}] is less than [{}]", actualValue, expectedValue);
|
||||
assertThat(actualValue, instanceOf(Comparable.class));
|
||||
assertThat(expectedValue, instanceOf(Comparable.class));
|
||||
assertThat(errorMessage(), (Comparable)actualValue, lessThan((Comparable)expectedValue));
|
||||
}
|
||||
|
||||
private String errorMessage() {
|
||||
return "field [" + getField() + "] is not less than [" + getExpectedValue() + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Represents a match assert section:
|
||||
*
|
||||
* - match: { get.fields._routing: "5" }
|
||||
*
|
||||
*/
|
||||
public class MatchAssertion extends Assertion {
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(MatchAssertion.class);
|
||||
|
||||
public MatchAssertion(String field, Object expectedValue) {
|
||||
super(field, expectedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAssert(Object actualValue, Object expectedValue) {
|
||||
assertThat(errorMessage(), actualValue, notNullValue());
|
||||
logger.trace("assert that [{}] matches [{}]", actualValue, expectedValue);
|
||||
if (!actualValue.getClass().equals(expectedValue.getClass())) {
|
||||
if (actualValue instanceof Number && expectedValue instanceof Number) {
|
||||
//Double 1.0 is equals to Integer 1
|
||||
assertThat(errorMessage(), ((Number) actualValue).doubleValue(), equalTo(((Number) expectedValue).doubleValue()));
|
||||
}
|
||||
} else {
|
||||
assertThat(errorMessage(), actualValue, equalTo(expectedValue));
|
||||
}
|
||||
}
|
||||
|
||||
private String errorMessage() {
|
||||
return "field [" + getField() + "] doesn't match the expected value";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds a REST test suite loaded from a specific yaml file.
|
||||
* Supports a setup section and multiple test sections.
|
||||
*/
|
||||
public class RestTestSuite {
|
||||
|
||||
private final String api;
|
||||
private final String name;
|
||||
|
||||
private SetupSection setupSection;
|
||||
|
||||
private List<TestSection> testSections = Lists.newArrayList();
|
||||
|
||||
public RestTestSuite(String api, String name) {
|
||||
this.api = replaceDot(api);
|
||||
this.name = replaceDot(name);
|
||||
}
|
||||
|
||||
public String getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
//describes the rest test suite (e.g. index/10_with_id)
|
||||
//useful also to reproduce failures (RestReproduceInfoPrinter)
|
||||
public String getDescription() {
|
||||
return api + File.separator + name;
|
||||
}
|
||||
|
||||
private static String replaceDot(String value) {
|
||||
// '.' is used as separator internally and not expected to be within suite or test names, better replace it
|
||||
return value.replace('.', '_');
|
||||
}
|
||||
|
||||
public SetupSection getSetupSection() {
|
||||
return setupSection;
|
||||
}
|
||||
|
||||
public void setSetupSection(SetupSection setupSection) {
|
||||
this.setupSection = setupSection;
|
||||
}
|
||||
|
||||
public void addTestSection(TestSection testSection) {
|
||||
this.testSections.add(testSection);
|
||||
}
|
||||
|
||||
public List<TestSection> getTestSections() {
|
||||
return testSections;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.elasticsearch.test.rest.RestTestExecutionContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a set section:
|
||||
*
|
||||
* - set: {_scroll_id: scroll_id}
|
||||
*
|
||||
*/
|
||||
public class SetSection implements ExecutableSection {
|
||||
|
||||
private Map<String, String> stash = Maps.newHashMap();
|
||||
|
||||
public void addSet(String responseField, String stashedField) {
|
||||
stash.put(responseField, stashedField);
|
||||
}
|
||||
|
||||
public Map<String, String> getStash() {
|
||||
return stash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(RestTestExecutionContext executionContext) throws IOException {
|
||||
for (Map.Entry<String, String> entry : stash.entrySet()) {
|
||||
Object actualValue = executionContext.response(entry.getKey());
|
||||
executionContext.stash(entry.getValue(), actualValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a setup section. Holds a skip section and multiple do sections.
|
||||
*/
|
||||
public class SetupSection {
|
||||
|
||||
public static final SetupSection EMPTY;
|
||||
|
||||
static {
|
||||
EMPTY = new SetupSection();
|
||||
EMPTY.setSkipSection(SkipSection.EMPTY);
|
||||
}
|
||||
|
||||
private SkipSection skipSection;
|
||||
|
||||
private List<DoSection> doSections = Lists.newArrayList();
|
||||
|
||||
public SkipSection getSkipSection() {
|
||||
return skipSection;
|
||||
}
|
||||
|
||||
public void setSkipSection(SkipSection skipSection) {
|
||||
this.skipSection = skipSection;
|
||||
}
|
||||
|
||||
public List<DoSection> getDoSections() {
|
||||
return doSections;
|
||||
}
|
||||
|
||||
public void addDoSection(DoSection doSection) {
|
||||
this.doSections.add(doSection);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return EMPTY.equals(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import org.elasticsearch.test.rest.support.VersionUtils;
|
||||
|
||||
/**
|
||||
* Represents a skip section that tells whether a specific test section or suite needs to be skipped
|
||||
* based on the elasticsearch version the tests are running against.
|
||||
*/
|
||||
public class SkipSection {
|
||||
|
||||
public static final SkipSection EMPTY = new SkipSection("", "");
|
||||
|
||||
private final String version;
|
||||
private final String reason;
|
||||
|
||||
public SkipSection(String version, String reason) {
|
||||
this.version = version;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public boolean skipVersion(String currentVersion) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return VersionUtils.skipCurrentVersion(version, currentVersion);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return EMPTY.equals(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.section;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a test section, which is composed of a skip section and multiple executable sections.
|
||||
*/
|
||||
public class TestSection {
|
||||
private final String name;
|
||||
private SkipSection skipSection;
|
||||
private final List<ExecutableSection> executableSections;
|
||||
|
||||
public TestSection(String name) {
|
||||
this.name = name;
|
||||
this.executableSections = Lists.newArrayList();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public SkipSection getSkipSection() {
|
||||
return skipSection;
|
||||
}
|
||||
|
||||
public void setSkipSection(SkipSection skipSection) {
|
||||
this.skipSection = skipSection;
|
||||
}
|
||||
|
||||
public List<ExecutableSection> getExecutableSections() {
|
||||
return executableSections;
|
||||
}
|
||||
|
||||
public void addExecutableSection(ExecutableSection executableSection) {
|
||||
this.executableSections.add(executableSection);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.spec;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.lucene.util.PriorityQueue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents an elasticsearch REST endpoint (api)
|
||||
*/
|
||||
public class RestApi {
|
||||
|
||||
private static final String ALL = "_all";
|
||||
|
||||
private final String name;
|
||||
private List<String> methods = Lists.newArrayList();
|
||||
private List<String> paths = Lists.newArrayList();
|
||||
private List<String> pathParts = Lists.newArrayList();
|
||||
|
||||
RestApi(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
RestApi(RestApi restApi, String name, String... methods) {
|
||||
this.name = name;
|
||||
this.methods = Arrays.asList(methods);
|
||||
paths.addAll(restApi.getPaths());
|
||||
pathParts.addAll(restApi.getPathParts());
|
||||
}
|
||||
|
||||
RestApi(RestApi restApi, List<String> paths) {
|
||||
this.name = restApi.getName();
|
||||
this.methods = restApi.getMethods();
|
||||
this.paths.addAll(paths);
|
||||
pathParts.addAll(restApi.getPathParts());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getMethods() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supported http methods given the rest parameters provided
|
||||
*/
|
||||
public List<String> getSupportedMethods(Set<String> restParams) {
|
||||
//we try to avoid hardcoded mappings but the index api is the exception
|
||||
if ("index".equals(name) || "create".equals(name)) {
|
||||
List<String> indexMethods = Lists.newArrayList();
|
||||
for (String method : methods) {
|
||||
if (restParams.contains("id")) {
|
||||
//PUT when the id is provided
|
||||
if (HttpPut.METHOD_NAME.equals(method)) {
|
||||
indexMethods.add(method);
|
||||
}
|
||||
} else {
|
||||
//POST without id
|
||||
if (HttpPost.METHOD_NAME.equals(method)) {
|
||||
indexMethods.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
return indexMethods;
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
void addMethod(String method) {
|
||||
this.methods.add(method);
|
||||
}
|
||||
|
||||
public List<String> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
void addPath(String path) {
|
||||
this.paths.add(path);
|
||||
}
|
||||
|
||||
public List<String> getPathParts() {
|
||||
return pathParts;
|
||||
}
|
||||
|
||||
void addPathPart(String pathPart) {
|
||||
this.pathParts.add(pathPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the best matching rest path given the current parameters and replaces
|
||||
* placeholders with their corresponding values received as arguments
|
||||
*/
|
||||
public String getFinalPath(Map<String, String> pathParams) {
|
||||
RestPath matchingRestPath = findMatchingRestPath(pathParams.keySet());
|
||||
String path = matchingRestPath.path;
|
||||
for (Map.Entry<String, String> paramEntry : matchingRestPath.params.entrySet()) {
|
||||
//replace path placeholders with actual values
|
||||
String value = pathParams.get(paramEntry.getValue());
|
||||
if (value == null) {
|
||||
//there might be additional placeholder to replace, not available as input params
|
||||
//it can only be {index} or {type} to be replaced with _all
|
||||
if (paramEntry.getValue().equals("index") || paramEntry.getValue().equals("type")) {
|
||||
value = ALL;
|
||||
} else {
|
||||
throw new IllegalArgumentException("path [" + path + "] contains placeholders that weren't replaced with proper values");
|
||||
}
|
||||
}
|
||||
path = path.replace(paramEntry.getKey(), value);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the best matching rest path out of the available ones with the current api (based on REST spec).
|
||||
*
|
||||
* The best path is the one that has exactly the same number of placeholders to replace
|
||||
* (e.g. /{index}/{type}/{id} when the params are exactly index, type and id).
|
||||
* Otherwise there might be additional placeholders, thus we use the path with the least additional placeholders.
|
||||
* (e.g. get with only index and id as parameters, the closest (and only) path contains {type} too, which becomes _all)
|
||||
*/
|
||||
private RestPath findMatchingRestPath(Set<String> restParams) {
|
||||
|
||||
RestPath[] restPaths = buildRestPaths();
|
||||
|
||||
//We need to find the path that has exactly the placeholders corresponding to our params
|
||||
//If there's no exact match we fallback to the closest one (with as less additional placeholders as possible)
|
||||
//The fallback is needed for:
|
||||
//1) get, get_source and exists with only index and id => /{index}/_all/{id} (
|
||||
//2) search with only type => /_all/{type/_search
|
||||
PriorityQueue<RestPath> restPathQueue = new PriorityQueue<RestPath>(1) {
|
||||
@Override
|
||||
protected boolean lessThan(RestPath a, RestPath b) {
|
||||
return a.params.size() >= b.params.size();
|
||||
}
|
||||
};
|
||||
for (RestPath restPath : restPaths) {
|
||||
if (restPath.params.values().containsAll(restParams)) {
|
||||
restPathQueue.insertWithOverflow(restPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (restPathQueue.size() > 0) {
|
||||
return restPathQueue.top();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unable to find best path for api [" + name + "] and params " + restParams);
|
||||
}
|
||||
|
||||
private RestPath[] buildRestPaths() {
|
||||
RestPath[] restPaths = new RestPath[paths.size()];
|
||||
for (int i = 0; i < restPaths.length; i++) {
|
||||
restPaths[i] = new RestPath(paths.get(i));
|
||||
}
|
||||
return restPaths;
|
||||
}
|
||||
|
||||
private static class RestPath {
|
||||
private static final Pattern PLACEHOLDERS_PATTERN = Pattern.compile("(\\{(.*?)})");
|
||||
|
||||
final String path;
|
||||
//contains param to replace (e.g. {index}) and param key to use for lookup in the current values map (e.g. index)
|
||||
final Map<String, String> params;
|
||||
|
||||
RestPath(String path) {
|
||||
this.path = path;
|
||||
this.params = extractParams(path);
|
||||
}
|
||||
|
||||
private static Map<String,String> extractParams(String input) {
|
||||
Map<String, String> params = Maps.newHashMap();
|
||||
Matcher matcher = PLACEHOLDERS_PATTERN.matcher(input);
|
||||
while (matcher.find()) {
|
||||
//key is e.g. {index}
|
||||
String key = input.substring(matcher.start(), matcher.end());
|
||||
if (matcher.groupCount() != 2) {
|
||||
throw new IllegalArgumentException("no lookup key found for param [" + key + "]");
|
||||
}
|
||||
//to be replaced with current value found with key e.g. index
|
||||
String value = matcher.group(2);
|
||||
params.put(key, value);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.spec;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parser for a REST api spec (single json file)
|
||||
*/
|
||||
public class RestApiParser {
|
||||
|
||||
public RestApi parse(XContentParser parser) throws IOException {
|
||||
|
||||
try {
|
||||
while ( parser.nextToken() != XContentParser.Token.FIELD_NAME ) {
|
||||
//move to first field name
|
||||
}
|
||||
|
||||
RestApi restApi = new RestApi(parser.currentName());
|
||||
|
||||
int level = -1;
|
||||
while (parser.nextToken() != XContentParser.Token.END_OBJECT || level >= 0) {
|
||||
|
||||
if (parser.currentToken() == XContentParser.Token.FIELD_NAME) {
|
||||
if ("methods".equals(parser.currentName())) {
|
||||
parser.nextToken();
|
||||
while (parser.nextToken() == XContentParser.Token.VALUE_STRING) {
|
||||
restApi.addMethod(parser.text());
|
||||
}
|
||||
}
|
||||
|
||||
if ("url".equals(parser.currentName())) {
|
||||
String currentFieldName = "url";
|
||||
int innerLevel = -1;
|
||||
while(parser.nextToken() != XContentParser.Token.END_OBJECT || innerLevel >= 0) {
|
||||
if (parser.currentToken() == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
}
|
||||
|
||||
if (parser.currentToken() == XContentParser.Token.START_ARRAY && "paths".equals(currentFieldName)) {
|
||||
while (parser.nextToken() == XContentParser.Token.VALUE_STRING) {
|
||||
restApi.addPath(parser.text());
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.currentToken() == XContentParser.Token.START_OBJECT && "parts".equals(currentFieldName)) {
|
||||
while (parser.nextToken() == XContentParser.Token.FIELD_NAME) {
|
||||
restApi.addPathPart(parser.currentName());
|
||||
parser.nextToken();
|
||||
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
|
||||
parser.skipChildren();
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
||||
innerLevel++;
|
||||
}
|
||||
if (parser.currentToken() == XContentParser.Token.END_OBJECT) {
|
||||
innerLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
||||
level++;
|
||||
}
|
||||
if (parser.currentToken() == XContentParser.Token.END_OBJECT) {
|
||||
level--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parser.nextToken();
|
||||
assert parser.currentToken() == XContentParser.Token.END_OBJECT;
|
||||
parser.nextToken();
|
||||
|
||||
return restApi;
|
||||
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.spec;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.test.rest.support.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds the elasticsearch REST spec
|
||||
*/
|
||||
public class RestSpec {
|
||||
Map<String, RestApi> restApiMap = Maps.newHashMap();
|
||||
|
||||
private RestSpec() {
|
||||
}
|
||||
|
||||
void addApi(RestApi restApi) {
|
||||
if ("info".equals(restApi.getName())) {
|
||||
//info and ping should really be two different api in the rest spec
|
||||
//info (GET|HEAD /) needs to be manually split into 1) info: GET / 2) ping: HEAD /
|
||||
restApiMap.put("info", new RestApi(restApi, "info", "GET"));
|
||||
restApiMap.put("ping", new RestApi(restApi, "ping", "HEAD"));
|
||||
} else if ("get".equals(restApi.getName())) {
|
||||
//get_source endpoint shouldn't be present in the rest spec for the get api
|
||||
//as get_source is already a separate api
|
||||
List<String> paths = Lists.newArrayList();
|
||||
for (String path : restApi.getPaths()) {
|
||||
if (!path.endsWith("/_source")) {
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
restApiMap.put(restApi.getName(), new RestApi(restApi, paths));
|
||||
} else {
|
||||
restApiMap.put(restApi.getName(), restApi);
|
||||
}
|
||||
}
|
||||
|
||||
public RestApi getApi(String api) {
|
||||
return restApiMap.get(api);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the complete set of REST spec available under the provided directories
|
||||
*/
|
||||
public static RestSpec parseFrom(String optionalPathPrefix, String... paths) throws IOException {
|
||||
RestSpec restSpec = new RestSpec();
|
||||
for (String path : paths) {
|
||||
for (File jsonFile : FileUtils.findJsonSpec(optionalPathPrefix, path)) {
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(new FileInputStream(jsonFile));
|
||||
RestApi restApi = new RestApiParser().parse(parser);
|
||||
restSpec.addApi(restApi);
|
||||
}
|
||||
}
|
||||
return restSpec;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.support;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class FileUtils {
|
||||
|
||||
private static final String YAML_SUFFIX = ".yaml";
|
||||
private static final String JSON_SUFFIX = ".json";
|
||||
|
||||
private FileUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json files found within the directory provided as argument.
|
||||
* Files are looked up in the classpath first, then outside of it if not found.
|
||||
*/
|
||||
public static Set<File> findJsonSpec(String optionalPathPrefix, String path) throws FileNotFoundException {
|
||||
File dir = resolveFile(optionalPathPrefix, path, null);
|
||||
|
||||
if (!dir.isDirectory()) {
|
||||
throw new FileNotFoundException("file [" + path + "] is not a directory");
|
||||
}
|
||||
|
||||
File[] jsonFiles = dir.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
return pathname.getName().endsWith(JSON_SUFFIX);
|
||||
}
|
||||
});
|
||||
|
||||
if (jsonFiles == null || jsonFiles.length == 0) {
|
||||
throw new FileNotFoundException("no json files found within [" + path + "]");
|
||||
}
|
||||
|
||||
return Sets.newHashSet(jsonFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the yaml files found within the paths provided.
|
||||
* Each input path can either be a single file (the .yaml suffix is optional) or a directory.
|
||||
* Each path is looked up in the classpath first, then outside of it if not found yet.
|
||||
*/
|
||||
public static Map<String, Set<File>> findYamlSuites(final String optionalPathPrefix, final String... paths) throws FileNotFoundException {
|
||||
Map<String, Set<File>> yamlSuites = Maps.newHashMap();
|
||||
for (String path : paths) {
|
||||
collectFiles(resolveFile(optionalPathPrefix, path, YAML_SUFFIX), YAML_SUFFIX, yamlSuites);
|
||||
}
|
||||
return yamlSuites;
|
||||
}
|
||||
|
||||
private static File resolveFile(String optionalPathPrefix, String path, String optionalFileSuffix) throws FileNotFoundException {
|
||||
//try within classpath with and without file suffix (as it could be a single test suite)
|
||||
URL resource = findResource(path, optionalFileSuffix);
|
||||
if (resource == null) {
|
||||
//try within classpath with optional prefix: /rest-spec/test (or /rest-test/api) is optional
|
||||
String newPath = optionalPathPrefix + File.separator + path;
|
||||
resource = findResource(newPath, optionalFileSuffix);
|
||||
if (resource == null) {
|
||||
//if it wasn't on classpath we look outside ouf the classpath
|
||||
File file = findFile(path, optionalFileSuffix);
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException("file [" + path + "] doesn't exist");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return new File(resource.getFile());
|
||||
}
|
||||
|
||||
private static URL findResource(String path, String optionalFileSuffix) {
|
||||
URL resource = FileUtils.class.getResource(path);
|
||||
if (resource == null) {
|
||||
//if not found we append the file suffix to the path (as it is optional)
|
||||
if (Strings.hasLength(optionalFileSuffix) && !path.endsWith(optionalFileSuffix)) {
|
||||
resource = FileUtils.class.getResource(path + optionalFileSuffix);
|
||||
}
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
private static File findFile(String path, String optionalFileSuffix) {
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
file = new File(path + optionalFileSuffix);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void collectFiles(final File file, final String fileSuffix, final Map<String, Set<File>> files) {
|
||||
if (file.isFile()) {
|
||||
// '.' is uses as separator internally and not expected to be within suite or test names, better replace it
|
||||
String groupName = file.getParentFile().getName().replace('.', '_');
|
||||
Set<File> filesSet = files.get(groupName);
|
||||
if (filesSet == null) {
|
||||
filesSet = Sets.newHashSet();
|
||||
files.put(groupName, filesSet);
|
||||
}
|
||||
filesSet.add(file);
|
||||
} else if (file.isDirectory()) {
|
||||
walkDir(file, fileSuffix, files);
|
||||
}
|
||||
}
|
||||
|
||||
private static void walkDir(final File dir, final String fileSuffix, final Map<String, Set<File>> files) {
|
||||
File[] children = dir.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
return pathname.isDirectory() || pathname.getName().endsWith(fileSuffix);
|
||||
}
|
||||
});
|
||||
|
||||
for (File file : children) {
|
||||
collectFiles(file, fileSuffix, files);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.support;
|
||||
|
||||
public final class VersionUtils {
|
||||
|
||||
private VersionUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an elasticsearch version string into an int array with an element per part
|
||||
* e.g. 0.90.7 => [0,90,7]
|
||||
*/
|
||||
public static int[] parseVersionNumber(String version) {
|
||||
String[] split = version.split("\\.");
|
||||
//we only take the first 3 parts if there are more, but less is ok too (e.g. 999)
|
||||
int length = Math.min(3, split.length);
|
||||
int[] versionNumber = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
try {
|
||||
versionNumber[i] = Integer.valueOf(split[i]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("version is not a number", e);
|
||||
}
|
||||
|
||||
}
|
||||
return versionNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the skip version read from a test fragment with the elasticsearch version
|
||||
* the tests are running against and determines whether the test fragment needs to be skipped
|
||||
*/
|
||||
public static boolean skipCurrentVersion(String skipVersion, String currentVersion) {
|
||||
int[] currentVersionNumber = parseVersionNumber(currentVersion);
|
||||
|
||||
String[] skipVersions = skipVersion.split("-");
|
||||
if (skipVersions.length > 2) {
|
||||
throw new IllegalArgumentException("too many skip versions found");
|
||||
}
|
||||
|
||||
String skipVersionLowerBound = skipVersions[0].trim();
|
||||
String skipVersionUpperBound = skipVersions[1].trim();
|
||||
|
||||
int[] skipVersionLowerBoundNumber = parseVersionNumber(skipVersionLowerBound);
|
||||
int[] skipVersionUpperBoundNumber = parseVersionNumber(skipVersionUpperBound);
|
||||
|
||||
int length = Math.min(skipVersionLowerBoundNumber.length, currentVersionNumber.length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (currentVersionNumber[i] < skipVersionLowerBoundNumber[i]) {
|
||||
return false;
|
||||
}
|
||||
if (currentVersionNumber[i] > skipVersionLowerBoundNumber[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
length = Math.min(skipVersionUpperBoundNumber.length, currentVersionNumber.length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (currentVersionNumber[i] > skipVersionUpperBoundNumber[i]) {
|
||||
return false;
|
||||
}
|
||||
if (currentVersionNumber[i] < skipVersionUpperBoundNumber[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
@Ignore
|
||||
public class AbstractParserTests extends ElasticsearchTestCase {
|
||||
|
||||
protected XContentParser parser;
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
//this is the way to make sure that we consumed the whole yaml
|
||||
assertThat(parser.currentToken(), nullValue());
|
||||
parser.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.parser.*;
|
||||
import org.elasticsearch.test.rest.section.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class AssertionParsersTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseIsTrue() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"get.fields._timestamp"
|
||||
);
|
||||
|
||||
IsTrueParser isTrueParser = new IsTrueParser();
|
||||
IsTrueAssertion trueAssertion = isTrueParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(trueAssertion, notNullValue());
|
||||
assertThat(trueAssertion.getField(), equalTo("get.fields._timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseIsFalse() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"docs.1._source"
|
||||
);
|
||||
|
||||
IsFalseParser isFalseParser = new IsFalseParser();
|
||||
IsFalseAssertion falseAssertion = isFalseParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(falseAssertion, notNullValue());
|
||||
assertThat(falseAssertion.getField(), equalTo("docs.1._source"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseGreaterThan() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ field: 3}"
|
||||
);
|
||||
|
||||
GreaterThanParser greaterThanParser = new GreaterThanParser();
|
||||
GreaterThanAssertion greaterThanAssertion = greaterThanParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
assertThat(greaterThanAssertion, notNullValue());
|
||||
assertThat(greaterThanAssertion.getField(), equalTo("field"));
|
||||
assertThat(greaterThanAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) greaterThanAssertion.getExpectedValue(), equalTo(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLessThan() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ field: 3}"
|
||||
);
|
||||
|
||||
LessThanParser lessThanParser = new LessThanParser();
|
||||
LessThanAssertion lessThanAssertion = lessThanParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
assertThat(lessThanAssertion, notNullValue());
|
||||
assertThat(lessThanAssertion.getField(), equalTo("field"));
|
||||
assertThat(lessThanAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) lessThanAssertion.getExpectedValue(), equalTo(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLength() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ _id: 22}"
|
||||
);
|
||||
|
||||
LengthParser lengthParser = new LengthParser();
|
||||
LengthAssertion lengthAssertion = lengthParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
assertThat(lengthAssertion, notNullValue());
|
||||
assertThat(lengthAssertion.getField(), equalTo("_id"));
|
||||
assertThat(lengthAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) lengthAssertion.getExpectedValue(), equalTo(22));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testParseMatchSimpleIntegerValue() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ field: 10 }"
|
||||
);
|
||||
|
||||
MatchParser matchParser = new MatchParser();
|
||||
MatchAssertion matchAssertion = matchParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(matchAssertion, notNullValue());
|
||||
assertThat(matchAssertion.getField(), equalTo("field"));
|
||||
assertThat(matchAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) matchAssertion.getExpectedValue(), equalTo(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testParseMatchSimpleStringValue() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ foo: bar }"
|
||||
);
|
||||
|
||||
MatchParser matchParser = new MatchParser();
|
||||
MatchAssertion matchAssertion = matchParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(matchAssertion, notNullValue());
|
||||
assertThat(matchAssertion.getField(), equalTo("foo"));
|
||||
assertThat(matchAssertion.getExpectedValue(), instanceOf(String.class));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testParseMatchArray() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{'matches': ['test_percolator_1', 'test_percolator_2']}"
|
||||
);
|
||||
|
||||
MatchParser matchParser = new MatchParser();
|
||||
MatchAssertion matchAssertion = matchParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(matchAssertion, notNullValue());
|
||||
assertThat(matchAssertion.getField(), equalTo("matches"));
|
||||
assertThat(matchAssertion.getExpectedValue(), instanceOf(List.class));
|
||||
List strings = (List) matchAssertion.getExpectedValue();
|
||||
assertThat(strings.size(), equalTo(2));
|
||||
assertThat(strings.get(0).toString(), equalTo("test_percolator_1"));
|
||||
assertThat(strings.get(1).toString(), equalTo("test_percolator_2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testParseMatchSourceValues() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ _source: { responses.0.hits.total: 3, foo: bar }}"
|
||||
);
|
||||
|
||||
MatchParser matchParser = new MatchParser();
|
||||
MatchAssertion matchAssertion = matchParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(matchAssertion, notNullValue());
|
||||
assertThat(matchAssertion.getField(), equalTo("_source"));
|
||||
assertThat(matchAssertion.getExpectedValue(), instanceOf(Map.class));
|
||||
Map<String, Object> expectedValue = (Map<String, Object>) matchAssertion.getExpectedValue();
|
||||
assertThat(expectedValue.size(), equalTo(2));
|
||||
Object o = expectedValue.get("responses.0.hits.total");
|
||||
assertThat(o, instanceOf(Integer.class));
|
||||
assertThat((Integer)o, equalTo(3));
|
||||
o = expectedValue.get("foo");
|
||||
assertThat(o, instanceOf(String.class));
|
||||
assertThat(o.toString(), equalTo("bar"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.parser.DoSectionParser;
|
||||
import org.elasticsearch.test.rest.parser.RestTestParseException;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParseContext;
|
||||
import org.elasticsearch.test.rest.section.ApiCallSection;
|
||||
import org.elasticsearch.test.rest.section.DoSection;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class DoSectionParserTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionNoBody() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"get:\n" +
|
||||
" index: test_index\n" +
|
||||
" type: test_type\n" +
|
||||
" id: 1"
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("get"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(3));
|
||||
assertThat(apiCallSection.getParams().get("index"), equalTo("test_index"));
|
||||
assertThat(apiCallSection.getParams().get("type"), equalTo("test_type"));
|
||||
assertThat(apiCallSection.getParams().get("id"), equalTo("1"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionNoParamsNoBody() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"cluster.node_info: {}"
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("cluster.node_info"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(0));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithJsonBody() throws Exception {
|
||||
String body = "{ \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }";
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"index:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: " + body
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("index"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(3));
|
||||
assertThat(apiCallSection.getParams().get("index"), equalTo("test_1"));
|
||||
assertThat(apiCallSection.getParams().get("type"), equalTo("test"));
|
||||
assertThat(apiCallSection.getParams().get("id"), equalTo("1"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(0), body);
|
||||
assertJsonEquals(apiCallSection.getBody(), body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithJsonMultipleBodiesAsLongString() throws Exception {
|
||||
String bodies[] = new String[]{
|
||||
"{ \"index\": { \"_index\":\"test_index\", \"_type\":\"test_type\", \"_id\":\"test_id\" } }\n",
|
||||
"{ \"f1\":\"v1\", \"f2\":42 }\n",
|
||||
"{ \"index\": { \"_index\":\"test_index2\", \"_type\":\"test_type2\", \"_id\":\"test_id2\" } }\n",
|
||||
"{ \"f1\":\"v2\", \"f2\":47 }\n"
|
||||
};
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"bulk:\n" +
|
||||
" refresh: true\n" +
|
||||
" body: |\n" +
|
||||
" " + bodies[0] +
|
||||
" " + bodies[1] +
|
||||
" " + bodies[2] +
|
||||
" " + bodies[3]
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("bulk"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(1));
|
||||
assertThat(apiCallSection.getParams().get("refresh"), equalTo("true"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(1));
|
||||
StringBuilder bodyBuilder = new StringBuilder();
|
||||
for (String body : bodies) {
|
||||
bodyBuilder.append(body);
|
||||
}
|
||||
assertThat(apiCallSection.getBody(), equalTo(bodyBuilder.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithJsonMultipleBodiesRepeatedProperty() throws Exception {
|
||||
String[] bodies = new String[] {
|
||||
"{ \"index\": { \"_index\":\"test_index\", \"_type\":\"test_type\", \"_id\":\"test_id\" } }",
|
||||
"{ \"f1\":\"v1\", \"f2\":42 }",
|
||||
};
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"bulk:\n" +
|
||||
" refresh: true\n" +
|
||||
" body: \n" +
|
||||
" " + bodies[0] + "\n" +
|
||||
" body: \n" +
|
||||
" " + bodies[1]
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("bulk"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(1));
|
||||
assertThat(apiCallSection.getParams().get("refresh"), equalTo("true"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(bodies.length));
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(i), bodies[i]);
|
||||
}
|
||||
|
||||
String[] returnedBodies = apiCallSection.getBody().split("\n");
|
||||
assertThat(returnedBodies.length, equalTo(bodies.length));
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
assertJsonEquals(returnedBodies[i], bodies[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithYamlBody() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"search:\n" +
|
||||
" body:\n" +
|
||||
" _source: [ include.field1, include.field2 ]\n" +
|
||||
" query: { match_all: {} }"
|
||||
);
|
||||
String body = "{ \"_source\": [ \"include.field1\", \"include.field2\" ], \"query\": { \"match_all\": {} }}";
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("search"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(0));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(1));
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(0), body);
|
||||
assertJsonEquals(apiCallSection.getBody(), body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithYamlMultipleBodies() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"bulk:\n" +
|
||||
" refresh: true\n" +
|
||||
" body:\n" +
|
||||
" - index:\n" +
|
||||
" _index: test_index\n" +
|
||||
" _type: test_type\n" +
|
||||
" _id: test_id\n" +
|
||||
" - f1: v1\n" +
|
||||
" f2: 42\n" +
|
||||
" - index:\n" +
|
||||
" _index: test_index2\n" +
|
||||
" _type: test_type2\n" +
|
||||
" _id: test_id2\n" +
|
||||
" - f1: v2\n" +
|
||||
" f2: 47"
|
||||
);
|
||||
String[] bodies = new String[4];
|
||||
bodies[0] = "{\"index\": {\"_index\": \"test_index\", \"_type\": \"test_type\", \"_id\": \"test_id\"}}";
|
||||
bodies[1] = "{ \"f1\":\"v1\", \"f2\": 42 }";
|
||||
bodies[2] = "{\"index\": {\"_index\": \"test_index2\", \"_type\": \"test_type2\", \"_id\": \"test_id2\"}}";
|
||||
bodies[3] = "{ \"f1\":\"v2\", \"f2\": 47 }";
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("bulk"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(1));
|
||||
assertThat(apiCallSection.getParams().get("refresh"), equalTo("true"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(bodies.length));
|
||||
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(i), bodies[i]);
|
||||
}
|
||||
|
||||
String[] returnedBodies = apiCallSection.getBody().split("\n");
|
||||
assertThat(returnedBodies.length, equalTo(bodies.length));
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
assertJsonEquals(returnedBodies[i], bodies[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithYamlMultipleBodiesRepeatedProperty() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"bulk:\n" +
|
||||
" refresh: true\n" +
|
||||
" body:\n" +
|
||||
" index:\n" +
|
||||
" _index: test_index\n" +
|
||||
" _type: test_type\n" +
|
||||
" _id: test_id\n" +
|
||||
" body:\n" +
|
||||
" f1: v1\n" +
|
||||
" f2: 42\n"
|
||||
);
|
||||
String[] bodies = new String[2];
|
||||
bodies[0] = "{\"index\": {\"_index\": \"test_index\", \"_type\": \"test_type\", \"_id\": \"test_id\"}}";
|
||||
bodies[1] = "{ \"f1\":\"v1\", \"f2\": 42 }";
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("bulk"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(1));
|
||||
assertThat(apiCallSection.getParams().get("refresh"), equalTo("true"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(bodies.length));
|
||||
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(i), bodies[i]);
|
||||
}
|
||||
|
||||
String[] returnedBodies = apiCallSection.getBody().split("\n");
|
||||
assertThat(returnedBodies.length, equalTo(bodies.length));
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
assertJsonEquals(returnedBodies[i], bodies[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithYamlBodyMultiGet() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"mget:\n" +
|
||||
" body:\n" +
|
||||
" docs:\n" +
|
||||
" - { _index: test_2, _type: test, _id: 1}\n" +
|
||||
" - { _index: test_1, _type: none, _id: 1}"
|
||||
);
|
||||
String body = "{ \"docs\": [ " +
|
||||
"{\"_index\": \"test_2\", \"_type\":\"test\", \"_id\":1}, " +
|
||||
"{\"_index\": \"test_1\", \"_type\":\"none\", \"_id\":1} " +
|
||||
"]}";
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("mget"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(0));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(1));
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(0), body);
|
||||
assertJsonEquals(apiCallSection.getBody(), body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithBodyStringified() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"index:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: \"{ _source: true, query: { match_all: {} } }\""
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection, notNullValue());
|
||||
assertThat(apiCallSection.getApi(), equalTo("index"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(3));
|
||||
assertThat(apiCallSection.getParams().get("index"), equalTo("test_1"));
|
||||
assertThat(apiCallSection.getParams().get("type"), equalTo("test"));
|
||||
assertThat(apiCallSection.getParams().get("id"), equalTo("1"));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(1));
|
||||
//stringified body is taken as is
|
||||
assertThat(apiCallSection.getBodiesAsList().get(0), equalTo("{ _source: true, query: { match_all: {} } }"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithBodiesStringifiedAndNot() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"index:\n" +
|
||||
" body:\n" +
|
||||
" - \"{ _source: true, query: { match_all: {} } }\"\n" +
|
||||
" - { size: 100, query: { match_all: {} } }"
|
||||
);
|
||||
|
||||
String body = "{ \"size\": 100, \"query\": { \"match_all\": {} } }";
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
ApiCallSection apiCallSection = doSection.getApiCallSection();
|
||||
|
||||
assertThat(apiCallSection.getApi(), equalTo("index"));
|
||||
assertThat(apiCallSection.getParams().size(), equalTo(0));
|
||||
assertThat(apiCallSection.hasBody(), equalTo(true));
|
||||
assertThat(apiCallSection.getBodiesAsList().size(), equalTo(2));
|
||||
//stringified body is taken as is
|
||||
assertThat(apiCallSection.getBodiesAsList().get(0), equalTo("{ _source: true, query: { match_all: {} } }"));
|
||||
assertJsonEquals(apiCallSection.getBodiesAsList().get(1), body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionWithCatch() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"catch: missing\n" +
|
||||
"indices.get_warmer:\n" +
|
||||
" index: test_index\n" +
|
||||
" name: test_warmer"
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(doSection.getCatch(), equalTo("missing"));
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_warmer"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(2));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test (expected = RestTestParseException.class)
|
||||
public void testParseDoSectionWithoutClientCallSection() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"catch: missing\n"
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDoSectionMultivaluedField() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"indices.get_field_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
" type: test_type\n" +
|
||||
" field: [ text , text1 ]"
|
||||
);
|
||||
|
||||
DoSectionParser doSectionParser = new DoSectionParser();
|
||||
DoSection doSection = doSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_field_mapping"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("index"), equalTo("test_index"));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("type"), equalTo("test_type"));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("field"), equalTo("text,text1"));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
assertThat(doSection.getApiCallSection().getBodiesAsList().size(), equalTo(0));
|
||||
}
|
||||
|
||||
private static void assertJsonEquals(String actual, String expected) throws IOException {
|
||||
Map<String,Object> actualMap = JsonXContent.jsonXContent.createParser(actual).mapOrderedAndClose();
|
||||
Map<String,Object> expectedMap = JsonXContent.jsonXContent.createParser(expected).mapOrderedAndClose();
|
||||
MatcherAssert.assertThat(actualMap, equalTo(expectedMap));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.rest.support.FileUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
|
||||
public class FileUtilsTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testLoadSingleYamlSuite() throws Exception {
|
||||
Map<String,Set<File>> yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "/rest-spec/test/get/10_basic");
|
||||
assertSingleFile(yamlSuites, "get", "10_basic.yaml");
|
||||
|
||||
//the path prefix is optional
|
||||
yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get/10_basic.yaml");
|
||||
assertSingleFile(yamlSuites, "get", "10_basic.yaml");
|
||||
|
||||
//extension .yaml is optional
|
||||
yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get/10_basic");
|
||||
assertSingleFile(yamlSuites, "get", "10_basic.yaml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadMultipleYamlSuites() throws Exception {
|
||||
//single directory
|
||||
Map<String,Set<File>> yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get");
|
||||
assertThat(yamlSuites, notNullValue());
|
||||
assertThat(yamlSuites.size(), equalTo(1));
|
||||
assertThat(yamlSuites.containsKey("get"), equalTo(true));
|
||||
assertThat(yamlSuites.get("get").size(), greaterThan(1));
|
||||
|
||||
//multiple directories
|
||||
yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get", "index");
|
||||
assertThat(yamlSuites, notNullValue());
|
||||
assertThat(yamlSuites.size(), equalTo(2));
|
||||
assertThat(yamlSuites.containsKey("get"), equalTo(true));
|
||||
assertThat(yamlSuites.get("get").size(), greaterThan(1));
|
||||
assertThat(yamlSuites.containsKey("index"), equalTo(true));
|
||||
assertThat(yamlSuites.get("index").size(), greaterThan(1));
|
||||
|
||||
//multiple paths, which can be both directories or yaml test suites (with optional file extension)
|
||||
yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get/10_basic", "index");
|
||||
assertThat(yamlSuites, notNullValue());
|
||||
assertThat(yamlSuites.size(), equalTo(2));
|
||||
assertThat(yamlSuites.containsKey("get"), equalTo(true));
|
||||
assertThat(yamlSuites.get("get").size(), equalTo(1));
|
||||
assertSingleFile(yamlSuites.get("get"), "get", "10_basic.yaml");
|
||||
assertThat(yamlSuites.containsKey("index"), equalTo(true));
|
||||
assertThat(yamlSuites.get("index").size(), greaterThan(1));
|
||||
|
||||
//files can be loaded from classpath and from file system too
|
||||
File dir = newTempDir();
|
||||
File file = new File(dir, "test_loading.yaml");
|
||||
assertThat(file.createNewFile(), equalTo(true));
|
||||
|
||||
//load from directory outside of the classpath
|
||||
yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get/10_basic", dir.getAbsolutePath());
|
||||
assertThat(yamlSuites, notNullValue());
|
||||
assertThat(yamlSuites.size(), equalTo(2));
|
||||
assertThat(yamlSuites.containsKey("get"), equalTo(true));
|
||||
assertThat(yamlSuites.get("get").size(), equalTo(1));
|
||||
assertSingleFile(yamlSuites.get("get"), "get", "10_basic.yaml");
|
||||
assertThat(yamlSuites.containsKey(dir.getName()), equalTo(true));
|
||||
assertSingleFile(yamlSuites.get(dir.getName()), dir.getName(), file.getName());
|
||||
|
||||
//load from external file (optional extension)
|
||||
yamlSuites = FileUtils.findYamlSuites("/rest-spec/test", "get/10_basic", dir.getAbsolutePath() + File.separator + "test_loading");
|
||||
assertThat(yamlSuites, notNullValue());
|
||||
assertThat(yamlSuites.size(), equalTo(2));
|
||||
assertThat(yamlSuites.containsKey("get"), equalTo(true));
|
||||
assertThat(yamlSuites.get("get").size(), equalTo(1));
|
||||
assertSingleFile(yamlSuites.get("get"), "get", "10_basic.yaml");
|
||||
assertThat(yamlSuites.containsKey(dir.getName()), equalTo(true));
|
||||
assertSingleFile(yamlSuites.get(dir.getName()), dir.getName(), file.getName());
|
||||
}
|
||||
|
||||
private static void assertSingleFile(Map<String, Set<File>> yamlSuites, String dirName, String fileName) {
|
||||
assertThat(yamlSuites, notNullValue());
|
||||
assertThat(yamlSuites.size(), equalTo(1));
|
||||
assertThat(yamlSuites.containsKey(dirName), equalTo(true));
|
||||
assertSingleFile(yamlSuites.get(dirName), dirName, fileName);
|
||||
}
|
||||
|
||||
private static void assertSingleFile(Set<File> files, String dirName, String fileName) {
|
||||
assertThat(files.size(), equalTo(1));
|
||||
File file = files.iterator().next();
|
||||
assertThat(file.getName(), equalTo(fileName));
|
||||
assertThat(file.getParentFile().getName(), equalTo(dirName));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.rest.json.JsonPath;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class JsonPathTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testEvaluateObjectPathEscape() throws Exception {
|
||||
String json = "{ \"field1\": { \"field2.field3\" : \"value2\" } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.field2\\.field3");
|
||||
assertThat(object, instanceOf(String.class));
|
||||
assertThat((String)object, equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateObjectPathWithDoubleDot() throws Exception {
|
||||
String json = "{ \"field1\": { \"field2\" : \"value2\" } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1..field2");
|
||||
assertThat(object, instanceOf(String.class));
|
||||
assertThat((String)object, equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateObjectPathEndsWithDot() throws Exception {
|
||||
String json = "{ \"field1\": { \"field2\" : \"value2\" } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.field2.");
|
||||
assertThat(object, instanceOf(String.class));
|
||||
assertThat((String)object, equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateString() throws Exception {
|
||||
String json = "{ \"field1\": { \"field2\" : \"value2\" } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.field2");
|
||||
assertThat(object, instanceOf(String.class));
|
||||
assertThat((String)object, equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateInteger() throws Exception {
|
||||
String json = "{ \"field1\": { \"field2\" : 333 } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.field2");
|
||||
assertThat(object, instanceOf(Integer.class));
|
||||
assertThat((Integer)object, equalTo(333));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateDouble() throws Exception {
|
||||
String json = "{ \"field1\": { \"field2\" : 3.55 } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.field2");
|
||||
assertThat(object, instanceOf(Double.class));
|
||||
assertThat((Double)object, equalTo(3.55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateArray() throws Exception {
|
||||
String json = "{ \"field1\": { \"array1\" : [ \"value1\", \"value2\" ] } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.array1");
|
||||
assertThat(object, instanceOf(List.class));
|
||||
List list = (List) object;
|
||||
assertThat(list.size(), equalTo(2));
|
||||
assertThat(list.get(0), instanceOf(String.class));
|
||||
assertThat((String)list.get(0), equalTo("value1"));
|
||||
assertThat(list.get(1), instanceOf(String.class));
|
||||
assertThat((String)list.get(1), equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateArrayElement() throws Exception {
|
||||
String json = "{ \"field1\": { \"array1\" : [ \"value1\", \"value2\" ] } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.array1.1");
|
||||
assertThat(object, instanceOf(String.class));
|
||||
assertThat((String)object, equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateArrayElementObject() throws Exception {
|
||||
String json = "{ \"field1\": { \"array1\" : [ {\"element\": \"value1\"}, {\"element\":\"value2\"} ] } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.array1.1.element");
|
||||
assertThat(object, instanceOf(String.class));
|
||||
assertThat((String)object, equalTo("value2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvaluateArrayElementObjectWrongPath() throws Exception {
|
||||
String json = "{ \"field1\": { \"array1\" : [ {\"element\": \"value1\"}, {\"element\":\"value2\"} ] } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("field1.array2.1.element");
|
||||
assertThat(object, nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testEvaluateObjectKeys() throws Exception {
|
||||
String json = "{ \"metadata\": { \"templates\" : {\"template_1\": { \"field\" : \"value\"}, \"template_2\": { \"field\" : \"value\"} } } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("metadata.templates");
|
||||
assertThat(object, instanceOf(Map.class));
|
||||
Map<String, Object> map = (Map<String, Object>)object;
|
||||
assertThat(map.size(), equalTo(2));
|
||||
Set<String> strings = map.keySet();
|
||||
assertThat(strings, contains("template_1", "template_2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testEvaluateEmptyPath() throws Exception {
|
||||
String json = "{ \"field1\": { \"array1\" : [ {\"element\": \"value1\"}, {\"element\":\"value2\"} ] } }";
|
||||
JsonPath jsonPath = new JsonPath(json);
|
||||
Object object = jsonPath.evaluate("");
|
||||
assertThat(object, notNullValue());
|
||||
assertThat(object, instanceOf(Map.class));
|
||||
assertThat(((Map<String, Object>)object).containsKey("field1"), equalTo(true));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.test.rest.spec.RestApi;
|
||||
import org.elasticsearch.test.rest.spec.RestApiParser;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public class RestApiParserTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseRestSpecIndexApi() throws Exception {
|
||||
parser = JsonXContent.jsonXContent.createParser(REST_SPEC_INDEX_API);
|
||||
RestApi restApi = new RestApiParser().parse(parser);
|
||||
|
||||
assertThat(restApi, notNullValue());
|
||||
assertThat(restApi.getName(), equalTo("index"));
|
||||
assertThat(restApi.getMethods().size(), equalTo(2));
|
||||
assertThat(restApi.getMethods().get(0), equalTo("POST"));
|
||||
assertThat(restApi.getMethods().get(1), equalTo("PUT"));
|
||||
assertThat(restApi.getPaths().size(), equalTo(2));
|
||||
assertThat(restApi.getPaths().get(0), equalTo("/{index}/{type}"));
|
||||
assertThat(restApi.getPaths().get(1), equalTo("/{index}/{type}/{id}"));
|
||||
assertThat(restApi.getPathParts().size(), equalTo(3));
|
||||
assertThat(restApi.getPathParts().get(0), equalTo("id"));
|
||||
assertThat(restApi.getPathParts().get(1), equalTo("index"));
|
||||
assertThat(restApi.getPathParts().get(2), equalTo("type"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRestSpecGetTemplateApi() throws Exception {
|
||||
parser = JsonXContent.jsonXContent.createParser(REST_SPEC_GET_TEMPLATE_API);
|
||||
RestApi restApi = new RestApiParser().parse(parser);
|
||||
assertThat(restApi, notNullValue());
|
||||
assertThat(restApi.getName(), equalTo("indices.get_template"));
|
||||
assertThat(restApi.getMethods().size(), equalTo(1));
|
||||
assertThat(restApi.getMethods().get(0), equalTo("GET"));
|
||||
assertThat(restApi.getPaths().size(), equalTo(2));
|
||||
assertThat(restApi.getPaths().get(0), equalTo("/_template"));
|
||||
assertThat(restApi.getPaths().get(1), equalTo("/_template/{name}"));
|
||||
assertThat(restApi.getPathParts().size(), equalTo(1));
|
||||
assertThat(restApi.getPathParts().get(0), equalTo("name"));
|
||||
}
|
||||
|
||||
private static final String REST_SPEC_GET_TEMPLATE_API = "{\n" +
|
||||
" \"indices.get_template\": {\n" +
|
||||
" \"documentation\": \"http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/\",\n" +
|
||||
" \"methods\": [\"GET\"],\n" +
|
||||
" \"url\": {\n" +
|
||||
" \"path\": \"/_template/{name}\",\n" +
|
||||
" \"paths\": [\"/_template\", \"/_template/{name}\"],\n" +
|
||||
" \"parts\": {\n" +
|
||||
" \"name\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"required\" : false,\n" +
|
||||
" \"description\" : \"The name of the template\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"params\": {\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"body\": null\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
private static final String REST_SPEC_INDEX_API = "{\n" +
|
||||
" \"index\": {\n" +
|
||||
" \"documentation\": \"http://elasticsearch.org/guide/reference/api/index_/\",\n" +
|
||||
" \"methods\": [\"POST\", \"PUT\"],\n" +
|
||||
" \"url\": {\n" +
|
||||
" \"path\": \"/{index}/{type}\",\n" +
|
||||
" \"paths\": [\"/{index}/{type}\", \"/{index}/{type}/{id}\"],\n" +
|
||||
" \"parts\": {\n" +
|
||||
" \"id\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"description\" : \"Document ID\"\n" +
|
||||
" },\n" +
|
||||
" \"index\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"required\" : true,\n" +
|
||||
" \"description\" : \"The name of the index\"\n" +
|
||||
" },\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"required\" : true,\n" +
|
||||
" \"description\" : \"The type of the document\"\n" +
|
||||
" }\n" +
|
||||
" } ,\n" +
|
||||
" \"params\": {\n" +
|
||||
" \"consistency\": {\n" +
|
||||
" \"type\" : \"enum\",\n" +
|
||||
" \"options\" : [\"one\", \"quorum\", \"all\"],\n" +
|
||||
" \"description\" : \"Explicit write consistency setting for the operation\"\n" +
|
||||
" },\n" +
|
||||
" \"op_type\": {\n" +
|
||||
" \"type\" : \"enum\",\n" +
|
||||
" \"options\" : [\"index\", \"create\"],\n" +
|
||||
" \"default\" : \"index\",\n" +
|
||||
" \"description\" : \"Explicit operation type\"\n" +
|
||||
" },\n" +
|
||||
" \"parent\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"description\" : \"ID of the parent document\"\n" +
|
||||
" },\n" +
|
||||
" \"percolate\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"description\" : \"Percolator queries to execute while indexing the document\"\n" +
|
||||
" },\n" +
|
||||
" \"refresh\": {\n" +
|
||||
" \"type\" : \"boolean\",\n" +
|
||||
" \"description\" : \"Refresh the index after performing the operation\"\n" +
|
||||
" },\n" +
|
||||
" \"replication\": {\n" +
|
||||
" \"type\" : \"enum\",\n" +
|
||||
" \"options\" : [\"sync\",\"async\"],\n" +
|
||||
" \"default\" : \"sync\",\n" +
|
||||
" \"description\" : \"Specific replication type\"\n" +
|
||||
" },\n" +
|
||||
" \"routing\": {\n" +
|
||||
" \"type\" : \"string\",\n" +
|
||||
" \"description\" : \"Specific routing value\"\n" +
|
||||
" },\n" +
|
||||
" \"timeout\": {\n" +
|
||||
" \"type\" : \"time\",\n" +
|
||||
" \"description\" : \"Explicit operation timeout\"\n" +
|
||||
" },\n" +
|
||||
" \"timestamp\": {\n" +
|
||||
" \"type\" : \"time\",\n" +
|
||||
" \"description\" : \"Explicit timestamp for the document\"\n" +
|
||||
" },\n" +
|
||||
" \"ttl\": {\n" +
|
||||
" \"type\" : \"duration\",\n" +
|
||||
" \"description\" : \"Expiration time for the document\"\n" +
|
||||
" },\n" +
|
||||
" \"version\" : {\n" +
|
||||
" \"type\" : \"number\",\n" +
|
||||
" \"description\" : \"Explicit version number for concurrency control\"\n" +
|
||||
" },\n" +
|
||||
" \"version_type\": {\n" +
|
||||
" \"type\" : \"enum\",\n" +
|
||||
" \"options\" : [\"internal\",\"external\"],\n" +
|
||||
" \"description\" : \"Specific version type\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"body\": {\n" +
|
||||
" \"description\" : \"The document\",\n" +
|
||||
" \"required\" : true\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
}
|
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParseContext;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParser;
|
||||
import org.elasticsearch.test.rest.section.DoSection;
|
||||
import org.elasticsearch.test.rest.section.IsTrueAssertion;
|
||||
import org.elasticsearch.test.rest.section.MatchAssertion;
|
||||
import org.elasticsearch.test.rest.section.RestTestSuite;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class RestTestParserTests extends ElasticsearchTestCase {
|
||||
|
||||
private XContentParser parser;
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
//makes sure that we consumed the whole stream, XContentParser doesn't expose isClosed method
|
||||
//next token can be null even in the middle of the document (e.g. with "---"), but not too many consecutive times
|
||||
assertThat(parser.currentToken(), nullValue());
|
||||
assertThat(parser.nextToken(), nullValue());
|
||||
assertThat(parser.nextToken(), nullValue());
|
||||
parser.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSetupAndSections() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"setup:\n" +
|
||||
" - do:\n" +
|
||||
" indices.create:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get index mapping\":\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
" - match: {test_index.test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_index.test_type.properties.text.analyzer: whitespace}\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get type mapping - pre 1.0\":\n" +
|
||||
"\n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.9 - 999\"\n" +
|
||||
" reason: \"for newer versions the index name is always returned\"\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
" type: test_type\n" +
|
||||
"\n" +
|
||||
" - match: {test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_type.properties.text.analyzer: whitespace}\n"
|
||||
);
|
||||
|
||||
RestTestSuiteParser testParser = new RestTestSuiteParser();
|
||||
RestTestSuite restTestSuite = testParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(restTestSuite, notNullValue());
|
||||
assertThat(restTestSuite.getName(), equalTo("suite"));
|
||||
assertThat(restTestSuite.getSetupSection(), notNullValue());
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().isEmpty(), equalTo(true));
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().size(), equalTo(1));
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().get(0).getApiCallSection().getApi(), equalTo("indices.create"));
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().get(0).getApiCallSection().getParams().size(), equalTo(1));
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().get(0).getApiCallSection().getParams().get("index"), equalTo("test_index"));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().size(), equalTo(2));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(0).getName(), equalTo("Get index mapping"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getSkipSection().isEmpty(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().size(), equalTo(3));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(0), instanceOf(DoSection.class));
|
||||
DoSection doSection = (DoSection) restTestSuite.getTestSections().get(0).getExecutableSections().get(0);
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_mapping"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(1));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("index"), equalTo("test_index"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(1), instanceOf(MatchAssertion.class));
|
||||
MatchAssertion matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(1);
|
||||
assertThat(matchAssertion.getField(), equalTo("test_index.test_type.properties.text.type"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("string"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(2), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(2);
|
||||
assertThat(matchAssertion.getField(), equalTo("test_index.test_type.properties.text.analyzer"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("whitespace"));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(1).getName(), equalTo("Get type mapping - pre 1.0"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().isEmpty(), equalTo(false));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().getReason(), equalTo("for newer versions the index name is always returned"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().getVersion(), equalTo("0.90.9 - 999"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().size(), equalTo(3));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().get(0), instanceOf(DoSection.class));
|
||||
doSection = (DoSection) restTestSuite.getTestSections().get(1).getExecutableSections().get(0);
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_mapping"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(2));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("index"), equalTo("test_index"));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("type"), equalTo("test_type"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(1), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(1).getExecutableSections().get(1);
|
||||
assertThat(matchAssertion.getField(), equalTo("test_type.properties.text.type"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("string"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().get(2), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(1).getExecutableSections().get(2);
|
||||
assertThat(matchAssertion.getField(), equalTo("test_type.properties.text.analyzer"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("whitespace"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSetupAndSectionsSkipLastSection() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"setup:\n" +
|
||||
" - do:\n" +
|
||||
" indices.create:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get index mapping\":\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
" - match: {test_index.test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_index.test_type.properties.text.analyzer: whitespace}\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get type mapping - pre 1.0\":\n" +
|
||||
"\n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.9 - 999\"\n" +
|
||||
" reason: \"for newer versions the index name is always returned\"\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
" type: test_type\n" +
|
||||
"\n" +
|
||||
" - match: {test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_type.properties.text.analyzer: whitespace}\n"
|
||||
);
|
||||
|
||||
RestTestSuiteParser testParser = new RestTestSuiteParser();
|
||||
RestTestSuite restTestSuite = testParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "1.0.0"));
|
||||
|
||||
assertThat(restTestSuite, notNullValue());
|
||||
assertThat(restTestSuite.getName(), equalTo("suite"));
|
||||
assertThat(restTestSuite.getSetupSection(), notNullValue());
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().isEmpty(), equalTo(true));
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().size(), equalTo(1));
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().get(0).getApiCallSection().getApi(), equalTo("indices.create"));
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().get(0).getApiCallSection().getParams().size(), equalTo(1));
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().get(0).getApiCallSection().getParams().get("index"), equalTo("test_index"));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().size(), equalTo(2));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(0).getName(), equalTo("Get index mapping"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getSkipSection().isEmpty(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().size(), equalTo(3));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(0), instanceOf(DoSection.class));
|
||||
DoSection doSection = (DoSection) restTestSuite.getTestSections().get(0).getExecutableSections().get(0);
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_mapping"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(1));
|
||||
assertThat(doSection.getApiCallSection().getParams().get("index"), equalTo("test_index"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(1), instanceOf(MatchAssertion.class));
|
||||
MatchAssertion matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(1);
|
||||
assertThat(matchAssertion.getField(), equalTo("test_index.test_type.properties.text.type"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("string"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(2), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(2);
|
||||
assertThat(matchAssertion.getField(), equalTo("test_index.test_type.properties.text.analyzer"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("whitespace"));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(1).getName(), equalTo("Get type mapping - pre 1.0"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().isEmpty(), equalTo(false));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().getReason(), equalTo("for newer versions the index name is always returned"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().getVersion(), equalTo("0.90.9 - 999"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSetupAndSectionsSkipEntireFile() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"setup:\n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.3 - 0.90.6\"\n" +
|
||||
" reason: \"test skip entire file\"\n" +
|
||||
" - do:\n" +
|
||||
" indices.create:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get index mapping\":\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
" - match: {test_index.test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_index.test_type.properties.text.analyzer: whitespace}\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get type mapping - pre 1.0\":\n" +
|
||||
"\n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.9 - 999\"\n" +
|
||||
" reason: \"for newer versions the index name is always returned\"\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
" type: test_type\n" +
|
||||
"\n" +
|
||||
" - match: {test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_type.properties.text.analyzer: whitespace}\n"
|
||||
);
|
||||
|
||||
RestTestSuiteParser testParser = new RestTestSuiteParser();
|
||||
RestTestSuite restTestSuite = testParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(restTestSuite, notNullValue());
|
||||
assertThat(restTestSuite.getName(), equalTo("suite"));
|
||||
assertThat(restTestSuite.getSetupSection(), notNullValue());
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().isEmpty(), equalTo(false));
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().getVersion(), equalTo("0.90.3 - 0.90.6"));
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().getReason(), equalTo("test skip entire file"));
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().size(), equalTo(0));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSetupAndSectionsSkipEntireFileNoDo() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"setup:\n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.3 - 0.90.6\"\n" +
|
||||
" reason: \"test skip entire file\"\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get index mapping\":\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
"\n" +
|
||||
" - match: {test_index.test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_index.test_type.properties.text.analyzer: whitespace}\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Get type mapping - pre 1.0\":\n" +
|
||||
"\n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.9 - 999\"\n" +
|
||||
" reason: \"for newer versions the index name is always returned\"\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" indices.get_mapping:\n" +
|
||||
" index: test_index\n" +
|
||||
" type: test_type\n" +
|
||||
"\n" +
|
||||
" - match: {test_type.properties.text.type: string}\n" +
|
||||
" - match: {test_type.properties.text.analyzer: whitespace}\n"
|
||||
);
|
||||
|
||||
RestTestSuiteParser testParser = new RestTestSuiteParser();
|
||||
RestTestSuite restTestSuite = testParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(restTestSuite, notNullValue());
|
||||
assertThat(restTestSuite.getName(), equalTo("suite"));
|
||||
assertThat(restTestSuite.getSetupSection(), notNullValue());
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().isEmpty(), equalTo(false));
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().getVersion(), equalTo("0.90.3 - 0.90.6"));
|
||||
assertThat(restTestSuite.getSetupSection().getSkipSection().getReason(), equalTo("test skip entire file"));
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().getDoSections().size(), equalTo(0));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSingleTestSection() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"---\n" +
|
||||
"\"Index with ID\":\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" index:\n" +
|
||||
" index: test-weird-index-中文\n" +
|
||||
" type: weird.type\n" +
|
||||
" id: 1\n" +
|
||||
" body: { foo: bar }\n" +
|
||||
"\n" +
|
||||
" - is_true: ok\n" +
|
||||
" - match: { _index: test-weird-index-中文 }\n" +
|
||||
" - match: { _type: weird.type }\n" +
|
||||
" - match: { _id: \"1\"}\n" +
|
||||
" - match: { _version: 1}\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" get:\n" +
|
||||
" index: test-weird-index-中文\n" +
|
||||
" type: weird.type\n" +
|
||||
" id: 1\n" +
|
||||
"\n" +
|
||||
" - match: { _index: test-weird-index-中文 }\n" +
|
||||
" - match: { _type: weird.type }\n" +
|
||||
" - match: { _id: \"1\"}\n" +
|
||||
" - match: { _version: 1}\n" +
|
||||
" - match: { _source: { foo: bar }}"
|
||||
);
|
||||
|
||||
RestTestSuiteParser testParser = new RestTestSuiteParser();
|
||||
RestTestSuite restTestSuite = testParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(restTestSuite, notNullValue());
|
||||
assertThat(restTestSuite.getName(), equalTo("suite"));
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().isEmpty(), equalTo(true));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().size(), equalTo(1));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(0).getName(), equalTo("Index with ID"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getSkipSection().isEmpty(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().size(), equalTo(12));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(0), instanceOf(DoSection.class));
|
||||
DoSection doSection = (DoSection) restTestSuite.getTestSections().get(0).getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("index"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(1), instanceOf(IsTrueAssertion.class));
|
||||
IsTrueAssertion trueAssertion = (IsTrueAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(1);
|
||||
assertThat(trueAssertion.getField(), equalTo("ok"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(2), instanceOf(MatchAssertion.class));
|
||||
MatchAssertion matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(2);
|
||||
assertThat(matchAssertion.getField(), equalTo("_index"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("test-weird-index-中文"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(3), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(3);
|
||||
assertThat(matchAssertion.getField(), equalTo("_type"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("weird.type"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(4), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(4);
|
||||
assertThat(matchAssertion.getField(), equalTo("_id"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("1"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(5), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(5);
|
||||
assertThat(matchAssertion.getField(), equalTo("_version"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("1"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(6), instanceOf(DoSection.class));
|
||||
doSection = (DoSection) restTestSuite.getTestSections().get(0).getExecutableSections().get(6);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("get"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(7), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(7);
|
||||
assertThat(matchAssertion.getField(), equalTo("_index"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("test-weird-index-中文"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(8), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(8);
|
||||
assertThat(matchAssertion.getField(), equalTo("_type"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("weird.type"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(9), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(9);
|
||||
assertThat(matchAssertion.getField(), equalTo("_id"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("1"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(10), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(10);
|
||||
assertThat(matchAssertion.getField(), equalTo("_version"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("1"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(11), instanceOf(MatchAssertion.class));
|
||||
matchAssertion = (MatchAssertion) restTestSuite.getTestSections().get(0).getExecutableSections().get(11);
|
||||
assertThat(matchAssertion.getField(), equalTo("_source"));
|
||||
assertThat(matchAssertion.getExpectedValue(), instanceOf(Map.class));
|
||||
assertThat(((Map) matchAssertion.getExpectedValue()).get("foo").toString(), equalTo("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestMultipleTestSections() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"---\n" +
|
||||
"\"Missing document (partial doc)\":\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" catch: missing\n" +
|
||||
" update:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: { doc: { foo: bar } }\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" update:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: { doc: { foo: bar } }\n" +
|
||||
" ignore: 404\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\"Missing document (script)\":\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" catch: missing\n" +
|
||||
" update:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body:\n" +
|
||||
" script: \"ctx._source.foo = bar\"\n" +
|
||||
" params: { bar: 'xxx' }\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" update:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" ignore: 404\n" +
|
||||
" body:\n" +
|
||||
" script: \"ctx._source.foo = bar\"\n" +
|
||||
" params: { bar: 'xxx' }\n"
|
||||
);
|
||||
|
||||
RestTestSuiteParser testParser = new RestTestSuiteParser();
|
||||
RestTestSuite restTestSuite = testParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(restTestSuite, notNullValue());
|
||||
assertThat(restTestSuite.getName(), equalTo("suite"));
|
||||
|
||||
assertThat(restTestSuite.getSetupSection().isEmpty(), equalTo(true));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().size(), equalTo(2));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(0).getName(), equalTo("Missing document (partial doc)"));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getSkipSection().isEmpty(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().size(), equalTo(2));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(0), instanceOf(DoSection.class));
|
||||
DoSection doSection = (DoSection) restTestSuite.getTestSections().get(0).getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), equalTo("missing"));
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("update"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(1), instanceOf(DoSection.class));
|
||||
doSection = (DoSection) restTestSuite.getTestSections().get(0).getExecutableSections().get(1);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("update"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(4));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
|
||||
assertThat(restTestSuite.getTestSections().get(1).getName(), equalTo("Missing document (script)"));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getSkipSection().isEmpty(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().size(), equalTo(2));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().get(0), instanceOf(DoSection.class));
|
||||
assertThat(restTestSuite.getTestSections().get(1).getExecutableSections().get(1), instanceOf(DoSection.class));
|
||||
doSection = (DoSection) restTestSuite.getTestSections().get(1).getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), equalTo("missing"));
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("update"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
assertThat(restTestSuite.getTestSections().get(0).getExecutableSections().get(1), instanceOf(DoSection.class));
|
||||
doSection = (DoSection) restTestSuite.getTestSections().get(1).getExecutableSections().get(1);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("update"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(4));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.parser.RestTestParseException;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParseContext;
|
||||
import org.elasticsearch.test.rest.parser.SetSectionParser;
|
||||
import org.elasticsearch.test.rest.section.SetSection;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public class SetSectionParserTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseSetSectionSingleValue() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ _id: id }"
|
||||
);
|
||||
|
||||
SetSectionParser setSectionParser = new SetSectionParser();
|
||||
|
||||
SetSection setSection = setSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(setSection, notNullValue());
|
||||
assertThat(setSection.getStash(), notNullValue());
|
||||
assertThat(setSection.getStash().size(), equalTo(1));
|
||||
assertThat(setSection.getStash().get("_id"), equalTo("id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseSetSectionMultipleValues() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ _id: id, _type: type, _index: index }"
|
||||
);
|
||||
|
||||
SetSectionParser setSectionParser = new SetSectionParser();
|
||||
|
||||
SetSection setSection = setSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(setSection, notNullValue());
|
||||
assertThat(setSection.getStash(), notNullValue());
|
||||
assertThat(setSection.getStash().size(), equalTo(3));
|
||||
assertThat(setSection.getStash().get("_id"), equalTo("id"));
|
||||
assertThat(setSection.getStash().get("_type"), equalTo("type"));
|
||||
assertThat(setSection.getStash().get("_index"), equalTo("index"));
|
||||
}
|
||||
|
||||
@Test(expected = RestTestParseException.class)
|
||||
public void testParseSetSectionNoValues() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"{ }"
|
||||
);
|
||||
|
||||
SetSectionParser setSectionParser = new SetSectionParser();
|
||||
|
||||
setSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParseContext;
|
||||
import org.elasticsearch.test.rest.parser.SetupSectionParser;
|
||||
import org.elasticsearch.test.rest.section.SetupSection;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public class SetupSectionParserTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseSetupSection() throws Exception {
|
||||
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
" - do:\n" +
|
||||
" index1:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: { \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }\n" +
|
||||
" - do:\n" +
|
||||
" index2:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 2\n" +
|
||||
" body: { \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }\n"
|
||||
);
|
||||
|
||||
SetupSectionParser setupSectionParser = new SetupSectionParser();
|
||||
SetupSection setupSection = setupSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(setupSection, notNullValue());
|
||||
assertThat(setupSection.getSkipSection().isEmpty(), equalTo(true));
|
||||
assertThat(setupSection.getDoSections().size(), equalTo(2));
|
||||
assertThat(setupSection.getDoSections().get(0).getApiCallSection().getApi(), equalTo("index1"));
|
||||
assertThat(setupSection.getDoSections().get(1).getApiCallSection().getApi(), equalTo("index2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseSetupAndSkipSectionSkip() throws Exception {
|
||||
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.0 - 0.90.7\"\n" +
|
||||
" reason: \"Update doesn't return metadata fields, waiting for #3259\"\n" +
|
||||
" - do:\n" +
|
||||
" index1:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: { \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }\n" +
|
||||
" - do:\n" +
|
||||
" index2:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 2\n" +
|
||||
" body: { \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }\n"
|
||||
);
|
||||
|
||||
SetupSectionParser setupSectionParser = new SetupSectionParser();
|
||||
SetupSection setupSection = setupSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(setupSection, notNullValue());
|
||||
assertThat(setupSection.getSkipSection().isEmpty(), equalTo(false));
|
||||
assertThat(setupSection.getSkipSection(), notNullValue());
|
||||
assertThat(setupSection.getSkipSection().getVersion(), equalTo("0.90.0 - 0.90.7"));
|
||||
assertThat(setupSection.getSkipSection().getReason(), equalTo("Update doesn't return metadata fields, waiting for #3259"));
|
||||
assertThat(setupSection.getDoSections().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseSetupAndSkipSectionNoSkip() throws Exception {
|
||||
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.0 - 0.90.7\"\n" +
|
||||
" reason: \"Update doesn't return metadata fields, waiting for #3259\"\n" +
|
||||
" - do:\n" +
|
||||
" index1:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 1\n" +
|
||||
" body: { \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }\n" +
|
||||
" - do:\n" +
|
||||
" index2:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 2\n" +
|
||||
" body: { \"include\": { \"field1\": \"v1\", \"field2\": \"v2\" }, \"count\": 1 }\n"
|
||||
);
|
||||
|
||||
SetupSectionParser setupSectionParser = new SetupSectionParser();
|
||||
SetupSection setupSection = setupSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.8"));
|
||||
|
||||
assertThat(setupSection, notNullValue());
|
||||
assertThat(setupSection.getSkipSection().isEmpty(), equalTo(false));
|
||||
assertThat(setupSection.getSkipSection(), notNullValue());
|
||||
assertThat(setupSection.getSkipSection().getVersion(), equalTo("0.90.0 - 0.90.7"));
|
||||
assertThat(setupSection.getSkipSection().getReason(), equalTo("Update doesn't return metadata fields, waiting for #3259"));
|
||||
assertThat(setupSection.getDoSections().size(), equalTo(2));
|
||||
assertThat(setupSection.getDoSections().get(0).getApiCallSection().getApi(), equalTo("index1"));
|
||||
assertThat(setupSection.getDoSections().get(1).getApiCallSection().getApi(), equalTo("index2"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.parser.RestTestParseException;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParseContext;
|
||||
import org.elasticsearch.test.rest.parser.SkipSectionParser;
|
||||
import org.elasticsearch.test.rest.section.SkipSection;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public class SkipSectionParserTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseSkipSection() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"version: \"0 - 0.90.2\"\n" +
|
||||
"reason: Delete ignores the parent param"
|
||||
);
|
||||
|
||||
SkipSectionParser skipSectionParser = new SkipSectionParser();
|
||||
|
||||
SkipSection skipSection = skipSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(skipSection, notNullValue());
|
||||
assertThat(skipSection.getVersion(), equalTo("0 - 0.90.2"));
|
||||
assertThat(skipSection.getReason(), equalTo("Delete ignores the parent param"));
|
||||
}
|
||||
|
||||
@Test(expected = RestTestParseException.class)
|
||||
public void testParseSkipSectionNoReason() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"version: \"0 - 0.90.2\"\n"
|
||||
);
|
||||
|
||||
SkipSectionParser skipSectionParser = new SkipSectionParser();
|
||||
skipSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
}
|
||||
|
||||
@Test(expected = RestTestParseException.class)
|
||||
public void testParseSkipSectionNoVersion() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"reason: Delete ignores the parent param\n"
|
||||
);
|
||||
|
||||
SkipSectionParser skipSectionParser = new SkipSectionParser();
|
||||
skipSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSectionParser;
|
||||
import org.elasticsearch.test.rest.parser.RestTestSuiteParseContext;
|
||||
import org.elasticsearch.test.rest.section.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class TestSectionParserTests extends AbstractParserTests {
|
||||
|
||||
@Test
|
||||
public void testParseTestSectionWithDoSection() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"\"First test section\": \n" +
|
||||
" - do :\n" +
|
||||
" catch: missing\n" +
|
||||
" indices.get_warmer:\n" +
|
||||
" index: test_index\n" +
|
||||
" name: test_warmer"
|
||||
);
|
||||
|
||||
RestTestSectionParser testSectionParser = new RestTestSectionParser();
|
||||
TestSection testSection = testSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(testSection, notNullValue());
|
||||
assertThat(testSection.getName(), equalTo("First test section"));
|
||||
assertThat(testSection.getSkipSection(), equalTo(SkipSection.EMPTY));
|
||||
assertThat(testSection.getExecutableSections().size(), equalTo(1));
|
||||
DoSection doSection = (DoSection)testSection.getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), equalTo("missing"));
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_warmer"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(2));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSectionWithDoSetAndSkipSectionsSkip() throws Exception {
|
||||
String yaml =
|
||||
"\"First test section\": \n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.0 - 0.90.7\"\n" +
|
||||
" reason: \"Update doesn't return metadata fields, waiting for #3259\"\n" +
|
||||
" - do :\n" +
|
||||
" catch: missing\n" +
|
||||
" indices.get_warmer:\n" +
|
||||
" index: test_index\n" +
|
||||
" name: test_warmer\n" +
|
||||
" - set: {_scroll_id: scroll_id}";
|
||||
|
||||
|
||||
RestTestSectionParser testSectionParser = new RestTestSectionParser();
|
||||
parser = YamlXContent.yamlXContent.createParser(yaml);
|
||||
TestSection testSection = testSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.7"));
|
||||
|
||||
assertThat(testSection, notNullValue());
|
||||
assertThat(testSection.getName(), equalTo("First test section"));
|
||||
assertThat(testSection.getSkipSection(), notNullValue());
|
||||
assertThat(testSection.getSkipSection().getVersion(), equalTo("0.90.0 - 0.90.7"));
|
||||
assertThat(testSection.getSkipSection().getReason(), equalTo("Update doesn't return metadata fields, waiting for #3259"));
|
||||
//skip parsing when needed
|
||||
assertThat(testSection.getExecutableSections().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSectionWithDoSetAndSkipSectionsNoSkip() throws Exception {
|
||||
String yaml =
|
||||
"\"First test section\": \n" +
|
||||
" - skip:\n" +
|
||||
" version: \"0.90.0 - 0.90.7\"\n" +
|
||||
" reason: \"Update doesn't return metadata fields, waiting for #3259\"\n" +
|
||||
" - do :\n" +
|
||||
" catch: missing\n" +
|
||||
" indices.get_warmer:\n" +
|
||||
" index: test_index\n" +
|
||||
" name: test_warmer\n" +
|
||||
" - set: {_scroll_id: scroll_id}";
|
||||
|
||||
|
||||
RestTestSectionParser testSectionParser = new RestTestSectionParser();
|
||||
parser = YamlXContent.yamlXContent.createParser(yaml);
|
||||
TestSection testSection = testSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.8"));
|
||||
|
||||
assertThat(testSection, notNullValue());
|
||||
assertThat(testSection.getName(), equalTo("First test section"));
|
||||
assertThat(testSection.getSkipSection(), notNullValue());
|
||||
assertThat(testSection.getSkipSection().getVersion(), equalTo("0.90.0 - 0.90.7"));
|
||||
assertThat(testSection.getSkipSection().getReason(), equalTo("Update doesn't return metadata fields, waiting for #3259"));
|
||||
assertThat(testSection.getExecutableSections().size(), equalTo(2));
|
||||
DoSection doSection = (DoSection)testSection.getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), equalTo("missing"));
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("indices.get_warmer"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(2));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
SetSection setSection = (SetSection) testSection.getExecutableSections().get(1);
|
||||
assertThat(setSection.getStash().size(), equalTo(1));
|
||||
assertThat(setSection.getStash().get("_scroll_id"), equalTo("scroll_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSectionWithMultipleDoSections() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"\"Basic\":\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" index:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 中文\n" +
|
||||
" body: { \"foo\": \"Hello: 中文\" }\n" +
|
||||
" - do:\n" +
|
||||
" get:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 中文"
|
||||
);
|
||||
|
||||
RestTestSectionParser testSectionParser = new RestTestSectionParser();
|
||||
TestSection testSection = testSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(testSection, notNullValue());
|
||||
assertThat(testSection.getName(), equalTo("Basic"));
|
||||
assertThat(testSection.getSkipSection(), equalTo(SkipSection.EMPTY));
|
||||
assertThat(testSection.getExecutableSections().size(), equalTo(2));
|
||||
DoSection doSection = (DoSection)testSection.getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("index"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
doSection = (DoSection)testSection.getExecutableSections().get(1);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("get"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTestSectionWithDoSectionsAndAssertions() throws Exception {
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"\"Basic\":\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" index:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 中文\n" +
|
||||
" body: { \"foo\": \"Hello: 中文\" }\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" get:\n" +
|
||||
" index: test_1\n" +
|
||||
" type: test\n" +
|
||||
" id: 中文\n" +
|
||||
"\n" +
|
||||
" - match: { _index: test_1 }\n" +
|
||||
" - is_true: _source\n" +
|
||||
" - match: { _source: { foo: \"Hello: 中文\" } }\n" +
|
||||
"\n" +
|
||||
" - do:\n" +
|
||||
" get:\n" +
|
||||
" index: test_1\n" +
|
||||
" id: 中文\n" +
|
||||
"\n" +
|
||||
" - length: { _index: 6 }\n" +
|
||||
" - is_false: whatever\n" +
|
||||
" - gt: { size: 5 }\n" +
|
||||
" - lt: { size: 10 }"
|
||||
);
|
||||
|
||||
RestTestSectionParser testSectionParser = new RestTestSectionParser();
|
||||
TestSection testSection = testSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
|
||||
assertThat(testSection, notNullValue());
|
||||
assertThat(testSection.getName(), equalTo("Basic"));
|
||||
assertThat(testSection.getSkipSection(), equalTo(SkipSection.EMPTY));
|
||||
assertThat(testSection.getExecutableSections().size(), equalTo(10));
|
||||
|
||||
DoSection doSection = (DoSection)testSection.getExecutableSections().get(0);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("index"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(true));
|
||||
|
||||
doSection = (DoSection)testSection.getExecutableSections().get(1);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("get"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(3));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
|
||||
MatchAssertion matchAssertion = (MatchAssertion)testSection.getExecutableSections().get(2);
|
||||
assertThat(matchAssertion.getField(), equalTo("_index"));
|
||||
assertThat(matchAssertion.getExpectedValue().toString(), equalTo("test_1"));
|
||||
|
||||
IsTrueAssertion trueAssertion = (IsTrueAssertion)testSection.getExecutableSections().get(3);
|
||||
assertThat(trueAssertion.getField(), equalTo("_source"));
|
||||
|
||||
matchAssertion = (MatchAssertion)testSection.getExecutableSections().get(4);
|
||||
assertThat(matchAssertion.getField(), equalTo("_source"));
|
||||
assertThat(matchAssertion.getExpectedValue(), instanceOf(Map.class));
|
||||
Map map = (Map) matchAssertion.getExpectedValue();
|
||||
assertThat(map.size(), equalTo(1));
|
||||
assertThat(map.get("foo").toString(), equalTo("Hello: 中文"));
|
||||
|
||||
doSection = (DoSection)testSection.getExecutableSections().get(5);
|
||||
assertThat(doSection.getCatch(), nullValue());
|
||||
assertThat(doSection.getApiCallSection(), notNullValue());
|
||||
assertThat(doSection.getApiCallSection().getApi(), equalTo("get"));
|
||||
assertThat(doSection.getApiCallSection().getParams().size(), equalTo(2));
|
||||
assertThat(doSection.getApiCallSection().hasBody(), equalTo(false));
|
||||
|
||||
LengthAssertion lengthAssertion = (LengthAssertion) testSection.getExecutableSections().get(6);
|
||||
assertThat(lengthAssertion.getField(), equalTo("_index"));
|
||||
assertThat(lengthAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) lengthAssertion.getExpectedValue(), equalTo(6));
|
||||
|
||||
IsFalseAssertion falseAssertion = (IsFalseAssertion)testSection.getExecutableSections().get(7);
|
||||
assertThat(falseAssertion.getField(), equalTo("whatever"));
|
||||
|
||||
GreaterThanAssertion greaterThanAssertion = (GreaterThanAssertion) testSection.getExecutableSections().get(8);
|
||||
assertThat(greaterThanAssertion.getField(), equalTo("size"));
|
||||
assertThat(greaterThanAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) greaterThanAssertion.getExpectedValue(), equalTo(5));
|
||||
|
||||
LessThanAssertion lessThanAssertion = (LessThanAssertion) testSection.getExecutableSections().get(9);
|
||||
assertThat(lessThanAssertion.getField(), equalTo("size"));
|
||||
assertThat(lessThanAssertion.getExpectedValue(), instanceOf(Integer.class));
|
||||
assertThat((Integer) lessThanAssertion.getExpectedValue(), equalTo(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallSection() throws Exception {
|
||||
|
||||
parser = YamlXContent.yamlXContent.createParser(
|
||||
"\"node_info test\":\n" +
|
||||
" - do:\n" +
|
||||
" cluster.node_info: {}\n" +
|
||||
" \n" +
|
||||
" - is_true: ok\n" +
|
||||
" - is_true: nodes\n" +
|
||||
" - is_true: cluster_name\n");
|
||||
RestTestSectionParser testSectionParser = new RestTestSectionParser();
|
||||
TestSection testSection = testSectionParser.parse(new RestTestSuiteParseContext("api", "suite", parser, "0.90.5"));
|
||||
assertThat(testSection, notNullValue());
|
||||
assertThat(testSection.getName(), equalTo("node_info test"));
|
||||
assertThat(testSection.getExecutableSections().size(), equalTo(4));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch 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.elasticsearch.test.rest.test;
|
||||
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.elasticsearch.test.rest.support.VersionUtils.parseVersionNumber;
|
||||
import static org.elasticsearch.test.rest.support.VersionUtils.skipCurrentVersion;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class VersionUtilsTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testParseVersionNumber() {
|
||||
|
||||
int[] versionNumber = parseVersionNumber("0.90.6");
|
||||
assertThat(versionNumber.length, equalTo(3));
|
||||
assertThat(versionNumber[0], equalTo(0));
|
||||
assertThat(versionNumber[1], equalTo(90));
|
||||
assertThat(versionNumber[2], equalTo(6));
|
||||
|
||||
versionNumber = parseVersionNumber("0.90.999");
|
||||
assertThat(versionNumber.length, equalTo(3));
|
||||
assertThat(versionNumber[0], equalTo(0));
|
||||
assertThat(versionNumber[1], equalTo(90));
|
||||
assertThat(versionNumber[2], equalTo(999));
|
||||
|
||||
versionNumber = parseVersionNumber("0.20.11");
|
||||
assertThat(versionNumber.length, equalTo(3));
|
||||
assertThat(versionNumber[0], equalTo(0));
|
||||
assertThat(versionNumber[1], equalTo(20));
|
||||
assertThat(versionNumber[2], equalTo(11));
|
||||
|
||||
versionNumber = parseVersionNumber("1.0.0.Beta1");
|
||||
assertThat(versionNumber.length, equalTo(3));
|
||||
assertThat(versionNumber[0], equalTo(1));
|
||||
assertThat(versionNumber[1], equalTo(0));
|
||||
assertThat(versionNumber[2], equalTo(0));
|
||||
|
||||
versionNumber = parseVersionNumber("1.0.0.RC1");
|
||||
assertThat(versionNumber.length, equalTo(3));
|
||||
assertThat(versionNumber[0], equalTo(1));
|
||||
assertThat(versionNumber[1], equalTo(0));
|
||||
assertThat(versionNumber[2], equalTo(0));
|
||||
|
||||
versionNumber = parseVersionNumber("1.0.0");
|
||||
assertThat(versionNumber.length, equalTo(3));
|
||||
assertThat(versionNumber[0], equalTo(1));
|
||||
assertThat(versionNumber[1], equalTo(0));
|
||||
assertThat(versionNumber[2], equalTo(0));
|
||||
|
||||
versionNumber = parseVersionNumber("1.0");
|
||||
assertThat(versionNumber.length, equalTo(2));
|
||||
assertThat(versionNumber[0], equalTo(1));
|
||||
assertThat(versionNumber[1], equalTo(0));
|
||||
|
||||
versionNumber = parseVersionNumber("999");
|
||||
assertThat(versionNumber.length, equalTo(1));
|
||||
assertThat(versionNumber[0], equalTo(999));
|
||||
|
||||
versionNumber = parseVersionNumber("0");
|
||||
assertThat(versionNumber.length, equalTo(1));
|
||||
assertThat(versionNumber[0], equalTo(0));
|
||||
|
||||
try {
|
||||
parseVersionNumber("1.0.Beta1");
|
||||
fail("parseVersionNumber should have thrown an error");
|
||||
} catch(IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("version is not a number"));
|
||||
assertThat(e.getCause(), instanceOf(NumberFormatException.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipCurrentVersion() {
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "0.90.2"), equalTo(true));
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "0.90.3"), equalTo(true));
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "0.90.6"), equalTo(true));
|
||||
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "0.20.10"), equalTo(false));
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "0.90.1"), equalTo(false));
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "0.90.7"), equalTo(false));
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.6", "1.0.0"), equalTo(false));
|
||||
|
||||
assertThat(skipCurrentVersion(" 0.90.2 - 0.90.999 ", "0.90.15"), equalTo(true));
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.999", "1.0.0"), equalTo(false));
|
||||
|
||||
assertThat(skipCurrentVersion("0 - 999", "0.90.15"), equalTo(true));
|
||||
assertThat(skipCurrentVersion("0 - 999", "0.20.1"), equalTo(true));
|
||||
assertThat(skipCurrentVersion("0 - 999", "1.0.0"), equalTo(true));
|
||||
|
||||
assertThat(skipCurrentVersion("0.90.9 - 999", "1.0.0"), equalTo(true));
|
||||
assertThat(skipCurrentVersion("0.90.9 - 999", "0.90.8"), equalTo(false));
|
||||
|
||||
try {
|
||||
assertThat(skipCurrentVersion("0.90.2 - 0.90.999 - 1.0.0", "1.0.0"), equalTo(false));
|
||||
fail("skipCurrentVersion should have thrown an error");
|
||||
} catch(IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("too many skip versions found"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
es.logger.level=INFO
|
||||
log4j.rootLogger=${es.logger.level}, out
|
||||
|
||||
log4j.logger.org.apache.http=INFO, out
|
||||
log4j.additivity.org.apache.http=false
|
||||
|
||||
log4j.appender.out=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.out.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.out.layout.conversionPattern=[%d{ISO8601}][%-5p][%-25c] %m%n
|
||||
|
|
Loading…
Reference in New Issue