Skip to content

Commit d6b3e99

Browse files
committed
[Test] Extending checks for Suggestion parsing (#25132)
When parsing responses we should be ignoring any new unknown fields or inner objects in most cases to be forward compatible with changes in core on the client side. This change adds test for this for Suggestions and its various subclasses to check if we are able to ignore new fields and objects in the xContent.
1 parent e9dfed7 commit d6b3e99

File tree

6 files changed

+103
-13
lines changed

6 files changed

+103
-13
lines changed

core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestionOptionTests.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@
3636
import java.util.HashSet;
3737
import java.util.Map;
3838
import java.util.Set;
39+
import java.util.function.Predicate;
3940

4041
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
42+
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
4143
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
4244

4345
public class CompletionSuggestionOptionTests extends ESTestCase {
@@ -67,17 +69,31 @@ public static Option createTestItem() {
6769
}
6870

6971
public void testFromXContent() throws IOException {
72+
doTestFromXContent(false);
73+
}
74+
75+
public void testFromXContentWithRandomFields() throws IOException {
76+
doTestFromXContent(true);
77+
}
78+
79+
private void doTestFromXContent(boolean addRandomFields) throws IOException {
7080
Option option = createTestItem();
7181
XContentType xContentType = randomFrom(XContentType.values());
7282
boolean humanReadable = randomBoolean();
7383
BytesReference originalBytes = toShuffledXContent(option, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
74-
if (randomBoolean()) {
75-
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
76-
originalBytes = shuffleXContent(parser, randomBoolean()).bytes();
77-
}
84+
BytesReference mutated;
85+
if (addRandomFields) {
86+
// "contexts" is an object consisting of key/array pairs, we shouldn't add anything random there
87+
// also there can be inner search hits fields inside this option, we need to exclude another couple of paths
88+
// where we cannot add random stuff
89+
Predicate<String> excludeFilter = (path) -> (path.endsWith(CompletionSuggestion.Entry.Option.CONTEXTS.getPreferredName())
90+
|| path.endsWith("highlight") || path.endsWith("fields") || path.contains("_source") || path.contains("inner_hits"));
91+
mutated = insertRandomFields(xContentType, originalBytes, excludeFilter, random());
92+
} else {
93+
mutated = originalBytes;
7894
}
7995
Option parsed;
80-
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
96+
try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
8197
parsed = Option.fromXContent(parser);
8298
assertNull(parser.nextToken());
8399
}

core/src/test/java/org/elasticsearch/search/suggest/SuggestTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void testFromXContent() throws IOException {
9090
Suggest suggest = createTestItem();
9191
XContentType xContentType = randomFrom(XContentType.values());
9292
boolean humanReadable = randomBoolean();
93-
BytesReference originalBytes = toXContent(suggest, xContentType, params, humanReadable);
93+
BytesReference originalBytes = toShuffledXContent(suggest, xContentType, params, humanReadable);
9494
Suggest parsed;
9595
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
9696
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);

core/src/test/java/org/elasticsearch/search/suggest/SuggestionEntryTests.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
import java.util.HashMap;
3737
import java.util.Map;
3838
import java.util.function.Function;
39+
import java.util.function.Predicate;
3940
import java.util.function.Supplier;
4041

4142
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
4243
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
44+
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
4345
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
4446

4547
public class SuggestionEntryTests extends ESTestCase {
@@ -80,15 +82,35 @@ public static <O extends Option> Entry<O> createTestItem(Class<? extends Entry>
8082
return entry;
8183
}
8284

83-
@SuppressWarnings("unchecked")
8485
public void testFromXContent() throws IOException {
86+
doTestFromXContent(false);
87+
}
88+
89+
public void testFromXContentWithRandomFields() throws IOException {
90+
doTestFromXContent(true);
91+
}
92+
93+
@SuppressWarnings("unchecked")
94+
private void doTestFromXContent(boolean addRandomFields) throws IOException {
8595
for (Class<? extends Entry> entryType : ENTRY_PARSERS.keySet()) {
8696
Entry<Option> entry = createTestItem(entryType);
8797
XContentType xContentType = randomFrom(XContentType.values());
8898
boolean humanReadable = randomBoolean();
8999
BytesReference originalBytes = toShuffledXContent(entry, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
100+
BytesReference mutated;
101+
if (addRandomFields) {
102+
// "contexts" is an object consisting of key/array pairs, we shouldn't add anything random there
103+
// also there can be inner search hits fields inside this option, we need to exclude another couple of paths
104+
// where we cannot add random stuff
105+
Predicate<String> excludeFilter = (
106+
path) -> (path.endsWith(CompletionSuggestion.Entry.Option.CONTEXTS.getPreferredName()) || path.endsWith("highlight")
107+
|| path.endsWith("fields") || path.contains("_source") || path.contains("inner_hits"));
108+
mutated = insertRandomFields(xContentType, originalBytes, excludeFilter, random());
109+
} else {
110+
mutated = originalBytes;
111+
}
90112
Entry<Option> parsed;
91-
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
113+
try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
92114
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
93115
parsed = ENTRY_PARSERS.get(entry.getClass()).apply(parser);
94116
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());

core/src/test/java/org/elasticsearch/search/suggest/SuggestionOptionTests.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
3333
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
34+
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
3435
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
3536

3637
public class SuggestionOptionTests extends ESTestCase {
@@ -44,12 +45,26 @@ public static Option createTestItem() {
4445
}
4546

4647
public void testFromXContent() throws IOException {
48+
doTestFromXContent(false);
49+
}
50+
51+
public void testFromXContentWithRandomFields() throws IOException {
52+
doTestFromXContent(true);
53+
}
54+
55+
private void doTestFromXContent(boolean addRandomFields) throws IOException {
4756
Option option = createTestItem();
4857
XContentType xContentType = randomFrom(XContentType.values());
4958
boolean humanReadable = randomBoolean();
5059
BytesReference originalBytes = toShuffledXContent(option, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
60+
BytesReference mutated;
61+
if (addRandomFields) {
62+
mutated = insertRandomFields(xContentType, originalBytes, null, random());
63+
} else {
64+
mutated = originalBytes;
65+
}
5166
Option parsed;
52-
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
67+
try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
5368
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
5469
parsed = Option.fromXContent(parser);
5570
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());

core/src/test/java/org/elasticsearch/search/suggest/SuggestionTests.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@
4141
import java.util.Collections;
4242
import java.util.Map;
4343
import java.util.Set;
44+
import java.util.function.Predicate;
4445
import java.util.function.Supplier;
4546

4647
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
4748
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
49+
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
4850
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
4951

5052
public class SuggestionTests extends ESTestCase {
@@ -98,16 +100,36 @@ public static Suggestion<? extends Entry<? extends Option>> createTestItem(Class
98100
return suggestion;
99101
}
100102

101-
@SuppressWarnings({ "rawtypes" })
102103
public void testFromXContent() throws IOException {
104+
doTestFromXContent(false);
105+
}
106+
107+
public void testFromXContentWithRandomFields() throws IOException {
108+
doTestFromXContent(true);
109+
}
110+
111+
@SuppressWarnings({ "rawtypes" })
112+
private void doTestFromXContent(boolean addRandomFields) throws IOException {
103113
ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
104114
for (Class<Suggestion<? extends Entry<? extends Option>>> type : SUGGESTION_TYPES) {
105115
Suggestion suggestion = createTestItem(type);
106116
XContentType xContentType = randomFrom(XContentType.values());
107117
boolean humanReadable = randomBoolean();
108-
BytesReference originalBytes = toXContent(suggestion, xContentType, params, humanReadable);
118+
BytesReference originalBytes = toShuffledXContent(suggestion, xContentType, params, humanReadable);
119+
BytesReference mutated;
120+
if (addRandomFields) {
121+
// - "contexts" is an object consisting of key/array pairs, we shouldn't add anything random there
122+
// - there can be inner search hits fields inside this option where we cannot add random stuff
123+
// - the root object should be excluded since it contains the named suggestion arrays
124+
Predicate<String> excludeFilter = path -> (path.isEmpty()
125+
|| path.endsWith(CompletionSuggestion.Entry.Option.CONTEXTS.getPreferredName()) || path.endsWith("highlight")
126+
|| path.endsWith("fields") || path.contains("_source") || path.contains("inner_hits"));
127+
mutated = insertRandomFields(xContentType, originalBytes, excludeFilter, random());
128+
} else {
129+
mutated = originalBytes;
130+
}
109131
Suggestion parsed;
110-
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
132+
try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
111133
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
112134
ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation);
113135
parsed = Suggestion.fromXContent(parser);

core/src/test/java/org/elasticsearch/search/suggest/TermSuggestionOptionTests.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
3333
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
34+
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
3435
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
3536

3637
public class TermSuggestionOptionTests extends ESTestCase {
@@ -43,12 +44,26 @@ public static Option createTestItem() {
4344
}
4445

4546
public void testFromXContent() throws IOException {
47+
doTestFromXContent(false);
48+
}
49+
50+
public void testFromXContentWithRandomFields() throws IOException {
51+
doTestFromXContent(true);
52+
}
53+
54+
private void doTestFromXContent(boolean addRandomFields) throws IOException {
4655
Option option = createTestItem();
4756
XContentType xContentType = randomFrom(XContentType.values());
4857
boolean humanReadable = randomBoolean();
4958
BytesReference originalBytes = toShuffledXContent(option, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
59+
BytesReference mutated;
60+
if (addRandomFields) {
61+
mutated = insertRandomFields(xContentType, originalBytes, null, random());
62+
} else {
63+
mutated = originalBytes;
64+
}
5065
Option parsed;
51-
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
66+
try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
5267
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
5368
parsed = Option.fromXContent(parser);
5469
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());

0 commit comments

Comments
 (0)