Browse Source

Restore V8 REST compatibility around highlight force_source parameter (#124873)

While that was an approved breaking change, the change should have ensured v8
compatibility, so that under v8 compatibility mode the parameter is still accepted,
but rejected in v9 compatibility mode (default).

This commit ensures compatibility and adds a test for it.
Luca Cavanna 7 months ago
parent
commit
6d914a2b8e

+ 5 - 0
docs/changelog/124873.yaml

@@ -0,0 +1,5 @@
+pr: 124873
+summary: Restore V8 REST compatibility around highlight `force_source` parameter
+area: Highlighting
+type: bug
+issues: []

+ 4 - 0
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java

@@ -17,6 +17,7 @@ import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.core.RestApiVersion;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.Rewriteable;
 import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder.BoundaryScannerType;
@@ -64,6 +65,8 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     public static final ParseField TYPE_FIELD = new ParseField("type");
     public static final ParseField FRAGMENTER_FIELD = new ParseField("fragmenter");
     public static final ParseField NO_MATCH_SIZE_FIELD = new ParseField("no_match_size");
+    public static final ParseField FORCE_SOURCE_FIELD = new ParseField("force_source").withAllDeprecated()
+        .forRestApiVersion(restApiVersion -> restApiVersion == RestApiVersion.V_8);
     public static final ParseField PHRASE_LIMIT_FIELD = new ParseField("phrase_limit");
     public static final ParseField OPTIONS_FIELD = new ParseField("options");
     public static final ParseField HIGHLIGHT_QUERY_FIELD = new ParseField("highlight_query");
@@ -666,6 +669,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         parser.declareString(HB::highlighterType, TYPE_FIELD);
         parser.declareString(HB::fragmenter, FRAGMENTER_FIELD);
         parser.declareInt(HB::noMatchSize, NO_MATCH_SIZE_FIELD);
+        parser.declareBoolean((builder, value) -> {}, FORCE_SOURCE_FIELD);  // force_source is ignored
         parser.declareInt(HB::phraseLimit, PHRASE_LIMIT_FIELD);
         parser.declareInt(HB::maxAnalyzedOffset, MAX_ANALYZED_OFFSET_FIELD);
         parser.declareObject(HB::options, (XContentParser p, Void c) -> {

+ 33 - 0
server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java

@@ -18,6 +18,8 @@ import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.Maps;
 import org.elasticsearch.common.util.set.Sets;
+import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
+import org.elasticsearch.core.RestApiVersion;
 import org.elasticsearch.index.Index;
 import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.index.IndexVersion;
@@ -46,6 +48,7 @@ import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentFactory;
 import org.elasticsearch.xcontent.XContentParseException;
 import org.elasticsearch.xcontent.XContentParser;
+import org.elasticsearch.xcontent.XContentParserConfiguration;
 import org.elasticsearch.xcontent.XContentType;
 import org.elasticsearch.xcontent.json.JsonXContent;
 import org.junit.AfterClass;
@@ -607,6 +610,36 @@ public class HighlightBuilderTests extends ESTestCase {
         }
     }
 
+    public void testForceSourceRemovedInV9() throws IOException {
+        String highlightJson = """
+            { "fields" : { }, "force_source" : true }
+            """;
+
+        XContentParserConfiguration config = XContentParserConfiguration.EMPTY.withRegistry(xContentRegistry())
+            .withDeprecationHandler(LoggingDeprecationHandler.INSTANCE)
+            .withRestApiVersion(RestApiVersion.V_9);
+        try (XContentParser parser = JsonXContent.jsonXContent.createParser(config, highlightJson)) {
+            XContentParseException xContentParseException = expectThrows(
+                XContentParseException.class,
+                () -> HighlightBuilder.fromXContent(parser)
+            );
+            assertThat(xContentParseException.getMessage(), containsString("unknown field [force_source]"));
+        }
+    }
+
+    public void testForceSourceV8Comp() throws IOException {
+        String highlightJson = """
+            { "fields" : { }, "force_source" : true }
+            """;
+        XContentParserConfiguration config = XContentParserConfiguration.EMPTY.withRegistry(xContentRegistry())
+            .withDeprecationHandler(LoggingDeprecationHandler.INSTANCE)
+            .withRestApiVersion(RestApiVersion.V_8);
+        try (XContentParser parser = JsonXContent.jsonXContent.createParser(config, highlightJson)) {
+            HighlightBuilder.fromXContent(parser);
+            assertWarnings("Deprecated field [force_source] used, this field is unused and will be removed entirely");
+        }
+    }
+
     protected static XContentBuilder toXContent(HighlightBuilder highlight, XContentType contentType) throws IOException {
         XContentBuilder builder = XContentFactory.contentBuilder(contentType);
         if (randomBoolean()) {