From 4c726311e2c5ef825b37d8d049bbedcad6224216 Mon Sep 17 00:00:00 2001 From: javanna Date: Thu, 15 Sep 2016 20:27:08 +0200 Subject: [PATCH] [TEST] introduce test plugin to inject random search ext elements in search request tests A few of our unit tests generate a random search request body nd run tests against it. The source can optionally contain ext elements under the ext sections, which can be parsed by plugins. With this commit we introduce a plugin so that the tests don't use the one from FetchSubPhasePluginIT anymore. They rather generate multiple search ext elements. The plugin can parse and deal with all those. This extends the test coverage as we may have multiple elements with random names. Took the chance to introduce a common test base class for search requests, called AbstractSearchTestCase, given that the setup phase is the same for all three tests around search source. Then we can have the setup isolated to the base class and the subclasses relying on it. Closes #17685 --- .../search/AbstractSearchTestCase.java | 512 ++++++++++++++++++ .../search/SearchRequestTests.java | 70 +-- .../builder/SearchSourceBuilderTests.java | 279 +--------- .../ShardSearchTransportRequestTests.java | 44 +- 4 files changed, 522 insertions(+), 383 deletions(-) create mode 100644 core/src/test/java/org/elasticsearch/search/AbstractSearchTestCase.java diff --git a/core/src/test/java/org/elasticsearch/search/AbstractSearchTestCase.java b/core/src/test/java/org/elasticsearch/search/AbstractSearchTestCase.java new file mode 100644 index 00000000000..048416c25ef --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/AbstractSearchTestCase.java @@ -0,0 +1,512 @@ +/* + * 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.search; + +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchType; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.common.ParsingException; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.text.Text; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.indices.IndicesModule; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.plugins.SearchPlugin; +import org.elasticsearch.script.Script; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.fetch.subphase.FetchSourceContext; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilderTests; +import org.elasticsearch.search.rescore.QueryRescoreBuilderTests; +import org.elasticsearch.search.searchafter.SearchAfterBuilder; +import org.elasticsearch.search.slice.SliceBuilder; +import org.elasticsearch.search.sort.ScriptSortBuilder; +import org.elasticsearch.search.sort.SortBuilders; +import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.search.suggest.SuggestBuilderTests; +import org.elasticsearch.test.AbstractQueryTestCase; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; + +public abstract class AbstractSearchTestCase extends ESTestCase { + + protected NamedWriteableRegistry namedWriteableRegistry; + protected SearchRequestParsers searchRequestParsers; + private TestSearchExtPlugin searchExtPlugin; + + public void setUp() throws Exception { + super.setUp(); + IndicesModule indicesModule = new IndicesModule(Collections.emptyList()); + searchExtPlugin = new TestSearchExtPlugin(); + SearchModule searchModule = new SearchModule(Settings.EMPTY, false, Collections.singletonList(searchExtPlugin)); + List entries = new ArrayList<>(); + entries.addAll(indicesModule.getNamedWriteables()); + entries.addAll(searchModule.getNamedWriteables()); + namedWriteableRegistry = new NamedWriteableRegistry(entries); + searchRequestParsers = searchModule.getSearchRequestParsers(); + } + + protected SearchSourceBuilder createSearchSourceBuilder() throws IOException { + SearchSourceBuilder builder = new SearchSourceBuilder(); + if (randomBoolean()) { + builder.from(randomIntBetween(0, 10000)); + } + if (randomBoolean()) { + builder.size(randomIntBetween(0, 10000)); + } + if (randomBoolean()) { + builder.explain(randomBoolean()); + } + if (randomBoolean()) { + builder.version(randomBoolean()); + } + if (randomBoolean()) { + builder.trackScores(randomBoolean()); + } + if (randomBoolean()) { + builder.minScore(randomFloat() * 1000); + } + if (randomBoolean()) { + builder.timeout(TimeValue.parseTimeValue(randomTimeValue(), null, "timeout")); + } + if (randomBoolean()) { + builder.terminateAfter(randomIntBetween(1, 100000)); + } + + switch(randomInt(2)) { + case 0: + builder.storedFields(); + break; + case 1: + builder.storedField("_none_"); + break; + case 2: + int fieldsSize = randomInt(25); + List fields = new ArrayList<>(fieldsSize); + for (int i = 0; i < fieldsSize; i++) { + fields.add(randomAsciiOfLengthBetween(5, 50)); + } + builder.storedFields(fields); + break; + default: + throw new IllegalStateException(); + } + + if (randomBoolean()) { + int scriptFieldsSize = randomInt(25); + for (int i = 0; i < scriptFieldsSize; i++) { + if (randomBoolean()) { + builder.scriptField(randomAsciiOfLengthBetween(5, 50), new Script("foo"), randomBoolean()); + } else { + builder.scriptField(randomAsciiOfLengthBetween(5, 50), new Script("foo")); + } + } + } + if (randomBoolean()) { + FetchSourceContext fetchSourceContext; + int branch = randomInt(5); + String[] includes = new String[randomIntBetween(0, 20)]; + for (int i = 0; i < includes.length; i++) { + includes[i] = randomAsciiOfLengthBetween(5, 20); + } + String[] excludes = new String[randomIntBetween(0, 20)]; + for (int i = 0; i < excludes.length; i++) { + excludes[i] = randomAsciiOfLengthBetween(5, 20); + } + switch (branch) { + case 0: + fetchSourceContext = new FetchSourceContext(randomBoolean()); + break; + case 1: + fetchSourceContext = new FetchSourceContext(includes, excludes); + break; + case 2: + fetchSourceContext = new FetchSourceContext(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20)); + break; + case 3: + fetchSourceContext = new FetchSourceContext(true, includes, excludes); + break; + case 4: + fetchSourceContext = new FetchSourceContext(includes); + break; + case 5: + fetchSourceContext = new FetchSourceContext(randomAsciiOfLengthBetween(5, 20)); + break; + default: + throw new IllegalStateException(); + } + builder.fetchSource(fetchSourceContext); + } + if (randomBoolean()) { + int size = randomIntBetween(0, 20); + List statsGroups = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + statsGroups.add(randomAsciiOfLengthBetween(5, 20)); + } + builder.stats(statsGroups); + } + if (randomBoolean()) { + int indexBoostSize = randomIntBetween(1, 10); + for (int i = 0; i < indexBoostSize; i++) { + builder.indexBoost(randomAsciiOfLengthBetween(5, 20), randomFloat() * 10); + } + } + if (randomBoolean()) { + builder.query(QueryBuilders.termQuery(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20))); + } + if (randomBoolean()) { + builder.postFilter(QueryBuilders.termQuery(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20))); + } + if (randomBoolean()) { + int numSorts = randomIntBetween(1, 5); + for (int i = 0; i < numSorts; i++) { + int branch = randomInt(5); + switch (branch) { + case 0: + builder.sort(SortBuilders.fieldSort(randomAsciiOfLengthBetween(5, 20)).order(randomFrom(SortOrder.values()))); + break; + case 1: + builder.sort(SortBuilders.geoDistanceSort(randomAsciiOfLengthBetween(5, 20), + AbstractQueryTestCase.randomGeohash(1, 12)).order(randomFrom(SortOrder.values()))); + break; + case 2: + builder.sort(SortBuilders.scoreSort().order(randomFrom(SortOrder.values()))); + break; + case 3: + builder.sort(SortBuilders.scriptSort(new Script("foo"), + ScriptSortBuilder.ScriptSortType.NUMBER).order(randomFrom(SortOrder.values()))); + break; + case 4: + builder.sort(randomAsciiOfLengthBetween(5, 20)); + break; + case 5: + builder.sort(randomAsciiOfLengthBetween(5, 20), randomFrom(SortOrder.values())); + break; + } + } + } + + if (randomBoolean()) { + int numSearchFrom = randomIntBetween(1, 5); + // We build a json version of the search_from first in order to + // ensure that every number type remain the same before/after xcontent (de)serialization. + // This is not a problem because the final type of each field value is extracted from associated sort field. + // This little trick ensure that equals and hashcode are the same when using the xcontent serialization. + XContentBuilder jsonBuilder = XContentFactory.jsonBuilder(); + jsonBuilder.startObject(); + jsonBuilder.startArray("search_from"); + for (int i = 0; i < numSearchFrom; i++) { + int branch = randomInt(8); + switch (branch) { + case 0: + jsonBuilder.value(randomInt()); + break; + case 1: + jsonBuilder.value(randomFloat()); + break; + case 2: + jsonBuilder.value(randomLong()); + break; + case 3: + jsonBuilder.value(randomDouble()); + break; + case 4: + jsonBuilder.value(randomAsciiOfLengthBetween(5, 20)); + break; + case 5: + jsonBuilder.value(randomBoolean()); + break; + case 6: + jsonBuilder.value(randomByte()); + break; + case 7: + jsonBuilder.value(randomShort()); + break; + case 8: + jsonBuilder.value(new Text(randomAsciiOfLengthBetween(5, 20))); + break; + } + } + jsonBuilder.endArray(); + jsonBuilder.endObject(); + XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(jsonBuilder.bytes()); + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + builder.searchAfter(SearchAfterBuilder.fromXContent(parser, null).getSortValues()); + } + if (randomBoolean()) { + builder.highlighter(HighlightBuilderTests.randomHighlighterBuilder()); + } + if (randomBoolean()) { + builder.suggest(SuggestBuilderTests.randomSuggestBuilder()); + } + if (randomBoolean()) { + int numRescores = randomIntBetween(1, 5); + for (int i = 0; i < numRescores; i++) { + builder.addRescorer(QueryRescoreBuilderTests.randomRescoreBuilder()); + } + } + if (randomBoolean()) { + builder.aggregation(AggregationBuilders.avg(randomAsciiOfLengthBetween(5, 20))); + } + if (randomBoolean()) { + Set elementNames = new HashSet<>(searchExtPlugin.getSupportedElements().keySet()); + int numSearchExts = randomIntBetween(1, elementNames.size()); + while(elementNames.size() > numSearchExts) { + elementNames.remove(randomFrom(elementNames)); + } + List searchExtBuilders = new ArrayList<>(); + for (String elementName : elementNames) { + searchExtBuilders.add(searchExtPlugin.getSupportedElements().get(elementName).apply(randomAsciiOfLengthBetween(3, 10))); + } + builder.ext(searchExtBuilders); + } + if (randomBoolean()) { + String field = randomBoolean() ? null : randomAsciiOfLengthBetween(5, 20); + int max = between(2, 1000); + int id = randomInt(max-1); + if (field == null) { + builder.slice(new SliceBuilder(id, max)); + } else { + builder.slice(new SliceBuilder(field, id, max)); + } + } + return builder; + } + + protected SearchRequest createSearchRequest() throws IOException { + SearchRequest searchRequest = new SearchRequest(); + if (randomBoolean()) { + searchRequest.indices(generateRandomStringArray(10, 10, false, false)); + } + if (randomBoolean()) { + searchRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean())); + } + if (randomBoolean()) { + searchRequest.types(generateRandomStringArray(10, 10, false, false)); + } + if (randomBoolean()) { + searchRequest.preference(randomAsciiOfLengthBetween(3, 10)); + } + if (randomBoolean()) { + searchRequest.requestCache(randomBoolean()); + } + if (randomBoolean()) { + searchRequest.routing(randomAsciiOfLengthBetween(3, 10)); + } + if (randomBoolean()) { + searchRequest.scroll(randomPositiveTimeValue()); + } + if (randomBoolean()) { + searchRequest.searchType(randomFrom(SearchType.values())); + } + if (randomBoolean()) { + searchRequest.source(createSearchSourceBuilder()); + } + return searchRequest; + } + + private static class TestSearchExtPlugin extends Plugin implements SearchPlugin { + private final List> searchExtSpecs; + private final Map> supportedElements; + + private TestSearchExtPlugin() { + int numSearchExts = randomIntBetween(1, 3); + this.searchExtSpecs = new ArrayList<>(numSearchExts); + this.supportedElements = new HashMap<>(); + for (int i = 0; i < numSearchExts; i++) { + switch (randomIntBetween(0, 2)) { + case 0: + if (this.supportedElements.put(TestSearchExtBuilder1.NAME, TestSearchExtBuilder1::new) == null) { + this.searchExtSpecs.add(new SearchExtSpec<>(TestSearchExtBuilder1.NAME, TestSearchExtBuilder1::new, + new TestSearchExtParser<>(TestSearchExtBuilder1::new))); + } + break; + case 1: + if (this.supportedElements.put(TestSearchExtBuilder2.NAME, TestSearchExtBuilder2::new) == null) { + this.searchExtSpecs.add(new SearchExtSpec<>(TestSearchExtBuilder2.NAME, TestSearchExtBuilder2::new, + new TestSearchExtParser<>(TestSearchExtBuilder2::new))); + } + break; + case 2: + if (this.supportedElements.put(TestSearchExtBuilder3.NAME, TestSearchExtBuilder3::new) == null) { + this.searchExtSpecs.add(new SearchExtSpec<>(TestSearchExtBuilder3.NAME, TestSearchExtBuilder3::new, + new TestSearchExtParser<>(TestSearchExtBuilder3::new))); + } + break; + default: + throw new UnsupportedOperationException(); + } + } + } + + Map> getSupportedElements() { + return supportedElements; + } + + @Override + public List> getSearchExts() { + return searchExtSpecs; + } + } + + private static class TestSearchExtParser implements SearchExtParser { + private final Function searchExtBuilderFunction; + + TestSearchExtParser(Function searchExtBuilderFunction) { + this.searchExtBuilderFunction = searchExtBuilderFunction; + } + + @Override + public T fromXContent(XContentParser parser) throws IOException { + return searchExtBuilderFunction.apply(parseField(parser)); + } + + String parseField(XContentParser parser) throws IOException { + if (parser.currentToken() != XContentParser.Token.START_OBJECT) { + throw new ParsingException(parser.getTokenLocation(), "start_object expected, found " + parser.currentToken()); + } + if (parser.nextToken() != XContentParser.Token.FIELD_NAME) { + throw new ParsingException(parser.getTokenLocation(), "field_name expected, found " + parser.currentToken()); + } + String field = parser.currentName(); + if (parser.nextToken() != XContentParser.Token.START_OBJECT) { + throw new ParsingException(parser.getTokenLocation(), "start_object expected, found " + parser.currentToken()); + } + if (parser.nextToken() != XContentParser.Token.END_OBJECT) { + throw new ParsingException(parser.getTokenLocation(), "end_object expected, found " + parser.currentToken()); + } + if (parser.nextToken() != XContentParser.Token.END_OBJECT) { + throw new ParsingException(parser.getTokenLocation(), "end_object expected, found " + parser.currentToken()); + } + return field; + } + } + + //Would be nice to have a single builder that gets its name as a parameter, but the name wouldn't get a value when the object + //is created reading from the stream (constructor that takes a StreamInput) which is a problem as we check that after reading + //a named writeable its name is the expected one. That's why we go for the following less dynamic approach. + private static class TestSearchExtBuilder1 extends TestSearchExtBuilder { + private static final String NAME = "name1"; + + TestSearchExtBuilder1(String field) { + super(NAME, field); + } + + TestSearchExtBuilder1(StreamInput in) throws IOException { + super(NAME, in); + } + } + + private static class TestSearchExtBuilder2 extends TestSearchExtBuilder { + private static final String NAME = "name2"; + + TestSearchExtBuilder2(String field) { + super(NAME, field); + } + + TestSearchExtBuilder2(StreamInput in) throws IOException { + super(NAME, in); + } + } + + private static class TestSearchExtBuilder3 extends TestSearchExtBuilder { + private static final String NAME = "name3"; + + TestSearchExtBuilder3(String field) { + super(NAME, field); + } + + TestSearchExtBuilder3(StreamInput in) throws IOException { + super(NAME, in); + } + } + + private abstract static class TestSearchExtBuilder extends SearchExtBuilder { + final String objectName; + protected final String name; + + TestSearchExtBuilder(String name, String objectName) { + this.name = name; + this.objectName = objectName; + } + + TestSearchExtBuilder(String name, StreamInput in) throws IOException { + this.name = name; + this.objectName = in.readString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(objectName); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TestSearchExtBuilder that = (TestSearchExtBuilder) o; + return Objects.equals(objectName, that.objectName) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(objectName, name); + } + + @Override + public String getWriteableName() { + return name; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(name); + builder.startObject(objectName); + builder.endObject(); + builder.endObject(); + return builder; + } + } +} diff --git a/core/src/test/java/org/elasticsearch/search/SearchRequestTests.java b/core/src/test/java/org/elasticsearch/search/SearchRequestTests.java index 2c7ae356bf8..6f48dbe4911 100644 --- a/core/src/test/java/org/elasticsearch/search/SearchRequestTests.java +++ b/core/src/test/java/org/elasticsearch/search/SearchRequestTests.java @@ -24,49 +24,13 @@ import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.indices.IndicesModule; -import org.elasticsearch.search.fetch.FetchSubPhasePluginIT; -import org.elasticsearch.test.ESTestCase; -import org.junit.AfterClass; -import org.junit.BeforeClass; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import static java.util.Collections.emptyList; -import static org.elasticsearch.search.builder.SearchSourceBuilderTests.createSearchSourceBuilder; - -public class SearchRequestTests extends ESTestCase { - - private static NamedWriteableRegistry namedWriteableRegistry; - - @BeforeClass - public static void beforeClass() { - IndicesModule indicesModule = new IndicesModule(emptyList()) { - @Override - protected void configure() { - bindMapperExtension(); - } - }; - SearchModule searchModule = new SearchModule(Settings.EMPTY, false, - Collections.singletonList(new FetchSubPhasePluginIT.FetchTermVectorsPlugin())); - List entries = new ArrayList<>(); - entries.addAll(indicesModule.getNamedWriteables()); - entries.addAll(searchModule.getNamedWriteables()); - namedWriteableRegistry = new NamedWriteableRegistry(entries); - } - - @AfterClass - public static void afterClass() { - namedWriteableRegistry = null; - } +public class SearchRequestTests extends AbstractSearchTestCase { public void testSerialization() throws Exception { SearchRequest searchRequest = createSearchRequest(); @@ -204,38 +168,6 @@ public class SearchRequestTests extends ESTestCase { } } - public static SearchRequest createSearchRequest() throws IOException { - SearchRequest searchRequest = new SearchRequest(); - if (randomBoolean()) { - searchRequest.indices(generateRandomStringArray(10, 10, false, false)); - } - if (randomBoolean()) { - searchRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean())); - } - if (randomBoolean()) { - searchRequest.types(generateRandomStringArray(10, 10, false, false)); - } - if (randomBoolean()) { - searchRequest.preference(randomAsciiOfLengthBetween(3, 10)); - } - if (randomBoolean()) { - searchRequest.requestCache(randomBoolean()); - } - if (randomBoolean()) { - searchRequest.routing(randomAsciiOfLengthBetween(3, 10)); - } - if (randomBoolean()) { - searchRequest.scroll(randomPositiveTimeValue()); - } - if (randomBoolean()) { - searchRequest.searchType(randomFrom(SearchType.values())); - } - if (randomBoolean()) { - searchRequest.source(createSearchSourceBuilder()); - } - return searchRequest; - } - private static SearchRequest copyRequest(SearchRequest searchRequest) throws IOException { SearchRequest result = new SearchRequest(); result.indices(searchRequest.indices()); diff --git a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java index 6d0ebffa5bd..43ea81e993c 100644 --- a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java @@ -26,297 +26,28 @@ import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.env.Environment; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; -import org.elasticsearch.indices.IndicesModule; -import org.elasticsearch.script.Script; -import org.elasticsearch.search.SearchModule; -import org.elasticsearch.search.SearchRequestParsers; -import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.fetch.FetchSubPhasePluginIT; -import org.elasticsearch.search.fetch.subphase.FetchSourceContext; -import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilderTests; -import org.elasticsearch.search.rescore.QueryRescoreBuilderTests; +import org.elasticsearch.search.AbstractSearchTestCase; import org.elasticsearch.search.rescore.QueryRescorerBuilder; -import org.elasticsearch.search.searchafter.SearchAfterBuilder; -import org.elasticsearch.search.slice.SliceBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.ScoreSortBuilder; -import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType; -import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; -import org.elasticsearch.search.suggest.SuggestBuilderTests; -import org.elasticsearch.test.AbstractQueryTestCase; -import org.elasticsearch.test.ESTestCase; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasToString; -public class SearchSourceBuilderTests extends ESTestCase { - - private NamedWriteableRegistry namedWriteableRegistry; - - private SearchRequestParsers searchRequestParsers; - - private ParseFieldMatcher parseFieldMatcher; - - public void setUp() throws Exception { - super.setUp(); - // we have to prefer CURRENT since with the range of versions we support - // it's rather unlikely to get the current actually. - Settings settings = Settings.builder() - .put("node.name", AbstractQueryTestCase.class.toString()) - .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build(); - IndicesModule indicesModule = new IndicesModule(Collections.emptyList()); - SearchModule searchModule = new SearchModule(settings, false, - Collections.singletonList(new FetchSubPhasePluginIT.FetchTermVectorsPlugin())); - List entries = new ArrayList<>(); - entries.addAll(indicesModule.getNamedWriteables()); - entries.addAll(searchModule.getNamedWriteables()); - namedWriteableRegistry = new NamedWriteableRegistry(entries); - searchRequestParsers = searchModule.getSearchRequestParsers(); - parseFieldMatcher = ParseFieldMatcher.STRICT; - } - - public static SearchSourceBuilder createSearchSourceBuilder() throws IOException { - SearchSourceBuilder builder = new SearchSourceBuilder(); - if (randomBoolean()) { - builder.from(randomIntBetween(0, 10000)); - } - if (randomBoolean()) { - builder.size(randomIntBetween(0, 10000)); - } - if (randomBoolean()) { - builder.explain(randomBoolean()); - } - if (randomBoolean()) { - builder.version(randomBoolean()); - } - if (randomBoolean()) { - builder.trackScores(randomBoolean()); - } - if (randomBoolean()) { - builder.minScore(randomFloat() * 1000); - } - if (randomBoolean()) { - builder.timeout(TimeValue.parseTimeValue(randomTimeValue(), null, "timeout")); - } - if (randomBoolean()) { - builder.terminateAfter(randomIntBetween(1, 100000)); - } - // if (randomBoolean()) { - // builder.defaultRescoreWindowSize(randomIntBetween(1, 100)); - // } - - switch(randomInt(2)) { - case 0: - builder.storedFields(); - break; - case 1: - builder.storedField("_none_"); - break; - case 2: - int fieldsSize = randomInt(25); - List fields = new ArrayList<>(fieldsSize); - for (int i = 0; i < fieldsSize; i++) { - fields.add(randomAsciiOfLengthBetween(5, 50)); - } - builder.storedFields(fields); - break; - default: - throw new IllegalStateException(); - } - - if (randomBoolean()) { - int scriptFieldsSize = randomInt(25); - for (int i = 0; i < scriptFieldsSize; i++) { - if (randomBoolean()) { - builder.scriptField(randomAsciiOfLengthBetween(5, 50), new Script("foo"), randomBoolean()); - } else { - builder.scriptField(randomAsciiOfLengthBetween(5, 50), new Script("foo")); - } - } - } - if (randomBoolean()) { - FetchSourceContext fetchSourceContext; - int branch = randomInt(5); - String[] includes = new String[randomIntBetween(0, 20)]; - for (int i = 0; i < includes.length; i++) { - includes[i] = randomAsciiOfLengthBetween(5, 20); - } - String[] excludes = new String[randomIntBetween(0, 20)]; - for (int i = 0; i < excludes.length; i++) { - excludes[i] = randomAsciiOfLengthBetween(5, 20); - } - switch (branch) { - case 0: - fetchSourceContext = new FetchSourceContext(randomBoolean()); - break; - case 1: - fetchSourceContext = new FetchSourceContext(includes, excludes); - break; - case 2: - fetchSourceContext = new FetchSourceContext(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20)); - break; - case 3: - fetchSourceContext = new FetchSourceContext(true, includes, excludes); - break; - case 4: - fetchSourceContext = new FetchSourceContext(includes); - break; - case 5: - fetchSourceContext = new FetchSourceContext(randomAsciiOfLengthBetween(5, 20)); - break; - default: - throw new IllegalStateException(); - } - builder.fetchSource(fetchSourceContext); - } - if (randomBoolean()) { - int size = randomIntBetween(0, 20); - List statsGroups = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - statsGroups.add(randomAsciiOfLengthBetween(5, 20)); - } - builder.stats(statsGroups); - } - if (randomBoolean()) { - int indexBoostSize = randomIntBetween(1, 10); - for (int i = 0; i < indexBoostSize; i++) { - builder.indexBoost(randomAsciiOfLengthBetween(5, 20), randomFloat() * 10); - } - } - if (randomBoolean()) { - builder.query(QueryBuilders.termQuery(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20))); - } - if (randomBoolean()) { - builder.postFilter(QueryBuilders.termQuery(randomAsciiOfLengthBetween(5, 20), randomAsciiOfLengthBetween(5, 20))); - } - if (randomBoolean()) { - int numSorts = randomIntBetween(1, 5); - for (int i = 0; i < numSorts; i++) { - int branch = randomInt(5); - switch (branch) { - case 0: - builder.sort(SortBuilders.fieldSort(randomAsciiOfLengthBetween(5, 20)).order(randomFrom(SortOrder.values()))); - break; - case 1: - builder.sort(SortBuilders.geoDistanceSort(randomAsciiOfLengthBetween(5, 20), - AbstractQueryTestCase.randomGeohash(1, 12)).order(randomFrom(SortOrder.values()))); - break; - case 2: - builder.sort(SortBuilders.scoreSort().order(randomFrom(SortOrder.values()))); - break; - case 3: - builder.sort(SortBuilders.scriptSort(new Script("foo"), - ScriptSortType.NUMBER).order(randomFrom(SortOrder.values()))); - break; - case 4: - builder.sort(randomAsciiOfLengthBetween(5, 20)); - break; - case 5: - builder.sort(randomAsciiOfLengthBetween(5, 20), randomFrom(SortOrder.values())); - break; - } - } - } - - if (randomBoolean()) { - int numSearchFrom = randomIntBetween(1, 5); - // We build a json version of the search_from first in order to - // ensure that every number type remain the same before/after xcontent (de)serialization. - // This is not a problem because the final type of each field value is extracted from associated sort field. - // This little trick ensure that equals and hashcode are the same when using the xcontent serialization. - XContentBuilder jsonBuilder = XContentFactory.jsonBuilder(); - jsonBuilder.startObject(); - jsonBuilder.startArray("search_from"); - for (int i = 0; i < numSearchFrom; i++) { - int branch = randomInt(8); - switch (branch) { - case 0: - jsonBuilder.value(randomInt()); - break; - case 1: - jsonBuilder.value(randomFloat()); - break; - case 2: - jsonBuilder.value(randomLong()); - break; - case 3: - jsonBuilder.value(randomDouble()); - break; - case 4: - jsonBuilder.value(randomAsciiOfLengthBetween(5, 20)); - break; - case 5: - jsonBuilder.value(randomBoolean()); - break; - case 6: - jsonBuilder.value(randomByte()); - break; - case 7: - jsonBuilder.value(randomShort()); - break; - case 8: - jsonBuilder.value(new Text(randomAsciiOfLengthBetween(5, 20))); - break; - } - } - jsonBuilder.endArray(); - jsonBuilder.endObject(); - XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(jsonBuilder.bytes()); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - builder.searchAfter(SearchAfterBuilder.fromXContent(parser, null).getSortValues()); - } - if (randomBoolean()) { - builder.highlighter(HighlightBuilderTests.randomHighlighterBuilder()); - } - if (randomBoolean()) { - builder.suggest(SuggestBuilderTests.randomSuggestBuilder()); - } - if (randomBoolean()) { - int numRescores = randomIntBetween(1, 5); - for (int i = 0; i < numRescores; i++) { - builder.addRescorer(QueryRescoreBuilderTests.randomRescoreBuilder()); - } - } - if (randomBoolean()) { - builder.aggregation(AggregationBuilders.avg(randomAsciiOfLengthBetween(5, 20))); - } - if (randomBoolean()) { - builder.ext(Collections.singletonList(new FetchSubPhasePluginIT.TermVectorsFetchBuilder("test"))); - } - if (randomBoolean()) { - String field = randomBoolean() ? null : randomAsciiOfLengthBetween(5, 20); - int max = between(2, 1000); - int id = randomInt(max-1); - if (field == null) { - builder.slice(new SliceBuilder(id, max)); - } else { - builder.slice(new SliceBuilder(field, id, max)); - } - } - return builder; - } +public class SearchSourceBuilderTests extends AbstractSearchTestCase { public void testFromXContent() throws IOException { SearchSourceBuilder testSearchSourceBuilder = createSearchSourceBuilder(); @@ -348,7 +79,7 @@ public class SearchSourceBuilderTests extends ESTestCase { } private QueryParseContext createParseContext(XContentParser parser) { - return new QueryParseContext(searchRequestParsers.queryParsers, parser, parseFieldMatcher); + return new QueryParseContext(searchRequestParsers.queryParsers, parser, ParseFieldMatcher.STRICT); } public void testSerialization() throws IOException { @@ -392,7 +123,7 @@ public class SearchSourceBuilderTests extends ESTestCase { } //we use the streaming infra to create a copy of the builder provided as argument - protected SearchSourceBuilder copyBuilder(SearchSourceBuilder builder) throws IOException { + private SearchSourceBuilder copyBuilder(SearchSourceBuilder builder) throws IOException { try (BytesStreamOutput output = new BytesStreamOutput()) { builder.writeTo(output); try (StreamInput in = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), namedWriteableRegistry)) { @@ -610,7 +341,7 @@ public class SearchSourceBuilderTests extends ESTestCase { } } - private void createIndexBoost(SearchSourceBuilder searchSourceBuilder) { + private static void createIndexBoost(SearchSourceBuilder searchSourceBuilder) { int indexBoostSize = randomIntBetween(1, 10); for (int i = 0; i < indexBoostSize; i++) { searchSourceBuilder.indexBoost(randomAsciiOfLengthBetween(5, 20), randomFloat() * 10); diff --git a/core/src/test/java/org/elasticsearch/search/internal/ShardSearchTransportRequestTests.java b/core/src/test/java/org/elasticsearch/search/internal/ShardSearchTransportRequestTests.java index 99a2b438ffd..452b6b6ba3a 100644 --- a/core/src/test/java/org/elasticsearch/search/internal/ShardSearchTransportRequestTests.java +++ b/core/src/test/java/org/elasticsearch/search/internal/ShardSearchTransportRequestTests.java @@ -27,49 +27,13 @@ import org.elasticsearch.cluster.routing.UnassignedInfo; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.indices.IndicesModule; -import org.elasticsearch.search.SearchModule; -import org.elasticsearch.search.SearchRequestTests; -import org.elasticsearch.search.fetch.FetchSubPhasePluginIT; -import org.elasticsearch.test.ESTestCase; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import org.elasticsearch.search.AbstractSearchTestCase; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import static java.util.Collections.emptyList; - -public class ShardSearchTransportRequestTests extends ESTestCase { - - private static NamedWriteableRegistry namedWriteableRegistry; - - @BeforeClass - public static void beforeClass() { - IndicesModule indicesModule = new IndicesModule(emptyList()) { - @Override - protected void configure() { - bindMapperExtension(); - } - }; - SearchModule searchModule = new SearchModule(Settings.EMPTY, false, - Collections.singletonList(new FetchSubPhasePluginIT.FetchTermVectorsPlugin())); - List entries = new ArrayList<>(); - entries.addAll(indicesModule.getNamedWriteables()); - entries.addAll(searchModule.getNamedWriteables()); - namedWriteableRegistry = new NamedWriteableRegistry(entries); - } - - @AfterClass - public static void afterClass() { - namedWriteableRegistry = null; - } +public class ShardSearchTransportRequestTests extends AbstractSearchTestCase { public void testSerialization() throws Exception { ShardSearchTransportRequest shardSearchTransportRequest = createShardSearchTransportRequest(); @@ -95,8 +59,8 @@ public class ShardSearchTransportRequestTests extends ESTestCase { } } - private static ShardSearchTransportRequest createShardSearchTransportRequest() throws IOException { - SearchRequest searchRequest = SearchRequestTests.createSearchRequest(); + private ShardSearchTransportRequest createShardSearchTransportRequest() throws IOException { + SearchRequest searchRequest = createSearchRequest(); ShardId shardId = new ShardId(randomAsciiOfLengthBetween(2, 10), randomAsciiOfLengthBetween(2, 10), randomInt()); ShardRouting shardRouting = TestShardRouting.newShardRouting(shardId, null, null, randomBoolean(), ShardRoutingState.UNASSIGNED, new UnassignedInfo(randomFrom(UnassignedInfo.Reason.values()), "reason"));