[Test] Extending parsing checks for SearchResponse (#25148)
This change extends the tests and parsing of SearchResponse to make sure we can skip additional fields the parser doesn't know for forward compatibility reasons.
This commit is contained in:
parent
a03b6c2fa5
commit
823cbb437b
|
@ -45,8 +45,6 @@ import java.util.Map;
|
|||
|
||||
import static org.elasticsearch.action.search.ShardSearchFailure.readShardSearchFailure;
|
||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
|
||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownField;
|
||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownToken;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -245,7 +243,7 @@ public class SearchResponse extends ActionResponse implements StatusToXContentOb
|
|||
} else if (NUM_REDUCE_PHASES.match(currentFieldName)) {
|
||||
numReducePhases = parser.intValue();
|
||||
} else {
|
||||
throwUnknownField(currentFieldName, parser.getTokenLocation());
|
||||
parser.skipChildren();
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if (SearchHits.Fields.HITS.equals(currentFieldName)) {
|
||||
|
@ -268,7 +266,7 @@ public class SearchResponse extends ActionResponse implements StatusToXContentOb
|
|||
} else if (RestActions.TOTAL_FIELD.match(currentFieldName)) {
|
||||
totalShards = parser.intValue();
|
||||
} else {
|
||||
throwUnknownField(currentFieldName, parser.getTokenLocation());
|
||||
parser.skipChildren();
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
if (RestActions.FAILURES_FIELD.match(currentFieldName)) {
|
||||
|
@ -276,14 +274,14 @@ public class SearchResponse extends ActionResponse implements StatusToXContentOb
|
|||
failures.add(ShardSearchFailure.fromXContent(parser));
|
||||
}
|
||||
} else {
|
||||
throwUnknownField(currentFieldName, parser.getTokenLocation());
|
||||
parser.skipChildren();
|
||||
}
|
||||
} else {
|
||||
throwUnknownToken(token, parser.getTokenLocation());
|
||||
parser.skipChildren();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throwUnknownField(currentFieldName, parser.getTokenLocation());
|
||||
parser.skipChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
|
||||
|
||||
public class SearchResponseTests extends ESTestCase {
|
||||
|
@ -78,31 +79,71 @@ public class SearchResponseTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private SearchResponse createTestItem(ShardSearchFailure... shardSearchFailures) {
|
||||
SearchHits hits = SearchHitsTests.createTestItem();
|
||||
return createTestItem(false, shardSearchFailures);
|
||||
}
|
||||
|
||||
/**
|
||||
* This SearchResponse doesn't include SearchHits, Aggregations, Suggestions, ShardSearchFailures, SearchProfileShardResults
|
||||
* to make it possible to only test properties of the SearchResponse itself
|
||||
*/
|
||||
private SearchResponse createMinimalTestItem() {
|
||||
return createTestItem(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* if minimal is set, don't include search hits, aggregations, suggest etc... to make test simpler
|
||||
*/
|
||||
private SearchResponse createTestItem(boolean minimal, ShardSearchFailure... shardSearchFailures) {
|
||||
boolean timedOut = randomBoolean();
|
||||
Boolean terminatedEarly = randomBoolean() ? null : randomBoolean();
|
||||
int numReducePhases = randomIntBetween(1, 10);
|
||||
long tookInMillis = randomNonNegativeLong();
|
||||
int successfulShards = randomInt();
|
||||
int totalShards = randomInt();
|
||||
|
||||
InternalAggregations aggregations = aggregationsTests.createTestInstance();
|
||||
Suggest suggest = SuggestTests.createTestItem();
|
||||
SearchProfileShardResults profileShardResults = SearchProfileShardResultsTests.createTestItem();
|
||||
|
||||
InternalSearchResponse internalSearchResponse = new InternalSearchResponse(hits, aggregations, suggest, profileShardResults,
|
||||
InternalSearchResponse internalSearchResponse;
|
||||
if (minimal == false) {
|
||||
SearchHits hits = SearchHitsTests.createTestItem();
|
||||
InternalAggregations aggregations = aggregationsTests.createTestInstance();
|
||||
Suggest suggest = SuggestTests.createTestItem();
|
||||
SearchProfileShardResults profileShardResults = SearchProfileShardResultsTests.createTestItem();
|
||||
internalSearchResponse = new InternalSearchResponse(hits, aggregations, suggest, profileShardResults,
|
||||
timedOut, terminatedEarly, numReducePhases);
|
||||
} else {
|
||||
internalSearchResponse = InternalSearchResponse.empty();
|
||||
}
|
||||
return new SearchResponse(internalSearchResponse, null, totalShards, successfulShards, tookInMillis, shardSearchFailures);
|
||||
}
|
||||
|
||||
/**
|
||||
* the "_shard/total/failures" section makes it impossible to directly
|
||||
* compare xContent, so we omit it here
|
||||
*/
|
||||
public void testFromXContent() throws IOException {
|
||||
// the "_shard/total/failures" section makes if impossible to directly compare xContent, so we omit it here
|
||||
SearchResponse response = createTestItem();
|
||||
doFromXContentTestWithRandomFields(createTestItem(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test adds random fields and objects to the xContent rendered out to
|
||||
* ensure we can parse it back to be forward compatible with additions to
|
||||
* the xContent. We test this with a "minimal" SearchResponse, adding random
|
||||
* fields to SearchHits, Aggregations etc... is tested in their own tests
|
||||
*/
|
||||
public void testFromXContentWithRandomFields() throws IOException {
|
||||
doFromXContentTestWithRandomFields(createMinimalTestItem(), true);
|
||||
}
|
||||
|
||||
private void doFromXContentTestWithRandomFields(SearchResponse response, boolean addRandomFields) throws IOException {
|
||||
XContentType xcontentType = randomFrom(XContentType.values());
|
||||
boolean humanReadable = randomBoolean();
|
||||
final ToXContent.Params params = new ToXContent.MapParams(singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
|
||||
BytesReference originalBytes = toShuffledXContent(response, xcontentType, params, humanReadable);
|
||||
try (XContentParser parser = createParser(xcontentType.xContent(), originalBytes)) {
|
||||
BytesReference mutated;
|
||||
if (addRandomFields) {
|
||||
mutated = insertRandomFields(xcontentType, originalBytes, null, random());
|
||||
} else {
|
||||
mutated = originalBytes;
|
||||
}
|
||||
try (XContentParser parser = createParser(xcontentType.xContent(), mutated)) {
|
||||
SearchResponse parsed = SearchResponse.fromXContent(parser);
|
||||
assertToXContentEquivalent(originalBytes, XContentHelper.toXContent(parsed, xcontentType, params, humanReadable), xcontentType);
|
||||
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
|
||||
|
|
Loading…
Reference in New Issue