Skip to content

Commit

Permalink
[TEST] Add basic Backwards Compatibility Tests
Browse files Browse the repository at this point in the history
This commit add a basic infrastructure as well as primitive tests
to ensure version backwards compatibility between the current
development trunk and an arbitrary previous version. The compatibility
tests are simple unit tests derived from a base class that starts
and manages nodes from a provided elasticsearch release package.

Use the following commandline executes all backwards compatiblity tests
in isolation:

```
mvn test -Dtests.bwc=true -Dtests.bwc.version=1.2.1 -Dtests.class=org.elasticsearch.bwcompat.*
```

These tests run basic checks like rolling upgrades and
routing/searching/get etc. against the specified version. The version
must be present in the `./backwards` folder as
`./backwards/elasticsearch-x.y.z`
  • Loading branch information
s1monw committed Jun 16, 2014
1 parent 93b56eb commit 4dfa822
Show file tree
Hide file tree
Showing 17 changed files with 1,518 additions and 447 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ target/
docs/html/
docs/build.log
/tmp/
backwards/

## eclipse ignores (use 'mvn eclipse:eclipse' to build eclipse projects)
## The only configuration files which are not ignored are certain files in
Expand Down
20 changes: 20 additions & 0 deletions TESTING.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,24 @@ even if tests are passing.
mvn test -Dtests.output=always
------------------------------

== Backwards Compatibility Tests

Running backwards compatibility tests is disabled by default since it
requires a release version of elasticsearch to be present on the test system.
To run backwards compatibiilty tests untar or unzip a release and run the tests
with the following command:

---------------------------------------------------------------------------
mvn test -Dtests.bwc=true -Dtests.bwc.version=x.y.z -Dtests.bwc.path=/path/to/elasticsearch
---------------------------------------------------------------------------

If the elasticsearch release is placed under `./backwards/elasticsearch-x.y.z` the path
can be omitted:

---------------------------------------------------------------------------
mvn test -Dtests.bwc=true -Dtests.bwc.version=x.y.z
---------------------------------------------------------------------------

== Testing the REST layer

The available integration tests make use of the java API to communicate with
Expand Down Expand Up @@ -213,3 +231,5 @@ cluster by specifying the `tests.cluster` property, which if present needs to co
comma separated list of nodes to connect to (e.g. localhost:9300). A transport client will
be created based on that and used for all the before|after test operations, and to extract
the http addresses of the nodes so that REST requests can be sent to them.


4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<tests.shuffle>true</tests.shuffle>
<tests.output>onerror</tests.output>
<tests.client.ratio></tests.client.ratio>
<tests.bwc.path>${project.basedir}/backwards</tests.bwc.path>
<es.logger.level>INFO</es.logger.level>
<tests.heap.size>512m</tests.heap.size>
<tests.topn>5</tests.topn>
Expand Down Expand Up @@ -468,6 +469,9 @@
<systemProperties>
<java.io.tmpdir>.</java.io.tmpdir> <!-- we use '.' since this is different per JVM-->
<!-- RandomizedTesting library system properties -->
<tests.bwc>${tests.bwc}</tests.bwc>
<tests.bwc.path>${tests.bwc.path}</tests.bwc.path>
<tests.bwc.version>${tests.bwc.version}</tests.bwc.version>
<tests.jvm.argline>${tests.jvm.argline}</tests.jvm.argline>
<tests.processors>${tests.processors}</tests.processors>
<tests.appendseed>${tests.appendseed}</tests.appendseed>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class DiscoveryModule extends AbstractModule implements SpawnModules {

private final Settings settings;

public static final String DISCOVERY_TYPE_KEY = "discovery.type";

public DiscoveryModule(Settings settings) {
this.settings = settings;
}
Expand All @@ -48,7 +50,7 @@ public Iterable<? extends Module> spawnModules() {
} else {
defaultDiscoveryModule = ZenDiscoveryModule.class;
}
return ImmutableList.of(Modules.createModule(settings.getAsClass("discovery.type", defaultDiscoveryModule, "org.elasticsearch.discovery.", "DiscoveryModule"), settings));
return ImmutableList.of(Modules.createModule(settings.getAsClass(DISCOVERY_TYPE_KEY, defaultDiscoveryModule, "org.elasticsearch.discovery.", "DiscoveryModule"), settings));
}

@Override
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/org/apache/lucene/util/AbstractRandomizedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,32 @@
// NOTE: this class is in o.a.lucene.util since it uses some classes that are related
// to the test framework that didn't make sense to copy but are package private access
public abstract class AbstractRandomizedTest extends RandomizedTest {


/**
* Annotation for backwards compat tests
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@TestGroup(enabled = false, sysProperty = TESTS_BACKWARDS_COMPATIBILITY)
public @interface BackwardsCompatibilityTest {
}

/**
* Key used to set the path for the elasticsearch executable used to run backwards compatibility tests from
* via the commandline -D{@value #TESTS_BACKWARDS_COMPATIBILITY_PATH}
*/
public static final String TESTS_BACKWARDS_COMPATIBILITY = "tests.bwc";

public static final String TESTS_BACKWARDS_COMPATIBILITY_VERSION = "tests.bwc.version";

/**
* Key used to set the path for the elasticsearch executable used to run backwards compatibility tests from
* via the commandline -D{@value #TESTS_BACKWARDS_COMPATIBILITY_PATH}
*/
public static final String TESTS_BACKWARDS_COMPATIBILITY_PATH = "tests.bwc.path";

/**
* Annotation for integration tests
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Licensed to Elasticsearch 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.bwcompat;

import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
import org.elasticsearch.indices.analysis.PreBuiltAnalyzers;
import org.elasticsearch.test.ElasticsearchBackwardsCompatIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;

import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.equalTo;

/**
*/
@ElasticsearchIntegrationTest.ClusterScope(numDataNodes = 0, scope = ElasticsearchIntegrationTest.Scope.SUITE, numClientNodes = 0, transportClientRatio = 0.0)
public class BasicAnalysisBackwardCompatibilityTests extends ElasticsearchBackwardsCompatIntegrationTest {

/**
* Simple upgrade test for analyzers to make sure they analyze to the same tokens after upgrade
* TODO we need this for random tokenizers / tokenfilters as well
*/
@Test
public void testAnalyzerTokensAfterUpgrade() throws IOException, ExecutionException, InterruptedException {
int numFields = randomIntBetween(PreBuiltAnalyzers.values().length, PreBuiltAnalyzers.values().length * 10);
StringBuilder builder = new StringBuilder();
String[] fields = new String[numFields * 2];
int fieldId = 0;
for (int i = 0; i < fields.length; i++) {
fields[i++] = "field_" + fieldId++;
String analyzer = RandomPicks.randomFrom(getRandom(), PreBuiltAnalyzers.values()).name().toLowerCase(Locale.ROOT);
fields[i] = "type=string,analyzer=" + analyzer;
}
assertAcked(prepareCreate("test")
.addMapping("type", fields)
.setSettings(indexSettings()));
ensureYellow();
InputOutput[] inout = new InputOutput[numFields];
for (int i = 0; i < numFields; i++) {
String input = randomRealisticUnicodeOfCodepointLengthBetween(1, 100);
AnalyzeResponse test = client().admin().indices().prepareAnalyze("test", input).setField("field_" + i).get();
inout[i] = new InputOutput(test, input, "field_" + i);
}

logClusterState();
boolean upgraded;
do {
logClusterState();
upgraded = backwardsCluster().upgradeOneNode();
ensureYellow();
} while (upgraded);

for (int i = 0; i < inout.length; i++) {
InputOutput inputOutput = inout[i];
AnalyzeResponse test = client().admin().indices().prepareAnalyze("test", inputOutput.input).setField(inputOutput.field).get();
List<AnalyzeResponse.AnalyzeToken> tokens = test.getTokens();
List<AnalyzeResponse.AnalyzeToken> expectedTokens = inputOutput.response.getTokens();
assertThat("size mismatch field: " + fields[i*2] + " analyzer: " + fields[i*2 + 1] + " input: " + inputOutput.input, expectedTokens.size(), equalTo(tokens.size()));
for (int j = 0; j < tokens.size(); j++) {
String msg = "failed for term: " + expectedTokens.get(j).getTerm() + " field: " + fields[i*2] + " analyzer: " + fields[i*2 + 1] + " input: " + inputOutput.input;
assertThat(msg, expectedTokens.get(j).getTerm(), equalTo(tokens.get(j).getTerm()));
assertThat(msg, expectedTokens.get(j).getPosition(), equalTo(tokens.get(j).getPosition()));
assertThat(msg, expectedTokens.get(j).getStartOffset(), equalTo(tokens.get(j).getStartOffset()));
assertThat(msg, expectedTokens.get(j).getEndOffset(), equalTo(tokens.get(j).getEndOffset()));
assertThat(msg, expectedTokens.get(j).getType(), equalTo(tokens.get(j).getType()));
}
}
}

private static final class InputOutput {
final AnalyzeResponse response;
final String input;
final String field;

public InputOutput(AnalyzeResponse response, String input, String field) {
this.response = response;
this.input = input;
this.field = field;
}


}
}
Loading

0 comments on commit 4dfa822

Please sign in to comment.