diff --git a/modules/analysis-common/build.gradle b/modules/analysis-common/build.gradle index 776e857f80389..100f5cc2ef875 100644 --- a/modules/analysis-common/build.gradle +++ b/modules/analysis-common/build.gradle @@ -19,7 +19,7 @@ esplugin { restResources { restApi { - include '_common', 'indices', 'index', 'cluster', 'search', 'nodes', 'bulk', 'termvectors', 'explain', 'count', 'synonyms.put' + include '_common', 'indices', 'index', 'cluster', 'search', 'nodes', 'bulk', 'termvectors', 'explain', 'count', 'synonyms.put', 'synonyms.delete' } } diff --git a/modules/analysis-common/src/yamlRestTest/resources/rest-api-spec/test/analysis-common/70_synonyms_from_index.yml b/modules/analysis-common/src/yamlRestTest/resources/rest-api-spec/test/analysis-common/70_synonyms_from_index.yml index afe9434b8afd0..24e649ae0c14b 100644 --- a/modules/analysis-common/src/yamlRestTest/resources/rest-api-spec/test/analysis-common/70_synonyms_from_index.yml +++ b/modules/analysis-common/src/yamlRestTest/resources/rest-api-spec/test/analysis-common/70_synonyms_from_index.yml @@ -1,8 +1,10 @@ --- -"Load synonyms from index for an analyzer": +"Load and auto-reload synonyms from index for an analyzer": - skip: version: " - 8.8.99" reason: Loading synonyms from index is introduced in 8.9.0 + + # Create a new synonyms set - do: synonyms.put: synonyms_set: set1 @@ -10,9 +12,9 @@ synonyms_set: - synonyms: "hello, hi" - synonyms: "bye => goodbye" - - match: { result: "created" } + # Create an index with synonym_filter that uses that synonyms set - do: indices.create: index: my_index @@ -46,6 +48,7 @@ - '{"index": {"_index": "my_index", "_id": "2"}}' - '{"my_field": "goodbye"}' + # Confirm that synonyms from the synonyms set are used - do: search: index: my_index @@ -66,6 +69,71 @@ query: bye - match: { hits.total.value: 1 } + # Update synonyms and check reload status + - do: + synonyms.put: + synonyms_set: set1 + body: + synonyms_set: + - synonyms: "hello, salute" + - synonyms: "ciao => goodbye" + - match: { result: "updated" } + - gte: { reload_analyzers_details._shards.total: 1 } + - match: { reload_analyzers_details.reload_details.0.index: "my_index" } + - match: { reload_analyzers_details.reload_details.0.reloaded_analyzers.0 : "my_analyzer" } + + # Confirm that the index analyzers are reloaded + - do: + search: + index: my_index + body: + query: + match: + my_field: + query: salute + - match: { hits.total.value: 1 } + + - do: + search: + index: my_index + body: + query: + match: + my_field: + query: ciao + - match: { hits.total.value: 1 } + + # Delete the synonyms set and confirm failed reload analyzers details + - do: + synonyms.delete: + synonyms_set: set1 + + - match: + acknowledged: true + - gte: { reload_analyzers_details._shards.failed: 1 } + - match: { reload_analyzers_details._shards.failures.0.index: "my_index" } + - match: { reload_analyzers_details._shards.failures.0.reason.reason: "Synonym set [set1] not found" } + + # Confirm that the index analyzers are not reloaded and still using old synonyms + - do: + search: + index: my_index + body: + query: + match: + my_field: + query: salute + - match: { hits.total.value: 1 } + + - do: + search: + index: my_index + body: + query: + match: + my_field: + query: ciao + - match: { hits.total.value: 1 } --- "Fail loading synonyms from index if synonyms_set doesn't exist": diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/10_synonyms_put.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/10_synonyms_put.yml index 68ef7dee077f4..028af6ea458ac 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/10_synonyms_put.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/10_synonyms_put.yml @@ -13,6 +13,8 @@ id: "test-id" - match: { result: "created" } + - match: { reload_analyzers_details._shards.total: 0 } + - length: { reload_analyzers_details.reload_details: 0 } - do: synonyms.put: @@ -22,6 +24,8 @@ - synonyms: "other, another" - match: { result: "updated" } + - match: { reload_analyzers_details._shards.total: 0 } + - length: { reload_analyzers_details.reload_details: 0 } --- "Validation fails tests": diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/30_synonyms_delete.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/30_synonyms_delete.yml index 841ef74ab3e6a..bd6a86124da59 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/30_synonyms_delete.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/30_synonyms_delete.yml @@ -20,6 +20,8 @@ setup: - match: acknowledged: true + - match: { reload_analyzers_details._shards.total: 0 } + - length: { reload_analyzers_details.reload_details: 0 } - do: catch: missing diff --git a/server/src/main/java/org/elasticsearch/action/synonyms/DeleteSynonymsAction.java b/server/src/main/java/org/elasticsearch/action/synonyms/DeleteSynonymsAction.java index 11e99dab6066b..8a400fb593e14 100644 --- a/server/src/main/java/org/elasticsearch/action/synonyms/DeleteSynonymsAction.java +++ b/server/src/main/java/org/elasticsearch/action/synonyms/DeleteSynonymsAction.java @@ -11,21 +11,28 @@ import org.apache.logging.log4j.util.Strings; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionType; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContentBuilder; import java.io.IOException; import java.util.Objects; -public class DeleteSynonymsAction extends ActionType { +import static org.elasticsearch.action.support.master.AcknowledgedResponse.ACKNOWLEDGED_KEY; + +public class DeleteSynonymsAction extends ActionType { public static final DeleteSynonymsAction INSTANCE = new DeleteSynonymsAction(); public static final String NAME = "cluster:admin/synonyms/delete"; public DeleteSynonymsAction() { - super(NAME, AcknowledgedResponse::readFrom); + super(NAME, Response::new); } public static class Request extends ActionRequest { @@ -71,4 +78,56 @@ public int hashCode() { return Objects.hash(synonymsSetId); } } + + public static class Response extends ActionResponse implements ToXContentObject { + + private final AcknowledgedResponse acknowledgedResponse; + private final ReloadAnalyzersResponse reloadAnalyzersResponse; + + public Response(StreamInput in) throws IOException { + super(in); + this.acknowledgedResponse = AcknowledgedResponse.readFrom(in); + this.reloadAnalyzersResponse = new ReloadAnalyzersResponse(in); + } + + public Response(AcknowledgedResponse acknowledgedResponse, ReloadAnalyzersResponse reloadAnalyzersResponse) { + super(); + Objects.requireNonNull(acknowledgedResponse, "Acknowledge response must not be null"); + Objects.requireNonNull(reloadAnalyzersResponse, "Reload analyzers response must not be null"); + this.acknowledgedResponse = acknowledgedResponse; + this.reloadAnalyzersResponse = reloadAnalyzersResponse; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + builder.startObject(); + { + builder.field(ACKNOWLEDGED_KEY, acknowledgedResponse.isAcknowledged()); + builder.field("reload_analyzers_details"); + reloadAnalyzersResponse.toXContent(builder, params); + } + builder.endObject(); + return builder; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + acknowledgedResponse.writeTo(out); + reloadAnalyzersResponse.writeTo(out); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Response response = (Response) o; + return Objects.equals(acknowledgedResponse, response.acknowledgedResponse) + && Objects.equals(reloadAnalyzersResponse, response.reloadAnalyzersResponse); + } + + @Override + public int hashCode() { + return Objects.hash(acknowledgedResponse, reloadAnalyzersResponse); + } + } } diff --git a/server/src/main/java/org/elasticsearch/action/synonyms/PutSynonymsAction.java b/server/src/main/java/org/elasticsearch/action/synonyms/PutSynonymsAction.java index 18dd7eb381ea5..d9d1219ca94db 100644 --- a/server/src/main/java/org/elasticsearch/action/synonyms/PutSynonymsAction.java +++ b/server/src/main/java/org/elasticsearch/action/synonyms/PutSynonymsAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionType; import org.elasticsearch.action.ValidateActions; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; @@ -22,6 +23,7 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.synonyms.SynonymRule; import org.elasticsearch.synonyms.SynonymsManagementAPIService; +import org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContent; @@ -121,36 +123,42 @@ public int hashCode() { public static class Response extends ActionResponse implements StatusToXContentObject { - private final SynonymsManagementAPIService.UpdateSynonymsResult result; + private final UpdateSynonymsResultStatus updateStatus; + private final ReloadAnalyzersResponse reloadAnalyzersResponse; public Response(StreamInput in) throws IOException { super(in); - this.result = in.readEnum((SynonymsManagementAPIService.UpdateSynonymsResult.class)); + this.updateStatus = in.readEnum(UpdateSynonymsResultStatus.class); + this.reloadAnalyzersResponse = new ReloadAnalyzersResponse(in); } - public Response(SynonymsManagementAPIService.UpdateSynonymsResult result) { + public Response(UpdateSynonymsResultStatus updateStatus, ReloadAnalyzersResponse reloadAnalyzersResponse) { super(); - Objects.requireNonNull(result, "Result must not be null"); - this.result = result; + Objects.requireNonNull(updateStatus, "Update status must not be null"); + Objects.requireNonNull(updateStatus, "Reload analyzers response must not be null"); + this.updateStatus = updateStatus; + this.reloadAnalyzersResponse = reloadAnalyzersResponse; } @Override public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { builder.startObject(); - builder.field("result", result.name().toLowerCase(Locale.ENGLISH)); + builder.field("result", updateStatus.name().toLowerCase(Locale.ENGLISH)); + builder.field("reload_analyzers_details"); + reloadAnalyzersResponse.toXContent(builder, params); builder.endObject(); - return builder; } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeEnum(result); + out.writeEnum(updateStatus); + reloadAnalyzersResponse.writeTo(out); } @Override public RestStatus status() { - return switch (result) { + return switch (updateStatus) { case CREATED -> RestStatus.CREATED; default -> RestStatus.OK; }; @@ -161,12 +169,12 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Response response = (Response) o; - return result == response.result; + return updateStatus == response.updateStatus && Objects.equals(reloadAnalyzersResponse, response.reloadAnalyzersResponse); } @Override public int hashCode() { - return Objects.hash(result); + return Objects.hash(updateStatus, reloadAnalyzersResponse); } } } diff --git a/server/src/main/java/org/elasticsearch/action/synonyms/TransportDeleteSynonymsAction.java b/server/src/main/java/org/elasticsearch/action/synonyms/TransportDeleteSynonymsAction.java index 5eae4877484ad..2e385979c2864 100644 --- a/server/src/main/java/org/elasticsearch/action/synonyms/TransportDeleteSynonymsAction.java +++ b/server/src/main/java/org/elasticsearch/action/synonyms/TransportDeleteSynonymsAction.java @@ -11,14 +11,13 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; -import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.synonyms.SynonymsManagementAPIService; import org.elasticsearch.tasks.Task; import org.elasticsearch.transport.TransportService; -public class TransportDeleteSynonymsAction extends HandledTransportAction { +public class TransportDeleteSynonymsAction extends HandledTransportAction { private final SynonymsManagementAPIService synonymsManagementAPIService; @@ -30,7 +29,10 @@ public TransportDeleteSynonymsAction(TransportService transportService, ActionFi } @Override - protected void doExecute(Task task, DeleteSynonymsAction.Request request, ActionListener listener) { - synonymsManagementAPIService.deleteSynonymsSet(request.synonymsSetId(), listener); + protected void doExecute(Task task, DeleteSynonymsAction.Request request, ActionListener listener) { + synonymsManagementAPIService.deleteSynonymsSet( + request.synonymsSetId(), + listener.map(dr -> new DeleteSynonymsAction.Response(dr.acknowledgedResponse(), dr.reloadAnalyzersResponse())) + ); } } diff --git a/server/src/main/java/org/elasticsearch/action/synonyms/TransportPutSynonymsAction.java b/server/src/main/java/org/elasticsearch/action/synonyms/TransportPutSynonymsAction.java index 28682ec7ec384..b60ed074133dc 100644 --- a/server/src/main/java/org/elasticsearch/action/synonyms/TransportPutSynonymsAction.java +++ b/server/src/main/java/org/elasticsearch/action/synonyms/TransportPutSynonymsAction.java @@ -33,7 +33,7 @@ protected void doExecute(Task task, PutSynonymsAction.Request request, ActionLis synonymsManagementAPIService.putSynonymsSet( request.synonymsSetId(), request.synonymRules(), - listener.map(PutSynonymsAction.Response::new) + listener.map(ur -> new PutSynonymsAction.Response(ur.updateStatus(), ur.reloadAnalyzersResponse())) ); } } diff --git a/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java b/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java index 8f1114526e20e..54b0bac74eac6 100644 --- a/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java +++ b/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java @@ -14,6 +14,9 @@ import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.DocWriteRequest; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzerAction; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersRequest; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse; import org.elasticsearch.action.bulk.BulkItemResponse; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.index.IndexRequest; @@ -205,7 +208,7 @@ private static String externalSynonymRuleId(String internalId) { return internalId.substring(index + 1); } - public void putSynonymsSet(String resourceName, SynonymRule[] synonymsSet, ActionListener listener) { + public void putSynonymsSet(String resourceName, SynonymRule[] synonymsSet, ActionListener listener) { deleteSynonymSetRules(resourceName, listener.delegateFailure((deleteByQueryResponseListener, bulkByScrollResponse) -> { boolean created = bulkByScrollResponse.getDeleted() == 0; final List bulkFailures = bulkByScrollResponse.getBulkFailures(); @@ -243,8 +246,20 @@ public void putSynonymsSet(String resourceName, SynonymRule[] synonymsSet, Actio bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) .execute(deleteByQueryResponseListener.delegateFailure((bulkResponseListener, bulkResponse) -> { if (bulkResponse.hasFailures() == false) { - UpdateSynonymsResult result = created ? UpdateSynonymsResult.CREATED : UpdateSynonymsResult.UPDATED; - bulkResponseListener.onResponse(result); + UpdateSynonymsResultStatus updateSynonymsResultStatus = created + ? UpdateSynonymsResultStatus.CREATED + : UpdateSynonymsResultStatus.UPDATED; + + // auto-reload all reloadable analyzers (currently only those that use updateable synonym or keyword_marker filters) + // TODO: reload only those analyzers that use this synonymsSet + ReloadAnalyzersRequest reloadAnalyzersRequest = new ReloadAnalyzersRequest("*"); + client.execute( + ReloadAnalyzerAction.INSTANCE, + reloadAnalyzersRequest, + bulkResponseListener.delegateFailure((reloadResponseListener, reloadResponse) -> { + reloadResponseListener.onResponse(new UpdateSynonymsSetResult(updateSynonymsResultStatus, reloadResponse)); + }) + ); } else { bulkResponseListener.onFailure( new ElasticsearchException("Couldn't update synonyms: " + bulkResponse.buildFailureMessage()) @@ -264,7 +279,7 @@ private void deleteSynonymSetRules(String resourceName, ActionListener listener) { + public void deleteSynonymsSet(String resourceName, ActionListener listener) { deleteSynonymSetRules(resourceName, listener.delegateFailure((l, bulkByScrollResponse) -> { if (bulkByScrollResponse.getDeleted() == 0) { // If nothing was deleted, synonym set did not exist @@ -282,7 +297,16 @@ public void deleteSynonymsSet(String resourceName, ActionListener { + reloadResponseListener.onResponse(new DeleteSynonymsSetResult(AcknowledgedResponse.of(true), reloadResponse)); + }) + ); })); } @@ -305,8 +329,12 @@ static Settings settings() { .build(); } - public enum UpdateSynonymsResult { + public enum UpdateSynonymsResultStatus { CREATED, UPDATED } + + public record UpdateSynonymsSetResult(UpdateSynonymsResultStatus updateStatus, ReloadAnalyzersResponse reloadAnalyzersResponse) {} + + public record DeleteSynonymsSetResult(AcknowledgedResponse acknowledgedResponse, ReloadAnalyzersResponse reloadAnalyzersResponse) {} } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/analyze/ReloadAnalyzersResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/analyze/ReloadAnalyzersResponseTests.java index ab34f49cfd5a9..a6524932dd775 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/analyze/ReloadAnalyzersResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/analyze/ReloadAnalyzersResponseTests.java @@ -32,6 +32,11 @@ protected ReloadAnalyzersResponse createTestInstance( int failedShards, List failures ) { + Map reloadedIndicesDetails = createRandomReloadDetails(); + return new ReloadAnalyzersResponse(totalShards, successfulShards, failedShards, failures, reloadedIndicesDetails); + } + + public static Map createRandomReloadDetails() { Map reloadedIndicesDetails = new HashMap<>(); int randomIndices = randomIntBetween(0, 5); for (int i = 0; i < randomIndices; i++) { @@ -40,7 +45,7 @@ protected ReloadAnalyzersResponse createTestInstance( Set reloadedAnalyzers = new HashSet<>(Arrays.asList(generateRandomStringArray(5, 5, false, true))); reloadedIndicesDetails.put(name, new ReloadAnalyzersResponse.ReloadDetails(name, reloadedIndicesNodes, reloadedAnalyzers)); } - return new ReloadAnalyzersResponse(totalShards, successfulShards, failedShards, failures, reloadedIndicesDetails); + return reloadedIndicesDetails; } @Override diff --git a/server/src/test/java/org/elasticsearch/action/synonyms/DeleteSynonymsActionResponseSerializingTests.java b/server/src/test/java/org/elasticsearch/action/synonyms/DeleteSynonymsActionResponseSerializingTests.java new file mode 100644 index 0000000000000..505882bc51821 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/synonyms/DeleteSynonymsActionResponseSerializingTests.java @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.action.synonyms; + +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponseTests; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.test.AbstractWireSerializingTestCase; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +public class DeleteSynonymsActionResponseSerializingTests extends AbstractWireSerializingTestCase { + + @Override + protected Writeable.Reader instanceReader() { + return DeleteSynonymsAction.Response::new; + } + + @Override + protected DeleteSynonymsAction.Response createTestInstance() { + Map reloadedIndicesDetails = ReloadAnalyzersResponseTests + .createRandomReloadDetails(); + AcknowledgedResponse acknowledgedResponse = AcknowledgedResponse.of(randomBoolean()); + return new DeleteSynonymsAction.Response( + acknowledgedResponse, + new ReloadAnalyzersResponse(10, 10, 0, null, reloadedIndicesDetails) + ); + } + + @Override + protected DeleteSynonymsAction.Response mutateInstance(DeleteSynonymsAction.Response instance) throws IOException { + return randomValueOtherThan(instance, this::createTestInstance); + } + + public void testToXContent() throws IOException { + Map reloadedIndicesNodes = Collections.singletonMap( + "index", + new ReloadAnalyzersResponse.ReloadDetails("index", Collections.singleton("nodeId"), Collections.singleton("my_analyzer")) + ); + ReloadAnalyzersResponse reloadAnalyzersResponse = new ReloadAnalyzersResponse(10, 5, 0, null, reloadedIndicesNodes); + AcknowledgedResponse acknowledgedResponse = AcknowledgedResponse.of(true); + DeleteSynonymsAction.Response response = new DeleteSynonymsAction.Response(acknowledgedResponse, reloadAnalyzersResponse); + + String output = Strings.toString(response); + assertEquals(XContentHelper.stripWhitespace(""" + { + "acknowledged": true, + "reload_analyzers_details": { + "_shards": { + "total": 10, + "successful": 5, + "failed": 0 + }, + "reload_details": [ + { + "index": "index", + "reloaded_analyzers": [ "my_analyzer" ], + "reloaded_node_ids": [ "nodeId" ] + } + ] + } + }"""), output); + } +} diff --git a/server/src/test/java/org/elasticsearch/action/synonyms/PutSynonymsActionResponseSerializingTests.java b/server/src/test/java/org/elasticsearch/action/synonyms/PutSynonymsActionResponseSerializingTests.java index 36d6aa3112cbd..43ecd6093e87c 100644 --- a/server/src/test/java/org/elasticsearch/action/synonyms/PutSynonymsActionResponseSerializingTests.java +++ b/server/src/test/java/org/elasticsearch/action/synonyms/PutSynonymsActionResponseSerializingTests.java @@ -8,13 +8,20 @@ package org.elasticsearch.action.synonyms; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse; +import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponseTests; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus; import org.elasticsearch.test.AbstractWireSerializingTestCase; import java.io.IOException; +import java.util.Collections; +import java.util.Map; -import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResult.CREATED; -import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResult.UPDATED; +import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus.CREATED; +import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus.UPDATED; public class PutSynonymsActionResponseSerializingTests extends AbstractWireSerializingTestCase { @@ -25,11 +32,43 @@ protected Writeable.Reader instanceReader() { @Override protected PutSynonymsAction.Response createTestInstance() { - return new PutSynonymsAction.Response(randomBoolean() ? CREATED : UPDATED); + UpdateSynonymsResultStatus updateStatus = randomFrom(CREATED, UPDATED); + Map reloadedIndicesDetails = ReloadAnalyzersResponseTests + .createRandomReloadDetails(); + return new PutSynonymsAction.Response(updateStatus, new ReloadAnalyzersResponse(10, 10, 0, null, reloadedIndicesDetails)); } @Override protected PutSynonymsAction.Response mutateInstance(PutSynonymsAction.Response instance) throws IOException { return randomValueOtherThan(instance, this::createTestInstance); } + + public void testToXContent() throws IOException { + Map reloadedIndicesNodes = Collections.singletonMap( + "index", + new ReloadAnalyzersResponse.ReloadDetails("index", Collections.singleton("nodeId"), Collections.singleton("my_analyzer")) + ); + ReloadAnalyzersResponse reloadAnalyzersResponse = new ReloadAnalyzersResponse(10, 5, 0, null, reloadedIndicesNodes); + PutSynonymsAction.Response response = new PutSynonymsAction.Response(CREATED, reloadAnalyzersResponse); + + String output = Strings.toString(response); + assertEquals(XContentHelper.stripWhitespace(""" + { + "result": "created", + "reload_analyzers_details": { + "_shards": { + "total": 10, + "successful": 5, + "failed": 0 + }, + "reload_details": [ + { + "index": "index", + "reloaded_analyzers": [ "my_analyzer" ], + "reloaded_node_ids": [ "nodeId" ] + } + ] + } + }"""), output); + } }