Merge branch 'master' into feature/query-refactoring

Conflicts:
	core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringParser.java
This commit is contained in:
javanna 2015-08-11 13:24:17 +02:00 committed by Luca Cavanna
commit e2181990c4
18 changed files with 565 additions and 78 deletions

View File

@ -43,7 +43,10 @@ import java.util.*;
*/
public class ElasticsearchException extends RuntimeException implements ToXContent {
public static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.skip_cause";
public static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.cause.skip";
public static final String REST_EXCEPTION_SKIP_STACK_TRACE = "rest.exception.stacktrace.skip";
private static final boolean REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT = false;
private static final boolean REST_EXCEPTION_SKIP_CAUSE_DEFAULT = false;
private static final String INDEX_HEADER_KEY = "es.index";
private static final String SHARD_HEADER_KEY = "es.shard";
private static final String RESOURCE_HEADER_TYPE_KEY = "es.resource.type";
@ -270,6 +273,9 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
}
innerToXContent(builder, params);
renderHeader(builder, params);
if (params.paramAsBoolean(REST_EXCEPTION_SKIP_STACK_TRACE, REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) == false) {
builder.field("stack_trace", ExceptionsHelper.stackTrace(this));
}
}
return builder;
}
@ -286,7 +292,7 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
*/
protected final void causeToXContent(XContentBuilder builder, Params params) throws IOException {
final Throwable cause = getCause();
if (cause != null && params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, false) == false) {
if (cause != null && params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, REST_EXCEPTION_SKIP_CAUSE_DEFAULT) == false) {
builder.field("caused_by");
builder.startObject();
toXContent(builder, params, cause);
@ -342,6 +348,9 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
toXContent(builder, params, ex.getCause());
builder.endObject();
}
if (params.paramAsBoolean(REST_EXCEPTION_SKIP_STACK_TRACE, REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) == false) {
builder.field("stack_trace", ExceptionsHelper.stackTrace(ex));
}
}
}

View File

@ -263,10 +263,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
@Override
protected Query doToQuery(QueryShardContext context) throws IOException {
// Use the default field (_all) if no fields specified
// Use the default field if no fields specified
if (fieldsAndWeights.isEmpty()) {
String field = context.defaultField();
fieldsAndWeights.put(field, 1.0F);
fieldsAndWeights.put(context.defaultField(), AbstractQueryBuilder.DEFAULT_BOOST);
}
// field names in builder can have wildcards etc, need to resolve them here

View File

@ -20,7 +20,9 @@
package org.elasticsearch.index.query;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
@ -59,20 +61,26 @@ import java.util.Map;
*/
public class SimpleQueryStringParser extends BaseQueryParser {
public static final String NAME = "simple_query_string";
@Inject
public SimpleQueryStringParser() {
}
@Override
public String[] names() {
return new String[]{SimpleQueryStringBuilder.NAME, Strings.toCamelCase(SimpleQueryStringBuilder.NAME)};
}
@Override
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
public SimpleQueryStringBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
XContentParser parser = parseContext.parser();
String currentFieldName = null;
String queryBody = null;
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
String queryName = null;
String field = null;
String minimumShouldMatch = null;
Map<String, Float> fieldsAndWeights = new HashMap<>();
Operator defaultOperator = null;
@ -108,9 +116,7 @@ public class SimpleQueryStringParser extends BaseQueryParser {
fieldsAndWeights.put(fField, fBoost);
}
} else {
throw new QueryParsingException(parseContext,
"[" + SimpleQueryStringBuilder.NAME + "] query does not support [" + currentFieldName
+ "]");
throw new QueryParsingException(parseContext, "[" + NAME + "] query does not support [" + currentFieldName + "]");
}
} else if (token.isValue()) {
if ("query".equals(currentFieldName)) {
@ -119,8 +125,6 @@ public class SimpleQueryStringParser extends BaseQueryParser {
boost = parser.floatValue();
} else if ("analyzer".equals(currentFieldName)) {
analyzerName = parser.text();
} else if ("field".equals(currentFieldName)) {
field = parser.text();
} else if ("default_operator".equals(currentFieldName) || "defaultOperator".equals(currentFieldName)) {
defaultOperator = Operator.fromString(parser.text());
} else if ("flags".equals(currentFieldName)) {
@ -158,11 +162,6 @@ public class SimpleQueryStringParser extends BaseQueryParser {
throw new QueryParsingException(parseContext, "[" + SimpleQueryStringBuilder.NAME + "] query text missing");
}
// Support specifying only a field instead of a map
if (field == null) {
field = currentFieldName;
}
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(queryBody);
qb.boost(boost).fields(fieldsAndWeights).analyzer(analyzerName).queryName(queryName).minimumShouldMatch(minimumShouldMatch);
qb.flags(flags).defaultOperator(defaultOperator).locale(locale).lowercaseExpandedTerms(lowercaseExpandedTerms);

View File

@ -53,10 +53,12 @@ import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.NoSuchFileException;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
public class ESExceptionTests extends ESTestCase {
private static final ToXContent.Params PARAMS = new ToXContent.MapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true"));
@Test
public void testStatus() {
@ -145,7 +147,7 @@ public class ESExceptionTests extends ESTestCase {
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1});
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
ex.toXContent(builder, PARAMS);
builder.endObject();
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\"}}]}";
assertEquals(expected, builder.string());
@ -160,7 +162,7 @@ public class ESExceptionTests extends ESTestCase {
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1, failure2});
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
ex.toXContent(builder, PARAMS);
builder.endObject();
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\"}},{\"shard\":1,\"index\":\"foo1\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo1\"}}]}";
assertEquals(expected, builder.string());
@ -185,7 +187,7 @@ public class ESExceptionTests extends ESTestCase {
ElasticsearchException ex = new SearchParseException(new TestSearchContext(), "foo", new XContentLocation(1,0));
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
ex.toXContent(builder, PARAMS);
builder.endObject();
String expected = "{\"type\":\"search_parse_exception\",\"reason\":\"foo\",\"line\":1,\"col\":0}";
@ -195,7 +197,7 @@ public class ESExceptionTests extends ESTestCase {
ElasticsearchException ex = new ElasticsearchException("foo", new ElasticsearchException("bar", new IllegalArgumentException("index is closed", new RuntimeException("foobar"))));
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
ex.toXContent(builder, PARAMS);
builder.endObject();
String expected = "{\"type\":\"exception\",\"reason\":\"foo\",\"caused_by\":{\"type\":\"exception\",\"reason\":\"bar\",\"caused_by\":{\"type\":\"illegal_argument_exception\",\"reason\":\"index is closed\",\"caused_by\":{\"type\":\"runtime_exception\",\"reason\":\"foobar\"}}}}";
@ -210,7 +212,7 @@ public class ESExceptionTests extends ESTestCase {
}
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
ElasticsearchException.toXContent(builder, PARAMS, ex);
builder.endObject();
String expected = "{\"type\":\"file_not_found_exception\",\"reason\":\"foo not found\"}";
@ -221,7 +223,7 @@ public class ESExceptionTests extends ESTestCase {
QueryParsingException ex = new TestQueryParsingException(new Index("foo"), 1, 2, "foobar", null);
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
ElasticsearchException.toXContent(builder, PARAMS, ex);
builder.endObject();
String expected = "{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\",\"line\":1,\"col\":2}";
assertEquals(expected, builder.string());
@ -231,13 +233,13 @@ public class ESExceptionTests extends ESTestCase {
ElasticsearchException ex = new RemoteTransportException("foobar", new FileNotFoundException("foo not found"));
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
ElasticsearchException.toXContent(builder, PARAMS, ex);
builder.endObject();
XContentBuilder otherBuilder = XContentFactory.jsonBuilder();
otherBuilder.startObject();
ex.toXContent(otherBuilder, ToXContent.EMPTY_PARAMS);
ex.toXContent(otherBuilder, PARAMS);
otherBuilder.endObject();
assertEquals(otherBuilder.string(), builder.string());
assertEquals("{\"type\":\"file_not_found_exception\",\"reason\":\"foo not found\"}", builder.string());
@ -249,7 +251,7 @@ public class ESExceptionTests extends ESTestCase {
ex.addHeader("test_multi", "some value", "another value");
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
ElasticsearchException.toXContent(builder, PARAMS, ex);
builder.endObject();
assertThat(builder.string(), Matchers.anyOf( // iteration order depends on platform
equalTo("{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\",\"line\":1,\"col\":2,\"header\":{\"test_multi\":[\"some value\",\"another value\"],\"test\":\"some value\"}}"),

View File

@ -93,6 +93,7 @@ import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@ -540,7 +541,7 @@ public class ExceptionSerializationTests extends ESTestCase {
try {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
x.toXContent(builder, ToXContent.EMPTY_PARAMS);
x.toXContent(builder, new ToXContent.MapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true")));
builder.endObject();
return builder.string();
} catch (IOException e) {

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.search;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.test.StreamsUtils;
import org.elasticsearch.common.xcontent.ToXContent;
@ -28,6 +29,7 @@ import org.elasticsearch.test.ESTestCase;
import org.junit.Test;
import java.io.IOException;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
@ -123,7 +125,7 @@ public class MultiSearchRequestTests extends ESTestCase {
public void testResponseErrorToXContent() throws IOException {
MultiSearchResponse response = new MultiSearchResponse(new MultiSearchResponse.Item[]{new MultiSearchResponse.Item(null, new IllegalStateException("foobar")), new MultiSearchResponse.Item(null, new IllegalStateException("baaaaaazzzz"))});
XContentBuilder builder = XContentFactory.jsonBuilder();
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
response.toXContent(builder, new ToXContent.MapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true")));
assertEquals("\"responses\"[{\"error\":{\"root_cause\":[{\"type\":\"illegal_state_exception\",\"reason\":\"foobar\"}],\"type\":\"illegal_state_exception\",\"reason\":\"foobar\"}},{\"error\":{\"root_cause\":[{\"type\":\"illegal_state_exception\",\"reason\":\"baaaaaazzzz\"}],\"type\":\"illegal_state_exception\",\"reason\":\"baaaaaazzzz\"}}]",
builder.string());
}

View File

@ -21,7 +21,6 @@ package org.elasticsearch.index.query;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.index.*;
import org.apache.lucene.index.memory.MemoryIndex;
@ -74,10 +73,10 @@ import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import static org.elasticsearch.test.StreamsUtils.copyToBytesFromClasspath;
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.elasticsearch.test.StreamsUtils.copyToBytesFromClasspath;
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
import static org.hamcrest.Matchers.*;
@ -2284,14 +2283,6 @@ public class SimpleIndexQueryParserTests extends ESSingleNodeTestCase {
}
}
@Test
public void testSimpleQueryString() throws Exception {
IndexQueryParserService queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/simple-query-string.json");
Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(BooleanQuery.class));
}
@Test
public void testMatchWithFuzzyTranspositions() throws Exception {
IndexQueryParserService queryParser = queryParser();
@ -2374,7 +2365,7 @@ public class SimpleIndexQueryParserTests extends ESSingleNodeTestCase {
IndexQueryParserService queryParser = queryParser();
String query = jsonBuilder().startObject().startObject("function_score")
.startArray("functions")
.startObject().field("weight", 2).field("boost_factor",2).endObject()
.startObject().field("weight", 2).field("boost_factor", 2).endObject()
.endArray()
.endObject().endObject().string();
try {

View File

@ -19,16 +19,20 @@
package org.elasticsearch.index.query;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.junit.Test;
import java.io.IOException;
import java.util.*;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.*;
public class SimpleQueryStringBuilderTest extends BaseQueryTestCase<SimpleQueryStringBuilder> {
@ -86,6 +90,27 @@ public class SimpleQueryStringBuilderTest extends BaseQueryTestCase<SimpleQueryS
@Override
protected void doAssertLuceneQuery(SimpleQueryStringBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
assertThat(query, notNullValue());
if (queryBuilder.fields().size() > 1) {
assertThat(query, instanceOf(BooleanQuery.class));
BooleanQuery booleanQuery = (BooleanQuery) query;
assertThat(booleanQuery.clauses().size(), equalTo(queryBuilder.fields().size()));
Iterator<String> fields = queryBuilder.fields().keySet().iterator();
for (BooleanClause booleanClause : booleanQuery) {
assertThat(booleanClause.getQuery(), instanceOf(TermQuery.class));
TermQuery termQuery = (TermQuery) booleanClause.getQuery();
assertThat(termQuery.getTerm(), equalTo(new Term(fields.next(), queryBuilder.text().toLowerCase(Locale.ROOT))));
}
} else {
assertThat(query, instanceOf(TermQuery.class));
String field;
if (queryBuilder.fields().size() == 0) {
field = MetaData.ALL;
} else {
field = queryBuilder.fields().keySet().iterator().next();
}
TermQuery termQuery = (TermQuery) query;
assertThat(termQuery.getTerm(), equalTo(new Term(field, queryBuilder.text().toLowerCase(Locale.ROOT))));
}
}
@Test
@ -214,7 +239,28 @@ public class SimpleQueryStringBuilderTest extends BaseQueryTestCase<SimpleQueryS
qb.fields(null);
}
private int shouldClauses(BooleanQuery query) {
@Test
public void testDefaultFieldParsing() throws IOException {
QueryParseContext context = createParseContext();
String query = randomAsciiOfLengthBetween(1, 10).toLowerCase(Locale.ROOT);
String contentString = "{\n" +
" \"simple_query_string\" : {\n" +
" \"query\" : \"" + query + "\"" +
" }\n" +
"}";
XContentParser parser = XContentFactory.xContent(contentString).createParser(contentString);
context.reset(parser);
SimpleQueryStringBuilder queryBuilder = new SimpleQueryStringParser().fromXContent(context);
assertThat(queryBuilder.text(), equalTo(query));
assertThat(queryBuilder.fields(), notNullValue());
assertThat(queryBuilder.fields().size(), equalTo(0));
Query luceneQuery = queryBuilder.toQuery(createShardContext());
assertThat(luceneQuery, instanceOf(TermQuery.class));
TermQuery termQuery = (TermQuery) luceneQuery;
assertThat(termQuery.getTerm(), equalTo(new Term(MetaData.ALL, query)));
}
private static int shouldClauses(BooleanQuery query) {
int result = 0;
for (BooleanClause c : query.clauses()) {
if (c.getOccur() == BooleanClause.Occur.SHOULD) {

View File

@ -1,8 +0,0 @@
{
"simple_query_string": {
"query": "foo bar",
"analyzer": "keyword",
"fields": ["body^5","_all"],
"default_operator": "and"
}
}

View File

@ -176,6 +176,7 @@ public class BytesRestResponseTests extends ESTestCase {
DetailedExceptionRestChannel(RestRequest request) {
super(request, true);
request.params().put(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true");
}
@Override

View File

@ -24,7 +24,6 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.SimpleQueryStringBuilder;
import org.elasticsearch.index.query.SimpleQueryStringFlag;
import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Test;
@ -34,10 +33,7 @@ import java.util.Locale;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.simpleQueryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
import static org.hamcrest.Matchers.equalTo;
@ -94,11 +90,6 @@ public class SimpleQueryStringIT extends ESIntegTestCase {
searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("spaghetti").field("*body")).get();
assertHitCount(searchResponse, 2l);
assertSearchHits(searchResponse, "5", "6");
// Have to bypass the builder here because the builder always uses "fields" instead of "field"
searchResponse = client().prepareSearch().setQuery("{\"simple_query_string\": {\"query\": \"spaghetti\", \"field\": \"_all\"}}").get();
assertHitCount(searchResponse, 2l);
assertSearchHits(searchResponse, "5", "6");
}
@Test

View File

@ -1,6 +1,5 @@
<?xml version="1.0"?>
<project name="elasticsearch-integration-tests">
<!-- our pid file for easy cleanup -->
<property name="integ.pidfile" location="${integ.scratch}/es.pid"/>
@ -124,11 +123,27 @@
</sequential>
</macrodef>
<!-- waits for cluster to form and have exactly two nodes -->
<macrodef name="waitfor-two-nodes">
<attribute name="port"/>
<attribute name="timeoutproperty"/>
<sequential>
<echo>Waiting for elasticsearch to form a cluster of two...</echo>
<waitfor maxwait="30" maxwaitunit="second"
checkevery="500" checkeveryunit="millisecond"
timeoutproperty="@{timeoutproperty}">
<http url="http://127.0.0.1:@{port}/_cluster/health?wait_for_nodes=2"/>
</waitfor>
</sequential>
</macrodef>
<!-- start elasticsearch and wait until its ready -->
<macrodef name="startup-elasticsearch">
<attribute name="home" default="${integ.scratch}/elasticsearch-${elasticsearch.version}"/>
<attribute name="spawn" default="true"/>
<attribute name="args" default="${integ.args}"/>
<attribute name="es.unicast.enabled" default="false"/>
<attribute name="es.unicast.hosts" default=""/>
<attribute name="es.cluster.name" default="${integ.cluster.name}"/>
<attribute name="es.http.port" default="${integ.http.port}"/>
<attribute name="es.transport.tcp.port" default="${integ.transport.port}"/>
@ -146,6 +161,8 @@
-Des.pidfile=@{es.pidfile}
-Des.path.repo=@{home}/repo
-Des.discovery.zen.ping.multicast.enabled=false
-Des.discovery.zen.ping.unicast.enabled=@{es.unicast.enabled}
-Des.discovery.zen.ping.unicast.hosts=@{es.unicast.hosts}
-Des.script.inline=on
-Des.script.indexed=on
-Des.repositories.url.allowed_urls=http://snapshot.test*
@ -183,7 +200,7 @@
<local name="integ.pid"/>
<extract-pid file="@{es.pidfile}" property="integ.pid"/>
<echo>External cluster started PID ${integ.pid}</echo>
<echo>External node started PID ${integ.pid}</echo>
</sequential>
</macrodef>
@ -205,6 +222,40 @@
</sequential>
</macrodef>
<macrodef name="stop-node">
<attribute name="es.pidfile" default="${integ.pidfile}"/>
<sequential>
<local name="integ.pid"/>
<extract-pid file="@{es.pidfile}" property="integ.pid"/>
<echo>Shutting down external node PID ${integ.pid}</echo>
<exec executable="taskkill" failonerror="true" osfamily="winnt">
<arg value="/F"/>
<arg value="/PID"/>
<arg value="${integ.pid}"/>
</exec>
<exec executable="kill" failonerror="true" osfamily="unix">
<arg value="-9"/>
<arg value="${integ.pid}"/>
</exec>
<delete file="@{es.pidfile}"/>
</sequential>
</macrodef>
<!-- starts a unicast node on an already setup workspace-->
<macrodef name="start-unicast-node">
<attribute name="es.http.port" default="${integ.http.port}"/>
<attribute name="es.transport.port" default="${integ.transport.port}"/>
<attribute name="es.pidfile" default="${integ.pidfile}"/>
<attribute name="es.peer.list" />
<sequential>
<startup-elasticsearch es.pidfile="@{es.pidfile}" es.unicast.enabled="true"
es.transport.tcp.port="@{es.transport.port}" es.http.port="@{es.http.port}"
es.unicast.hosts="@{es.peer.list}"/>
</sequential>
</macrodef>
<!-- unzip the elasticsearch zip -->
<target name="setup-workspace" depends="stop-external-cluster">
<sequential>
@ -233,21 +284,7 @@
<!-- TODO, for some more safety, add back some of the old jps logic
and verify the pid is really an ES process! (fail otherwise) -->
<target name="stop-external-cluster" if="integ.pidfile.exists">
<local name="integ.pid"/>
<extract-pid file="${integ.pidfile}" property="integ.pid"/>
<echo>Shutting down external cluster PID ${integ.pid}</echo>
<exec executable="taskkill" failonerror="true" osfamily="winnt">
<arg value="/F"/>
<arg value="/PID"/>
<arg value="${integ.pid}"/>
</exec>
<exec executable="kill" failonerror="true" osfamily="unix">
<arg value="-9"/>
<arg value="${integ.pid}"/>
</exec>
<delete file="${integ.pidfile}"/>
<stop-node/>
</target>
<!-- distribution tests: .zip -->

View File

@ -115,6 +115,8 @@
<integ.temp>${integ.scratch}/temp</integ.temp>
<integ.http.port>9400</integ.http.port>
<integ.transport.port>9500</integ.transport.port>
<integ.http.port.sec>9600</integ.http.port.sec>
<integ.transport.port.sec>9700</integ.transport.port.sec>
<no.commit.pattern>\bno(n|)commit\b</no.commit.pattern>
</properties>

View File

@ -147,6 +147,7 @@
<modules>
<module>smoke-test-plugins</module>
<module>smoke-test-shaded</module>
<module>smoke-test-multinode</module>
</modules>
<profiles>

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<project name="smoke-test-multinode"
xmlns:ac="antlib:net.sf.antcontrib">
<import file="${elasticsearch.integ.antfile.default}"/>
<property name="integ.pidfile.sec" location="${integ.scratch}/es-secondary.pid"/>
<available property="integ.pidfile.sec.exists" file="${integ.pidfile.sec}"/>
<target name="stop-secondary-node" if="integ.pidfile.sec.exists">
<stop-node es.pidfile="${integ.pidfile.sec}"/>
</target>
<target name="stop-primary-node" if="integ.pidfile.exists">
<stop-node es.pidfile="${integ.pidfile}"/>
</target>
<target name="start-external-multi-node-no-plugins" depends="stop-secondary-node, setup-workspace" unless="${shouldskip}">
<start-unicast-node es.peer.list="127.0.0.1:9700"/>
<ac:trycatch property="failure.message">
<ac:try>
<start-unicast-node es.http.port="9600" es.transport.port="9700"
es.pidfile="${integ.pidfile.sec}"
es.peer.list="127.0.0.1:${integ.transport.port}"/>
</ac:try>
<ac:catch>
<echo>Failed to start second node with message: ${failure.message}</echo>
<stop-node es.pidfile="${integ.pidfile}"/>
</ac:catch>
</ac:trycatch>
<ac:trycatch>
<ac:try>
<local name="failed.to.form.cluster"/>
<waitfor-two-nodes port="${integ.http.port}"
timeoutproperty="failed.to.form.cluster"/>
<fail message="Instances did not form a cluster" if="failed.to.form.cluster"/>
</ac:try>
<ac:catch>
<stop-node es.pidfile="${integ.pidfile}"/>
<stop-node es.pidfile="${integ.pidfile.sec}"/>
</ac:catch>
</ac:trycatch>
</target>
</project>

View File

@ -0,0 +1,305 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.elasticsearch.qa</groupId>
<artifactId>elasticsearch-qa</artifactId>
<version>2.0.0-beta1-SNAPSHOT</version>
</parent>
<!--
This test unzips elasticsearch, installs each plugin,
starts 2 elasticsearch nodes, verifies that they form a cluster.
-->
<artifactId>smoke-test-multinode</artifactId>
<name>QA: Smoke Test Multi-Node IT</name>
<description>Tests that multi node IT tests work</description>
<properties>
<skip.unit.tests>true</skip.unit.tests>
<elasticsearch.integ.antfile>${project.basedir}/integration-tests.xml</elasticsearch.integ.antfile>
<tests.rest.suite>smoke_test_multinode</tests.rest.suite>
<tests.rest.load_packaged>false</tests.rest.load_packaged>
</properties>
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<!-- Provided dependencies by elasticsearch itself -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-backward-codecs</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queries</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-memory</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-suggest</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-join</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-spatial</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-expressions</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.carrotsearch</groupId>
<artifactId>hppc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-convert</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-smile</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.ning</groupId>
<artifactId>compress-lzf</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.tdunning</groupId>
<artifactId>t-digest</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<classifier>indy</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>apache-log4j-extras</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<scope>provided</scope>
</dependency>
<!-- Required by the REST test framework -->
<!-- TODO: remove this dependency when we will have a REST Test module -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>integ-setup-dependencies</id>
<phase>pre-integration-test</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<skip>${skip.integ.tests}</skip>
<useBaseVersion>true</useBaseVersion>
<outputDirectory>${integ.deps}/plugins</outputDirectory>
<artifactItems>
<!-- elasticsearch distribution -->
<artifactItem>
<groupId>org.elasticsearch.distribution.zip</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>${integ.deps}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- integration tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<!-- start up external cluster -->
<execution>
<id>integ-setup</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<ant antfile="${elasticsearch.integ.antfile}" target="start-external-multi-node-no-plugins">
<property name="tests.jvm.argline" value="${tests.jvm.argline}"/>
<property name="integ.multi.node" value="true"/>
</ant>
</target>
<skip>${skip.integ.tests}</skip>
</configuration>
</execution>
<!-- shut down external cluster -->
<execution>
<id>integ-teardown</id>
<phase>post-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<ant antfile="${elasticsearch.integ.antfile}" target="stop-external-cluster"/>
</target>
<skip>${skip.integ.tests}</skip>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>1.0b3</version>
<exclusions>
<exclusion>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>1.8.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,26 @@
# Integration tests for smoke testing multi-node IT
#
---
"cluster health basic test, one index":
- do:
indices.create:
index: test_index
body:
settings:
index:
number_of_replicas: 1
- do:
cluster.health:
wait_for_status: green
- is_true: cluster_name
- is_false: timed_out
- gte: { number_of_nodes: 2 }
- gte: { number_of_data_nodes: 2 }
- gt: { active_primary_shards: 0 }
- gt: { active_shards: 0 }
- gte: { relocating_shards: 0 }
- match: { initializing_shards: 0 }
- match: { unassigned_shards: 0 }
- gte: { number_of_pending_tasks: 0 }

View File

@ -0,0 +1,41 @@
/*
* 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.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
public class SmokeTestMultiIT extends ESRestTestCase {
public SmokeTestMultiIT(@Name("yaml") RestTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
}
}