From 4a74bfa8f78c993536a7f3c818d7c4c78ce13afa Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 14 Nov 2018 10:25:40 +0100 Subject: [PATCH 01/10] HLRC: Add get watch API This changes adds the support for the get watch API in the high level rest client. --- .../elasticsearch/client/WatcherClient.java | 30 ++ .../client/WatcherRequestConverters.java | 16 +- .../client/watcher/ActionStatus.java | 2 +- .../client/watcher/GetWatchRequest.java | 54 ++++ .../client/watcher/GetWatchResponse.java | 140 +++++++++ .../client/watcher/WatchStatus.java | 4 + .../client/WatcherRequestConvertersTests.java | 11 + .../documentation/WatcherDocumentationIT.java | 44 +++ .../client/watcher/GetWatchResponseTests.java | 285 ++++++++++++++++++ .../watcher/WatchRequestValidationTests.java | 6 + .../high-level/supported-apis.asciidoc | 2 + .../high-level/watcher/get-watch.asciidoc | 56 ++++ .../actions/get/GetWatchResponse.java | 6 +- .../actions/get/TransportGetWatchAction.java | 3 +- 14 files changed, 651 insertions(+), 8 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java create mode 100644 docs/java-rest/high-level/watcher/get-watch.asciidoc diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java index c06493aea7381..ed0043c801c7b 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java @@ -26,6 +26,8 @@ import org.elasticsearch.client.watcher.ActivateWatchResponse; import org.elasticsearch.client.watcher.AckWatchRequest; import org.elasticsearch.client.watcher.AckWatchResponse; +import org.elasticsearch.client.watcher.GetWatchRequest; +import org.elasticsearch.client.watcher.GetWatchResponse; import org.elasticsearch.client.watcher.StartWatchServiceRequest; import org.elasticsearch.client.watcher.StopWatchServiceRequest; import org.elasticsearch.client.watcher.DeleteWatchRequest; @@ -129,6 +131,34 @@ public void putWatchAsync(PutWatchRequest request, RequestOptions options, PutWatchResponse::fromXContent, listener, emptySet()); } + /** + * Gets a watch from the cluster + * See + * the docs for more. + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + */ + public GetWatchResponse getWatch(GetWatchRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, WatcherRequestConverters::getWatch, options, + GetWatchResponse::fromXContent, emptySet()); + } + + /** + * Asynchronously gets a watch into the cluster + * See + * the docs for more. + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + */ + public void getWatchAsync(GetWatchRequest request, RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, WatcherRequestConverters::getWatch, options, + GetWatchResponse::fromXContent, listener, emptySet()); + } + /** * Deactivate an existing watch * See diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java index a017779495b9f..efaa597d766b3 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java @@ -28,12 +28,13 @@ import org.elasticsearch.client.watcher.DeactivateWatchRequest; import org.elasticsearch.client.watcher.ActivateWatchRequest; import org.elasticsearch.client.watcher.AckWatchRequest; +import org.elasticsearch.client.watcher.DeleteWatchRequest; +import org.elasticsearch.client.watcher.GetWatchRequest; +import org.elasticsearch.client.watcher.PutWatchRequest; import org.elasticsearch.client.watcher.StartWatchServiceRequest; import org.elasticsearch.client.watcher.StopWatchServiceRequest; import org.elasticsearch.client.watcher.WatcherStatsRequest; import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.client.watcher.DeleteWatchRequest; -import org.elasticsearch.client.watcher.PutWatchRequest; final class WatcherRequestConverters { @@ -76,6 +77,17 @@ static Request putWatch(PutWatchRequest putWatchRequest) { return request; } + + static Request getWatch(GetWatchRequest getWatchRequest) { + String endpoint = new RequestConverters.EndpointBuilder() + .addPathPartAsIs("_xpack", "watcher", "watch") + .addPathPart(getWatchRequest.getId()) + .build(); + + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + return request; + } + static Request deactivateWatch(DeactivateWatchRequest deactivateWatchRequest) { String endpoint = new RequestConverters.EndpointBuilder() .addPathPartAsIs("_xpack") diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java index ec413c10fa728..1a838afde85aa 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java @@ -193,7 +193,7 @@ public static Execution failure(DateTime timestamp, String reason) { private final boolean successful; private final String reason; - private Execution(DateTime timestamp, boolean successful, String reason) { + Execution(DateTime timestamp, boolean successful, String reason) { this.timestamp = timestamp.toDateTime(DateTimeZone.UTC); this.successful = successful; this.reason = reason; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchRequest.java new file mode 100644 index 0000000000000..fae2d31a256be --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchRequest.java @@ -0,0 +1,54 @@ +/* + * 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.client.watcher; + +import org.elasticsearch.client.Validatable; +import org.elasticsearch.client.ValidationException; + +/** + * The request to get the watch by name (id) + */ +public final class GetWatchRequest implements Validatable { + + private final String id; + + public GetWatchRequest(String watchId) { + validateId(watchId); + this.id = watchId; + } + + private void validateId(String id) { + ValidationException exception = new ValidationException(); + if (id == null) { + exception.addValidationError("watch id is missing"); + } else if (PutWatchRequest.isValidId(id) == false) { + exception.addValidationError("watch id contains whitespace"); + } + if (exception.validationErrors().isEmpty() == false) { + throw exception; + } + } + + /** + * @return The name of the watch to retrieve + */ + public String getId() { + return id; + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java new file mode 100644 index 0000000000000..c437378e470bd --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -0,0 +1,140 @@ +/* + * 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.client.watcher; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; + +import java.io.IOException; +import java.util.Objects; + +public class GetWatchResponse { + private final String id; + private final long version; + private final WatchStatus status; + + private final BytesReference source; + private final XContentType xContentType; + + public GetWatchResponse(String id) { + this(id, Versions.NOT_FOUND, null, null, null); + } + + public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source, XContentType xContentType) { + this.id = id; + this.version = version; + this.status = status; + this.source = source; + this.xContentType = xContentType; + } + + public String getId() { + return id; + } + + public long getVersion() { + return version; + } + + public boolean isFound() { + return version != Versions.NOT_FOUND; + } + + public WatchStatus getStatus() { + return status; + } + + public BytesReference getSource() { + return source; + } + + public XContentType getContentType() { + return xContentType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GetWatchResponse that = (GetWatchResponse) o; + return version == that.version && + Objects.equals(id, that.id) && + Objects.equals(status, that.status) && + Objects.equals(source, that.source) && + xContentType == that.xContentType; + } + + @Override + public int hashCode() { + return Objects.hash(id, status, source, xContentType, version); + } + + private static final ParseField ID_FIELD = new ParseField("_id"); + private static final ParseField FOUND_FIELD = new ParseField("found"); + private static final ParseField VERSION_FIELD = new ParseField("_version"); + private static final ParseField STATUS_FIELD = new ParseField("status"); + private static final ParseField WATCH_FIELD = new ParseField("watch"); + + private static ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("get_watch_response", true, + a -> { + boolean isFound = (boolean) a[1]; + if (isFound) { + XContentSource source = (XContentSource) a[4]; + return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source.source, source.contentType); + } else { + return new GetWatchResponse((String) a[0]); + } + }); + + static { + PARSER.declareString(ConstructingObjectParser.constructorArg(), ID_FIELD); + PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), FOUND_FIELD); + PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), VERSION_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), + (parser, context) -> WatchStatus.parse(parser), STATUS_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), + (parser, context) -> { + try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) { + builder.copyCurrentStructure(parser); + BytesReference ref = BytesReference.bytes(builder); + return new XContentSource(ref, parser.contentType()); + } + }, WATCH_FIELD); + } + + public static GetWatchResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } + + private static class XContentSource { + final BytesReference source; + final XContentType contentType; + + private XContentSource(BytesReference source, XContentType contentType) { + this.source = source; + this.contentType = contentType; + } + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java index 04b747c03635a..035fdeedc0de7 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java @@ -79,6 +79,10 @@ public ActionStatus actionStatus(String actionId) { return actions.get(actionId); } + Map getActions() { + return actions; + } + public long version() { return version; } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java index 2712dbc0438db..ff7050fd67ce7 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java @@ -28,6 +28,7 @@ import org.elasticsearch.client.watcher.DeactivateWatchRequest; import org.elasticsearch.client.watcher.DeleteWatchRequest; import org.elasticsearch.client.watcher.PutWatchRequest; +import org.elasticsearch.client.watcher.GetWatchRequest; import org.elasticsearch.client.watcher.StartWatchServiceRequest; import org.elasticsearch.client.watcher.StopWatchServiceRequest; import org.elasticsearch.client.watcher.WatcherStatsRequest; @@ -91,6 +92,16 @@ public void testPutWatch() throws Exception { assertThat(bos.toString("UTF-8"), is(body)); } + public void testGetWatch() throws Exception { + String watchId = randomAlphaOfLength(10); + GetWatchRequest getWatchRequest = new GetWatchRequest(watchId); + + Request request = WatcherRequestConverters.getWatch(getWatchRequest); + assertEquals(HttpGet.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/watcher/watch/" + watchId, request.getEndpoint()); + assertThat(request.getEntity(), nullValue()); + } + public void testDeactivateWatch() { String watchId = randomAlphaOfLength(10); DeactivateWatchRequest deactivateWatchRequest = new DeactivateWatchRequest(watchId); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java index 74562a1d17fd0..4fd4c86575f20 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java @@ -34,6 +34,8 @@ import org.elasticsearch.client.watcher.ActionStatus.AckStatus; import org.elasticsearch.client.watcher.DeactivateWatchRequest; import org.elasticsearch.client.watcher.DeactivateWatchResponse; +import org.elasticsearch.client.watcher.GetWatchRequest; +import org.elasticsearch.client.watcher.GetWatchResponse; import org.elasticsearch.client.watcher.StartWatchServiceRequest; import org.elasticsearch.client.watcher.StopWatchServiceRequest; import org.elasticsearch.client.watcher.WatchStatus; @@ -197,6 +199,48 @@ public void onFailure(Exception e) { assertTrue(latch.await(30L, TimeUnit.SECONDS)); } + { + //tag::x-pack-get-watch-execute + GetWatchRequest request = new GetWatchRequest("my_watch_id"); + GetWatchResponse response = client.watcher().getWatch(request, RequestOptions.DEFAULT); + //end::x-pack-get-watch-execute + + //tag::x-pack-get-watch-response + String watchId = response.getId(); // <1> + boolean found = response.isFound(); // <2> + long version = response.getVersion(); // <3> + WatchStatus status = response.getStatus(); // <4> + BytesReference source = response.getSource(); // <5> + //end::x-pack-get-watch-response + } + + { + GetWatchRequest request = new GetWatchRequest("my_other_watch_id"); + // tag::x-pack-get-watch-execute-listener + ActionListener listener = new ActionListener() { + @Override + public void onResponse(GetWatchResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::x-pack-get-watch-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::x-pack-get-watch-execute-async + client.watcher().getWatchAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::x-pack-get-watch-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + { //tag::x-pack-delete-watch-execute DeleteWatchRequest request = new DeleteWatchRequest("my_watch_id"); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java new file mode 100644 index 0000000000000..4ba52f4d84b14 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java @@ -0,0 +1,285 @@ +/* + * 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.client.watcher; + +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.DeprecationHandler; +import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; +import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContent; +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.test.AbstractXContentTestCase; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +import static org.elasticsearch.index.mapper.DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER; + +public class GetWatchResponseTests extends AbstractXContentTestCase { + /** + * A wrapper for {@link GetWatchResponse} that is able to serialize the response with {@link ToXContent}. + */ + static class ResponseWrapper implements ToXContentObject { + final NamedXContentRegistry xContentRegistry; + final GetWatchResponse response; + + ResponseWrapper(NamedXContentRegistry xContentRegistry, GetWatchResponse response) { + this.xContentRegistry = xContentRegistry; + this.response = response; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return GetWatchResponseTests.toXContent(xContentRegistry, response, builder); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResponseWrapper that = (ResponseWrapper) o; + return Objects.equals(response, that.response); + } + + @Override + public int hashCode() { + return Objects.hash(response); + } + } + + @Override + protected ResponseWrapper createTestInstance() { + String id = randomAlphaOfLength(10); + if (rarely()) { + return new ResponseWrapper(xContentRegistry(), new GetWatchResponse(id)); + } + long version = randomLongBetween(-1, Long.MAX_VALUE); + WatchStatus status = randomWatchStatus(); + BytesReference source = simpleWatch(); + ResponseWrapper wrapper = + new ResponseWrapper(xContentRegistry(), new GetWatchResponse(id, version, status, source, XContentType.JSON)); + return wrapper; + } + + @Override + protected ResponseWrapper doParseInstance(XContentParser parser) throws IOException { + return new ResponseWrapper(xContentRegistry(), GetWatchResponse.fromXContent(parser)); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } + + static String[] SHUFFLE_FIELDS_EXCEPTION = new String[] { "watch" }; + @Override + protected String[] getShuffleFieldsExceptions() { + return SHUFFLE_FIELDS_EXCEPTION; + } + + @Override + protected void assertEqualInstances(ResponseWrapper expectedInstance, ResponseWrapper newInstance) { + if (newInstance.response.isFound() && + expectedInstance.response.getContentType() != newInstance.response.getContentType()) { + /** + * The {@link GetWatchResponse#getContentType()} depends on the content type that + * was used to serialize the main object so we use the same content type than the + * expectedInstance to translate the watch of the newInstance. + */ + XContent from = XContentFactory.xContent(newInstance.response.getContentType()); + XContent to = XContentFactory.xContent(expectedInstance.response.getContentType()); + final BytesReference source; + // It is safe to use EMPTY here because this never uses namedObject + try (InputStream stream = newInstance.response.getSource().streamInput(); + XContentParser parser = XContentFactory.xContent(from.type()).createParser(NamedXContentRegistry.EMPTY, + DeprecationHandler.THROW_UNSUPPORTED_OPERATION, stream)) { + parser.nextToken(); + XContentBuilder builder = XContentFactory.contentBuilder(to.type()); + builder.copyCurrentStructure(parser); + source = BytesReference.bytes(builder); + } catch (IOException e) { + throw new AssertionError(e); + } + newInstance = new ResponseWrapper(xContentRegistry(), + new GetWatchResponse(newInstance.response.getId(), newInstance.response.getVersion(), + newInstance.response.getStatus(), source, expectedInstance.response.getContentType())); + } + super.assertEqualInstances(expectedInstance, newInstance); + } + + static XContentBuilder toXContentFragment(ActionStatus.Execution execution, XContentBuilder builder) throws IOException { + builder.field("timestamp").value(DEFAULT_DATE_TIME_FORMATTER.printer().print(execution.timestamp())); + builder.field("successful", execution.successful()); + if (execution.successful() == false) { + builder.field("reason", execution.reason()); + } + return builder; + } + + static XContentBuilder toXContentFragment(ActionStatus.Throttle throttle, XContentBuilder builder) throws IOException { + builder.field("timestamp").value(DEFAULT_DATE_TIME_FORMATTER.printer().print(throttle.timestamp())); + builder.field("reason", throttle.reason()); + return builder; + } + + static XContentBuilder toXContentFragment(ActionStatus.AckStatus status, XContentBuilder builder) throws IOException { + builder.field("timestamp").value(DEFAULT_DATE_TIME_FORMATTER.printer().print(status.timestamp())); + builder.field("state", status.state().name().toLowerCase(Locale.ROOT)); + return builder; + } + + static XContentBuilder toXContentFragment(ActionStatus status, XContentBuilder builder) throws IOException { + builder.startObject("ack"); + toXContentFragment(status.ackStatus(), builder); + builder.endObject(); + if (status.lastExecution() != null) { + builder.startObject("last_execution"); + toXContentFragment(status.lastExecution(), builder); + builder.endObject(); + } + if (status.lastSuccessfulExecution() != null) { + builder.startObject("last_successful_execution"); + toXContentFragment(status.lastSuccessfulExecution(), builder); + builder.endObject(); + } + if (status.lastThrottle() != null) { + builder.startObject("last_throttle"); + toXContentFragment(status.lastThrottle(), builder); + builder.endObject(); + } + return builder; + } + + static XContentBuilder toXContent(WatchStatus status, XContentBuilder builder) throws IOException { + builder.startObject("status"); + if (status.state() != null) { + builder.startObject("state"); + builder.field("active", status.state().isActive()); + builder.field("timestamp", DEFAULT_DATE_TIME_FORMATTER.printer().print(status.state().getTimestamp())); + builder.endObject(); + } + + if (status.lastChecked() != null) { + builder.timeField("last_checked", status.lastChecked()); + } + if (status.lastMetCondition() != null) { + builder.timeField("last_met_condition", status.lastMetCondition()); + } + builder.startObject("actions"); + for (Map.Entry entry :status.getActions().entrySet()) { + builder.startObject(entry.getKey()); + toXContentFragment(entry.getValue(), builder); + builder.endObject(); + } + builder.endObject(); + builder.field("execution_state", status.getExecutionState().id()); + builder.field("version", status.version()); + return builder.endObject(); + } + + static XContentParser parser(NamedXContentRegistry xContentRegistry, + XContentType contentType, InputStream stream) throws IOException { + return contentType.xContent().createParser(xContentRegistry, LoggingDeprecationHandler.INSTANCE, stream); + } + + static XContentBuilder toXContent(NamedXContentRegistry xContentRegistry, + GetWatchResponse response, XContentBuilder builder) throws IOException { + builder.startObject(); + builder.field("_id", response.getId()); + builder.field("found", response.isFound()); + if (response.isFound() == false) { + return builder.endObject(); + } + builder.field("_version", response.getVersion()); + toXContent(response.getStatus(), builder); + builder.field("watch"); + try (InputStream stream = response.getSource().streamInput(); + XContentParser parser = parser(xContentRegistry, response.getContentType(), stream)) { + parser.nextToken(); + builder.generator().copyCurrentStructure(parser); + } + return builder.endObject(); + } + + static ActionStatus.Execution randomExecution() { + if (randomBoolean()) { + return null; + } + boolean successful = randomBoolean(); + String reason = null; + if (successful == false) { + reason = randomAlphaOfLengthBetween(10, 20); + + } + return new ActionStatus.Execution(DateTime.now(DateTimeZone.UTC), successful, reason); + } + + static WatchStatus randomWatchStatus() { + long version = randomLongBetween(-1, Long.MAX_VALUE); + WatchStatus.State state = rarely() ? null : new WatchStatus.State(randomBoolean(), DateTime.now(DateTimeZone.UTC)); + ExecutionState executionState = randomFrom(ExecutionState.values()); + DateTime lastChecked = rarely() ? null : DateTime.now(DateTimeZone.UTC); + DateTime lastMetCondition = rarely() ? null : DateTime.now(DateTimeZone.UTC); + int size = randomIntBetween(0, 5); + Map actionMap = new HashMap<>(); + for (int i = 0; i < size; i++) { + ActionStatus.AckStatus ack = new ActionStatus.AckStatus(DateTime.now(DateTimeZone.UTC), + randomFrom(ActionStatus.AckStatus.State.values())); + ActionStatus actionStatus = new ActionStatus(ack, randomExecution(), randomExecution(), null); + actionMap.put(randomAlphaOfLength(10), actionStatus); + } + return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actionMap); + } + + static BytesReference simpleWatch() { + XContentBuilder builder = null; + try { + builder = XContentBuilder.builder(XContentType.JSON.xContent()); + builder.startObject() + .startObject("trigger") + .startObject("schedule") + .field("interval", "10h") + .endObject() + .endObject() + .startObject("input") + .startObject("none") + .endObject() + .endObject() + .startObject("actions") + .startObject("logme") + .field("text", "{{ctx.payload}}") + .endObject() + .endObject().endObject(); + return BytesReference.bytes(builder); + } catch (IOException e) { + throw new AssertionError(e); + } + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/WatchRequestValidationTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/WatchRequestValidationTests.java index 1fea3bccb62a7..7f3bc2e0c8931 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/WatchRequestValidationTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/WatchRequestValidationTests.java @@ -91,4 +91,10 @@ public void testPutWatchContentNull() { () -> new PutWatchRequest("foo", BytesArray.EMPTY, null)); assertThat(exception.getMessage(), is("request body is missing")); } + + public void testGetWatchInvalidWatchId() { + ValidationException e = expectThrows(ValidationException.class, + () -> new GetWatchRequest("id with whitespaces")); + assertThat(e.validationErrors(), hasItem("watch id contains whitespace")); + } } diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 9f3674e224b83..4b80a77373d9b 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -373,6 +373,7 @@ The Java High Level REST Client supports the following Watcher APIs: * <<{upid}-start-watch-service>> * <<{upid}-stop-watch-service>> * <> +* <> * <> * <> * <<{upid}-ack-watch>> @@ -382,6 +383,7 @@ The Java High Level REST Client supports the following Watcher APIs: include::watcher/start-watch-service.asciidoc[] include::watcher/stop-watch-service.asciidoc[] include::watcher/put-watch.asciidoc[] +include::watcher/get-watch.asciidoc[] include::watcher/delete-watch.asciidoc[] include::watcher/ack-watch.asciidoc[] include::watcher/deactivate-watch.asciidoc[] diff --git a/docs/java-rest/high-level/watcher/get-watch.asciidoc b/docs/java-rest/high-level/watcher/get-watch.asciidoc new file mode 100644 index 0000000000000..30a4acf3ac175 --- /dev/null +++ b/docs/java-rest/high-level/watcher/get-watch.asciidoc @@ -0,0 +1,56 @@ +[[java-rest-high-x-pack-watcher-get-watch]] +=== Get Watch API + +[[java-rest-high-x-pack-watcher-get-watch-execution]] +==== Execution + +A watch can be retrieved as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute] +-------------------------------------------------- + + +[[java-rest-high-x-pack-watcher-get-watch-response]] +==== Response + +The returned `GetWatchResponse` contains `id`, +, `version`, `status` and `source` information. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-response] +-------------------------------------------------- +<1> `_id`, id of the watch +<2> `found` is a boolean indicating whether the watch was found +<2> `_version` returns the version of the watch +<3> `status` contains status of the watch +<4> `source` the source of the watch + +[[java-rest-high-x-pack-watcher-put-watch-async]] +==== Asynchronous Execution + +This request can be executed asynchronously: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute-async] +-------------------------------------------------- +<1> The `GetWatchRequest` to execute and the `ActionListener` to use when +the execution completes + +The asynchronous method does not block and returns immediately. Once it is +completed the `ActionListener` is called back using the `onResponse` method +if the execution successfully completed or using the `onFailure` method if +it failed. + +A typical listener for `GetWatchResponse` looks like: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute-listener] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java index 7b94b446ffefa..ca7025e72ad22 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java @@ -6,11 +6,9 @@ package org.elasticsearch.xpack.core.watcher.transport.actions.get; import org.elasticsearch.action.ActionResponse; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.lucene.uid.Versions; -import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.core.watcher.watch.WatchStatus; @@ -40,11 +38,11 @@ public GetWatchResponse(String id) { /** * ctor for found watch */ - public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source, XContentType contentType) { + public GetWatchResponse(String id, long version, WatchStatus status, XContentSource source) { this.id = id; this.status = status; this.found = true; - this.source = new XContentSource(source, contentType); + this.source = source; this.version = version; } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/get/TransportGetWatchAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/get/TransportGetWatchAction.java index 2e6a49ac8bdc1..4262703f7db1a 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/get/TransportGetWatchAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/get/TransportGetWatchAction.java @@ -19,6 +19,7 @@ import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.watcher.support.xcontent.WatcherParams; +import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchAction; import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchRequest; import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchResponse; @@ -71,7 +72,7 @@ protected void doExecute(GetWatchRequest request, ActionListener Date: Tue, 27 Nov 2018 20:49:22 +0100 Subject: [PATCH 02/10] iter --- .../client/WatcherRequestConverters.java | 3 +-- .../client/watcher/GetWatchResponse.java | 21 +++++++------------ .../high-level/watcher/get-watch.asciidoc | 11 +++++++--- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java index efaa597d766b3..1da7ef4c617ff 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java @@ -84,8 +84,7 @@ static Request getWatch(GetWatchRequest getWatchRequest) { .addPathPart(getWatchRequest.getId()) .build(); - Request request = new Request(HttpGet.METHOD_NAME, endpoint); - return request; + return new Request(HttpGet.METHOD_NAME, endpoint); } static Request deactivateWatch(DeactivateWatchRequest deactivateWatchRequest) { diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index c437378e470bd..5b3a7b87a09d7 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -37,6 +37,9 @@ public class GetWatchResponse { private final BytesReference source; private final XContentType xContentType; + /** + * Ctor for missing watch + */ public GetWatchResponse(String id) { this(id, Versions.NOT_FOUND, null, null, null); } @@ -101,8 +104,9 @@ public int hashCode() { a -> { boolean isFound = (boolean) a[1]; if (isFound) { - XContentSource source = (XContentSource) a[4]; - return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source.source, source.contentType); + XContentBuilder builder = (XContentBuilder) a[4]; + BytesReference source = BytesReference.bytes(builder); + return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source, builder.contentType()); } else { return new GetWatchResponse((String) a[0]); } @@ -118,8 +122,7 @@ public int hashCode() { (parser, context) -> { try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) { builder.copyCurrentStructure(parser); - BytesReference ref = BytesReference.bytes(builder); - return new XContentSource(ref, parser.contentType()); + return builder; } }, WATCH_FIELD); } @@ -127,14 +130,4 @@ public int hashCode() { public static GetWatchResponse fromXContent(XContentParser parser) throws IOException { return PARSER.parse(parser, null); } - - private static class XContentSource { - final BytesReference source; - final XContentType contentType; - - private XContentSource(BytesReference source, XContentType contentType) { - this.source = source; - this.contentType = contentType; - } - } } diff --git a/docs/java-rest/high-level/watcher/get-watch.asciidoc b/docs/java-rest/high-level/watcher/get-watch.asciidoc index 30a4acf3ac175..6fa10e59a07e9 100644 --- a/docs/java-rest/high-level/watcher/get-watch.asciidoc +++ b/docs/java-rest/high-level/watcher/get-watch.asciidoc @@ -1,7 +1,13 @@ -[[java-rest-high-x-pack-watcher-get-watch]] +-- +:api: get-watch +:request: GetWatchRequest +:response: GetWatchResponse +-- + +[id="{upid}-{api}"] === Get Watch API -[[java-rest-high-x-pack-watcher-get-watch-execution]] +[id="{upid}-{api}-request"] ==== Execution A watch can be retrieved as follows: @@ -11,7 +17,6 @@ A watch can be retrieved as follows: include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute] -------------------------------------------------- - [[java-rest-high-x-pack-watcher-get-watch-response]] ==== Response From 22c0c7a666c1b66e31e4866efc459f7c8831333a Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 28 Nov 2018 14:24:38 +0100 Subject: [PATCH 03/10] address review --- .../client/watcher/GetWatchResponse.java | 20 +- .../client/watcher/WatchStatus.java | 16 +- .../documentation/WatcherDocumentationIT.java | 19 +- .../client/watcher/GetWatchResponseTests.java | 285 ------------------ .../high-level/watcher/get-watch.asciidoc | 37 +-- .../test/AbstractSerializingTestCase.java | 2 + .../AbstractStreamableXContentTestCase.java | 13 +- .../test/AbstractXContentTestCase.java | 80 ++++- .../support/xcontent/XContentSource.java | 14 + .../actions/get/GetWatchResponse.java | 48 ++- .../xpack/core/watcher/watch/WatchStatus.java | 14 +- ...bstractHlrcStreamableXContentTestCase.java | 2 +- .../AbstractHlrcXContentTestCase.java | 2 + .../xpack/watcher/GetWatchResponseTests.java | 175 +++++++++++ 14 files changed, 367 insertions(+), 360 deletions(-) delete mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java create mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index 5b3a7b87a09d7..86f63ad7ddf37 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -35,21 +35,19 @@ public class GetWatchResponse { private final WatchStatus status; private final BytesReference source; - private final XContentType xContentType; /** * Ctor for missing watch */ public GetWatchResponse(String id) { - this(id, Versions.NOT_FOUND, null, null, null); + this(id, Versions.NOT_FOUND, null, null); } - public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source, XContentType xContentType) { + public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source) { this.id = id; this.version = version; this.status = status; this.source = source; - this.xContentType = xContentType; } public String getId() { @@ -73,7 +71,7 @@ public BytesReference getSource() { } public XContentType getContentType() { - return xContentType; + return XContentType.JSON; } @Override @@ -84,13 +82,12 @@ public boolean equals(Object o) { return version == that.version && Objects.equals(id, that.id) && Objects.equals(status, that.status) && - Objects.equals(source, that.source) && - xContentType == that.xContentType; + Objects.equals(source, that.source); } @Override public int hashCode() { - return Objects.hash(id, status, source, xContentType, version); + return Objects.hash(id, status, source, version); } private static final ParseField ID_FIELD = new ParseField("_id"); @@ -104,9 +101,8 @@ public int hashCode() { a -> { boolean isFound = (boolean) a[1]; if (isFound) { - XContentBuilder builder = (XContentBuilder) a[4]; - BytesReference source = BytesReference.bytes(builder); - return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source, builder.contentType()); + BytesReference source = (BytesReference) a[4]; + return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source); } else { return new GetWatchResponse((String) a[0]); } @@ -122,7 +118,7 @@ public int hashCode() { (parser, context) -> { try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) { builder.copyCurrentStructure(parser); - return builder; + return BytesReference.bytes(builder); } }, WATCH_FIELD); } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java index 035fdeedc0de7..bc37dd8de89b1 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java @@ -20,6 +20,7 @@ package org.elasticsearch.client.watcher; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.Nullable; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.XContentParser; import org.joda.time.DateTime; @@ -44,19 +45,22 @@ public class WatchStatus { private final DateTime lastMetCondition; private final long version; private final Map actions; + @Nullable private Map headers; public WatchStatus(long version, State state, ExecutionState executionState, DateTime lastChecked, DateTime lastMetCondition, - Map actions) { + Map actions, + Map headers) { this.version = version; this.lastChecked = lastChecked; this.lastMetCondition = lastMetCondition; this.actions = actions; this.state = state; this.executionState = executionState; + this.headers = headers; } public State state() { @@ -79,7 +83,7 @@ public ActionStatus actionStatus(String actionId) { return actions.get(actionId); } - Map getActions() { + public Map getActions() { return actions; } @@ -116,6 +120,7 @@ public static WatchStatus parse(XContentParser parser) throws IOException { DateTime lastChecked = null; DateTime lastMetCondition = null; Map actions = null; + Map headers = null; long version = -1; ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser::getTokenLocation); @@ -176,13 +181,17 @@ public static WatchStatus parse(XContentParser parser) throws IOException { throw new ElasticsearchParseException("could not parse watch status. expecting field [{}] to be an object, " + "found [{}] instead", currentFieldName, token); } + } else if (Field.HEADERS.match(currentFieldName, parser.getDeprecationHandler())) { + if (token == XContentParser.Token.START_OBJECT) { + headers = parser.mapStrings(); + } } else { parser.skipChildren(); } } actions = actions == null ? emptyMap() : unmodifiableMap(actions); - return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actions); + return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actions, headers); } public static class State { @@ -233,5 +242,6 @@ public interface Field { ParseField ACTIONS = new ParseField("actions"); ParseField VERSION = new ParseField("version"); ParseField EXECUTION_STATE = new ParseField("execution_state"); + ParseField HEADERS = new ParseField("headers"); } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java index 4fd4c86575f20..03dfc2ea7e088 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java @@ -200,23 +200,26 @@ public void onFailure(Exception e) { } { - //tag::x-pack-get-watch-execute + //tag::get-watch-request GetWatchRequest request = new GetWatchRequest("my_watch_id"); + //end::get-watch-request + + //tag::ack-watch-execute GetWatchResponse response = client.watcher().getWatch(request, RequestOptions.DEFAULT); - //end::x-pack-get-watch-execute + //end::get-watch-request - //tag::x-pack-get-watch-response + //tag::get-watch-response String watchId = response.getId(); // <1> boolean found = response.isFound(); // <2> long version = response.getVersion(); // <3> WatchStatus status = response.getStatus(); // <4> BytesReference source = response.getSource(); // <5> - //end::x-pack-get-watch-response + //end::get-watch-response } { GetWatchRequest request = new GetWatchRequest("my_other_watch_id"); - // tag::x-pack-get-watch-execute-listener + // tag::get-watch-execute-listener ActionListener listener = new ActionListener() { @Override public void onResponse(GetWatchResponse response) { @@ -228,15 +231,15 @@ public void onFailure(Exception e) { // <2> } }; - // end::x-pack-get-watch-execute-listener + // end::get-watch-execute-listener // Replace the empty listener by a blocking listener in test final CountDownLatch latch = new CountDownLatch(1); listener = new LatchedActionListener<>(listener, latch); - // tag::x-pack-get-watch-execute-async + // tag::get-watch-execute-async client.watcher().getWatchAsync(request, RequestOptions.DEFAULT, listener); // <1> - // end::x-pack-get-watch-execute-async + // end::get-watch-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java deleted file mode 100644 index 4ba52f4d84b14..0000000000000 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/GetWatchResponseTests.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * 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.client.watcher; - -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.xcontent.DeprecationHandler; -import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; -import org.elasticsearch.common.xcontent.NamedXContentRegistry; -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContent; -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.test.AbstractXContentTestCase; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; - -import static org.elasticsearch.index.mapper.DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER; - -public class GetWatchResponseTests extends AbstractXContentTestCase { - /** - * A wrapper for {@link GetWatchResponse} that is able to serialize the response with {@link ToXContent}. - */ - static class ResponseWrapper implements ToXContentObject { - final NamedXContentRegistry xContentRegistry; - final GetWatchResponse response; - - ResponseWrapper(NamedXContentRegistry xContentRegistry, GetWatchResponse response) { - this.xContentRegistry = xContentRegistry; - this.response = response; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return GetWatchResponseTests.toXContent(xContentRegistry, response, builder); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ResponseWrapper that = (ResponseWrapper) o; - return Objects.equals(response, that.response); - } - - @Override - public int hashCode() { - return Objects.hash(response); - } - } - - @Override - protected ResponseWrapper createTestInstance() { - String id = randomAlphaOfLength(10); - if (rarely()) { - return new ResponseWrapper(xContentRegistry(), new GetWatchResponse(id)); - } - long version = randomLongBetween(-1, Long.MAX_VALUE); - WatchStatus status = randomWatchStatus(); - BytesReference source = simpleWatch(); - ResponseWrapper wrapper = - new ResponseWrapper(xContentRegistry(), new GetWatchResponse(id, version, status, source, XContentType.JSON)); - return wrapper; - } - - @Override - protected ResponseWrapper doParseInstance(XContentParser parser) throws IOException { - return new ResponseWrapper(xContentRegistry(), GetWatchResponse.fromXContent(parser)); - } - - @Override - protected boolean supportsUnknownFields() { - return false; - } - - static String[] SHUFFLE_FIELDS_EXCEPTION = new String[] { "watch" }; - @Override - protected String[] getShuffleFieldsExceptions() { - return SHUFFLE_FIELDS_EXCEPTION; - } - - @Override - protected void assertEqualInstances(ResponseWrapper expectedInstance, ResponseWrapper newInstance) { - if (newInstance.response.isFound() && - expectedInstance.response.getContentType() != newInstance.response.getContentType()) { - /** - * The {@link GetWatchResponse#getContentType()} depends on the content type that - * was used to serialize the main object so we use the same content type than the - * expectedInstance to translate the watch of the newInstance. - */ - XContent from = XContentFactory.xContent(newInstance.response.getContentType()); - XContent to = XContentFactory.xContent(expectedInstance.response.getContentType()); - final BytesReference source; - // It is safe to use EMPTY here because this never uses namedObject - try (InputStream stream = newInstance.response.getSource().streamInput(); - XContentParser parser = XContentFactory.xContent(from.type()).createParser(NamedXContentRegistry.EMPTY, - DeprecationHandler.THROW_UNSUPPORTED_OPERATION, stream)) { - parser.nextToken(); - XContentBuilder builder = XContentFactory.contentBuilder(to.type()); - builder.copyCurrentStructure(parser); - source = BytesReference.bytes(builder); - } catch (IOException e) { - throw new AssertionError(e); - } - newInstance = new ResponseWrapper(xContentRegistry(), - new GetWatchResponse(newInstance.response.getId(), newInstance.response.getVersion(), - newInstance.response.getStatus(), source, expectedInstance.response.getContentType())); - } - super.assertEqualInstances(expectedInstance, newInstance); - } - - static XContentBuilder toXContentFragment(ActionStatus.Execution execution, XContentBuilder builder) throws IOException { - builder.field("timestamp").value(DEFAULT_DATE_TIME_FORMATTER.printer().print(execution.timestamp())); - builder.field("successful", execution.successful()); - if (execution.successful() == false) { - builder.field("reason", execution.reason()); - } - return builder; - } - - static XContentBuilder toXContentFragment(ActionStatus.Throttle throttle, XContentBuilder builder) throws IOException { - builder.field("timestamp").value(DEFAULT_DATE_TIME_FORMATTER.printer().print(throttle.timestamp())); - builder.field("reason", throttle.reason()); - return builder; - } - - static XContentBuilder toXContentFragment(ActionStatus.AckStatus status, XContentBuilder builder) throws IOException { - builder.field("timestamp").value(DEFAULT_DATE_TIME_FORMATTER.printer().print(status.timestamp())); - builder.field("state", status.state().name().toLowerCase(Locale.ROOT)); - return builder; - } - - static XContentBuilder toXContentFragment(ActionStatus status, XContentBuilder builder) throws IOException { - builder.startObject("ack"); - toXContentFragment(status.ackStatus(), builder); - builder.endObject(); - if (status.lastExecution() != null) { - builder.startObject("last_execution"); - toXContentFragment(status.lastExecution(), builder); - builder.endObject(); - } - if (status.lastSuccessfulExecution() != null) { - builder.startObject("last_successful_execution"); - toXContentFragment(status.lastSuccessfulExecution(), builder); - builder.endObject(); - } - if (status.lastThrottle() != null) { - builder.startObject("last_throttle"); - toXContentFragment(status.lastThrottle(), builder); - builder.endObject(); - } - return builder; - } - - static XContentBuilder toXContent(WatchStatus status, XContentBuilder builder) throws IOException { - builder.startObject("status"); - if (status.state() != null) { - builder.startObject("state"); - builder.field("active", status.state().isActive()); - builder.field("timestamp", DEFAULT_DATE_TIME_FORMATTER.printer().print(status.state().getTimestamp())); - builder.endObject(); - } - - if (status.lastChecked() != null) { - builder.timeField("last_checked", status.lastChecked()); - } - if (status.lastMetCondition() != null) { - builder.timeField("last_met_condition", status.lastMetCondition()); - } - builder.startObject("actions"); - for (Map.Entry entry :status.getActions().entrySet()) { - builder.startObject(entry.getKey()); - toXContentFragment(entry.getValue(), builder); - builder.endObject(); - } - builder.endObject(); - builder.field("execution_state", status.getExecutionState().id()); - builder.field("version", status.version()); - return builder.endObject(); - } - - static XContentParser parser(NamedXContentRegistry xContentRegistry, - XContentType contentType, InputStream stream) throws IOException { - return contentType.xContent().createParser(xContentRegistry, LoggingDeprecationHandler.INSTANCE, stream); - } - - static XContentBuilder toXContent(NamedXContentRegistry xContentRegistry, - GetWatchResponse response, XContentBuilder builder) throws IOException { - builder.startObject(); - builder.field("_id", response.getId()); - builder.field("found", response.isFound()); - if (response.isFound() == false) { - return builder.endObject(); - } - builder.field("_version", response.getVersion()); - toXContent(response.getStatus(), builder); - builder.field("watch"); - try (InputStream stream = response.getSource().streamInput(); - XContentParser parser = parser(xContentRegistry, response.getContentType(), stream)) { - parser.nextToken(); - builder.generator().copyCurrentStructure(parser); - } - return builder.endObject(); - } - - static ActionStatus.Execution randomExecution() { - if (randomBoolean()) { - return null; - } - boolean successful = randomBoolean(); - String reason = null; - if (successful == false) { - reason = randomAlphaOfLengthBetween(10, 20); - - } - return new ActionStatus.Execution(DateTime.now(DateTimeZone.UTC), successful, reason); - } - - static WatchStatus randomWatchStatus() { - long version = randomLongBetween(-1, Long.MAX_VALUE); - WatchStatus.State state = rarely() ? null : new WatchStatus.State(randomBoolean(), DateTime.now(DateTimeZone.UTC)); - ExecutionState executionState = randomFrom(ExecutionState.values()); - DateTime lastChecked = rarely() ? null : DateTime.now(DateTimeZone.UTC); - DateTime lastMetCondition = rarely() ? null : DateTime.now(DateTimeZone.UTC); - int size = randomIntBetween(0, 5); - Map actionMap = new HashMap<>(); - for (int i = 0; i < size; i++) { - ActionStatus.AckStatus ack = new ActionStatus.AckStatus(DateTime.now(DateTimeZone.UTC), - randomFrom(ActionStatus.AckStatus.State.values())); - ActionStatus actionStatus = new ActionStatus(ack, randomExecution(), randomExecution(), null); - actionMap.put(randomAlphaOfLength(10), actionStatus); - } - return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actionMap); - } - - static BytesReference simpleWatch() { - XContentBuilder builder = null; - try { - builder = XContentBuilder.builder(XContentType.JSON.xContent()); - builder.startObject() - .startObject("trigger") - .startObject("schedule") - .field("interval", "10h") - .endObject() - .endObject() - .startObject("input") - .startObject("none") - .endObject() - .endObject() - .startObject("actions") - .startObject("logme") - .field("text", "{{ctx.payload}}") - .endObject() - .endObject().endObject(); - return BytesReference.bytes(builder); - } catch (IOException e) { - throw new AssertionError(e); - } - } -} diff --git a/docs/java-rest/high-level/watcher/get-watch.asciidoc b/docs/java-rest/high-level/watcher/get-watch.asciidoc index 6fa10e59a07e9..c4773d70ad731 100644 --- a/docs/java-rest/high-level/watcher/get-watch.asciidoc +++ b/docs/java-rest/high-level/watcher/get-watch.asciidoc @@ -14,18 +14,18 @@ A watch can be retrieved as follows: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute] +include-tagged::{doc-tests-file}[{api}-request] -------------------------------------------------- -[[java-rest-high-x-pack-watcher-get-watch-response]] +[id="{upid}-{api}-response"] ==== Response -The returned `GetWatchResponse` contains `id`, -, `version`, `status` and `source` information. +The returned +{response}+ contains `id`, `version`, `status` and `source` +information. ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-response] +include-tagged::{doc-tests-file}[{api}-response] -------------------------------------------------- <1> `_id`, id of the watch <2> `found` is a boolean indicating whether the watch was found @@ -33,29 +33,4 @@ include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-respons <3> `status` contains status of the watch <4> `source` the source of the watch -[[java-rest-high-x-pack-watcher-put-watch-async]] -==== Asynchronous Execution - -This request can be executed asynchronously: - -["source","java",subs="attributes,callouts,macros"] --------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute-async] --------------------------------------------------- -<1> The `GetWatchRequest` to execute and the `ActionListener` to use when -the execution completes - -The asynchronous method does not block and returns immediately. Once it is -completed the `ActionListener` is called back using the `onResponse` method -if the execution successfully completed or using the `onFailure` method if -it failed. - -A typical listener for `GetWatchResponse` looks like: - -["source","java",subs="attributes,callouts,macros"] --------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[x-pack-get-watch-execute-listener] --------------------------------------------------- -<1> Called when the execution is successfully completed. The response is -provided as an argument -<2> Called in case of failure. The raised exception is provided as an argument +include::../execution.asciidoc[] \ No newline at end of file diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java index 5aeb30bfdbd5d..f6b0294b6efc2 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java @@ -24,8 +24,10 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; +import java.util.Arrays; import java.util.function.Predicate; public abstract class AbstractSerializingTestCase extends AbstractWireSerializingTestCase { diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java index 5bc9c66d4c9a7..09536bfaa9e1e 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java @@ -23,8 +23,11 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import java.util.function.Predicate; public abstract class AbstractStreamableXContentTestCase extends AbstractStreamableTestCase { @@ -36,7 +39,7 @@ public abstract class AbstractStreamableXContentTestCase supportedContentTypes() { + return Arrays.asList(XContentType.values()); + } + /** * Params that have to be provided when calling calling {@link ToXContent#toXContent(XContentBuilder, ToXContent.Params)} */ diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java index 767cd6d260ceb..804f9d851c1aa 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java @@ -33,6 +33,8 @@ import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.function.Supplier; @@ -43,12 +45,30 @@ public abstract class AbstractXContentTestCase extends ESTestCase { protected static final int NUMBER_OF_TEST_RUNS = 20; + public static XContentTester xContentTester( + CheckedBiFunction createParser, + Supplier instanceSupplier, + CheckedBiConsumer toXContent, + CheckedFunction fromXContent) { + return new XContentTester<>( + createParser, + instanceSupplier, + (testInstance, xContentType) -> { + try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) { + toXContent.accept(testInstance, builder); + return BytesReference.bytes(builder); + } + }, + fromXContent, Arrays.asList(XContentType.values())); + } + public static XContentTester xContentTester( CheckedBiFunction createParser, Supplier instanceSupplier, CheckedBiConsumer toXContent, - CheckedFunction fromXContent) { - return new XContentTester( + CheckedFunction fromXContent, + List supportedContentTypes) { + return new XContentTester<>( createParser, instanceSupplier, (testInstance, xContentType) -> { @@ -57,7 +77,7 @@ public static XContentTester xContentTester( return BytesReference.bytes(builder); } }, - fromXContent); + fromXContent, supportedContentTypes); } public static XContentTester xContentTester( @@ -67,17 +87,31 @@ public static XContentTester xContentTester( return xContentTester(createParser, instanceSupplier, ToXContent.EMPTY_PARAMS, fromXContent); } + public static XContentTester xContentTester( + CheckedBiFunction createParser, + Supplier instanceSupplier, + ToXContent.Params toXContentParams, + CheckedFunction fromXContent) { + return new XContentTester<>( + createParser, + instanceSupplier, + (testInstance, xContentType) -> + XContentHelper.toXContent(testInstance, xContentType, toXContentParams, false), + fromXContent, Arrays.asList(XContentType.values())); + } + public static XContentTester xContentTester( CheckedBiFunction createParser, Supplier instanceSupplier, ToXContent.Params toXContentParams, - CheckedFunction fromXContent) { - return new XContentTester( + CheckedFunction fromXContent, + List supportedContentTypes) { + return new XContentTester<>( createParser, instanceSupplier, (testInstance, xContentType) -> XContentHelper.toXContent(testInstance, xContentType, toXContentParams, false), - fromXContent); + fromXContent, supportedContentTypes); } /** @@ -88,6 +122,7 @@ public static class XContentTester { private final Supplier instanceSupplier; private final CheckedBiFunction toXContent; private final CheckedFunction fromXContent; + private final List supportedContentTypes; private int numberOfTestRuns = NUMBER_OF_TEST_RUNS; private boolean supportsUnknownFields = false; @@ -104,17 +139,19 @@ private XContentTester( CheckedBiFunction createParser, Supplier instanceSupplier, CheckedBiFunction toXContent, - CheckedFunction fromXContent) { + CheckedFunction fromXContent, + List supportedContentTypes) { this.createParser = createParser; this.instanceSupplier = instanceSupplier; this.toXContent = toXContent; this.fromXContent = fromXContent; + this.supportedContentTypes = supportedContentTypes; } public void test() throws IOException { for (int runs = 0; runs < numberOfTestRuns; runs++) { T testInstance = instanceSupplier.get(); - XContentType xContentType = randomFrom(XContentType.values()); + XContentType xContentType = randomFrom(supportedContentTypes); BytesReference originalXContent = toXContent.apply(testInstance, xContentType); BytesReference shuffledContent = insertRandomFieldsAndShuffle(originalXContent, xContentType, supportsUnknownFields, shuffleFieldsExceptions, randomFieldsExcludeFilter, createParser); @@ -161,6 +198,28 @@ public XContentTester assertToXContentEquivalence(boolean assertToXContentEqu } } + public static void testFromXContent( + int numberOfTestRuns, + Supplier instanceSupplier, + boolean supportsUnknownFields, + String[] shuffleFieldsExceptions, + Predicate randomFieldsExcludeFilter, + CheckedBiFunction createParserFunction, + CheckedFunction fromXContent, + BiConsumer assertEqualsConsumer, + boolean assertToXContentEquivalence, + ToXContent.Params toXContentParams) throws IOException { + xContentTester(createParserFunction, instanceSupplier, toXContentParams, fromXContent, Arrays.asList(XContentType.values())) + .numberOfTestRuns(numberOfTestRuns) + .supportsUnknownFields(supportsUnknownFields) + .shuffleFieldsExceptions(shuffleFieldsExceptions) + .randomFieldsExcludeFilter(randomFieldsExcludeFilter) + .assertEqualsConsumer(assertEqualsConsumer) + .assertToXContentEquivalence(assertToXContentEquivalence) + .test(); + } + + public static void testFromXContent( int numberOfTestRuns, Supplier instanceSupplier, @@ -171,8 +230,9 @@ public static void testFromXContent( CheckedFunction fromXContent, BiConsumer assertEqualsConsumer, boolean assertToXContentEquivalence, - ToXContent.Params toXContentParams) throws IOException { - xContentTester(createParserFunction, instanceSupplier, toXContentParams, fromXContent) + ToXContent.Params toXContentParams, + List supportedContentTypes) throws IOException { + xContentTester(createParserFunction, instanceSupplier, toXContentParams, fromXContent, supportedContentTypes) .numberOfTestRuns(numberOfTestRuns) .supportsUnknownFields(supportsUnknownFields) .shuffleFieldsExceptions(shuffleFieldsExceptions) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java index e0724795c297c..27d8c130fcdaa 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Encapsulates the xcontent source @@ -133,4 +134,17 @@ private Object data() { return data; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + XContentSource that = (XContentSource) o; + return Objects.equals(bytes, that.bytes) && + contentType == that.contentType; + } + + @Override + public int hashCode() { + return Objects.hash(bytes, contentType); + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java index ca7025e72ad22..d92ae1dcc4626 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/transport/actions/get/GetWatchResponse.java @@ -6,19 +6,23 @@ package org.elasticsearch.xpack.core.watcher.transport.actions.get; import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.core.watcher.watch.WatchStatus; import java.io.IOException; +import java.util.Objects; -public class GetWatchResponse extends ActionResponse { +public class GetWatchResponse extends ActionResponse implements ToXContent { private String id; private WatchStatus status; - private boolean found = false; + private boolean found; private XContentSource source; private long version; @@ -30,9 +34,10 @@ public GetWatchResponse() { */ public GetWatchResponse(String id) { this.id = id; + this.status = null; this.found = false; this.source = null; - version = Versions.NOT_FOUND; + this.version = Versions.NOT_FOUND; } /** @@ -75,6 +80,10 @@ public void readFrom(StreamInput in) throws IOException { status = WatchStatus.read(in); source = XContentSource.readFrom(in); version = in.readZLong(); + } else { + status = null; + source = null; + version = Versions.NOT_FOUND; } } @@ -89,4 +98,37 @@ public void writeTo(StreamOutput out) throws IOException { out.writeZLong(version); } } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.field("found", found); + builder.field("_id", id); + if (found) { + builder.field("_version", version); + builder.field("status", status, params); + builder.field("watch", source, params); + } + return builder; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GetWatchResponse that = (GetWatchResponse) o; + return version == that.version && + Objects.equals(id, that.id) && + Objects.equals(status, that.status) && + Objects.equals(source, that.source); + } + + @Override + public int hashCode() { + return Objects.hash(id, status, version); + } + + @Override + public String toString() { + return Strings.toString(this); + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java index 69d114bd2b045..59715d7607cea 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java @@ -54,11 +54,11 @@ private WatchStatus() { } public WatchStatus(DateTime now, Map actions) { - this(-1, new State(true, now), null, null, null, actions, Collections.emptyMap()); + this(-1, new State(true, now), null, null, null, actions, null); } - private WatchStatus(long version, State state, ExecutionState executionState, DateTime lastChecked, DateTime lastMetCondition, - Map actions, Map headers) { + public WatchStatus(long version, State state, ExecutionState executionState, DateTime lastChecked, DateTime lastMetCondition, + Map actions, Map headers) { this.version = version; this.lastChecked = lastChecked; this.lastMetCondition = lastMetCondition; @@ -209,7 +209,7 @@ public void writeTo(StreamOutput out) throws IOException { if (executionState != null) { out.writeString(executionState.id()); } - boolean statusHasHeaders = headers != null && headers.isEmpty() == false; + boolean statusHasHeaders = headers != null; out.writeBoolean(statusHasHeaders); if (statusHasHeaders) { out.writeMap(headers, StreamOutput::writeString, StreamOutput::writeString); @@ -234,6 +234,8 @@ public void readFrom(StreamInput in) throws IOException { } if (in.readBoolean()) { headers = in.readMap(StreamInput::readString, StreamInput::readString); + } else { + headers = null; } } @@ -265,7 +267,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (executionState != null) { builder.field(Field.EXECUTION_STATE.getPreferredName(), executionState.id()); } - if (headers != null && headers.isEmpty() == false && WatcherParams.hideHeaders(params) == false) { + if (headers != null && WatcherParams.hideHeaders(params) == false) { builder.field(Field.HEADERS.getPreferredName(), headers); } builder.field(Field.VERSION.getPreferredName(), version); @@ -279,7 +281,7 @@ public static WatchStatus parse(String watchId, WatcherXContentParser parser) th DateTime lastMetCondition = null; Map actions = null; long version = -1; - Map headers = Collections.emptyMap(); + Map headers = null; String currentFieldName = null; XContentParser.Token token; diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java index d471a1a03f8ef..24c96a02c9a72 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java @@ -23,7 +23,7 @@ public abstract class AbstractHlrcStreamableXContentTestCase convertHlrcToInternal(doHlrcParseInstance(p))) + p -> convertHlrcToInternal(doHlrcParseInstance(p)), supportedContentTypes()) .numberOfTestRuns(NUMBER_OF_TEST_RUNS) .supportsUnknownFields(supportsUnknownFields()) .shuffleFieldsExceptions(getShuffleFieldsExceptions()) diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java index d6d8f9afe3659..2fe33923edd26 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java @@ -7,9 +7,11 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.AbstractXContentTestCase; import java.io.IOException; +import java.util.Arrays; public abstract class AbstractHlrcXContentTestCase extends AbstractXContentTestCase { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java new file mode 100644 index 0000000000000..e32731a1e8924 --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.protocol.xpack.watcher; + +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase; +import org.elasticsearch.xpack.core.watcher.actions.ActionStatus; +import org.elasticsearch.xpack.core.watcher.execution.ExecutionState; +import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; +import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchResponse; +import org.elasticsearch.xpack.core.watcher.watch.WatchStatus; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GetWatchResponseTests extends + AbstractHlrcStreamableXContentTestCase { + + private static final String[] SHUFFLE_FIELDS_EXCEPTION = new String[] { "watch" }; + + @Override + protected String[] getShuffleFieldsExceptions() { + return SHUFFLE_FIELDS_EXCEPTION; + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } + + @Override + protected List supportedContentTypes() { + // The get watch API supports JSON output only. + return Arrays.asList(XContentType.JSON); + } + + @Override + protected GetWatchResponse createBlankInstance() { + return new GetWatchResponse(); + } + + @Override + protected GetWatchResponse createTestInstance() { + String id = randomAlphaOfLength(10); + if (rarely()) { + return new GetWatchResponse(id); + } + long version = randomLongBetween(0, 10); + WatchStatus status = randomWatchStatus(); + BytesReference source = emptyWatch(); + return new GetWatchResponse(id, version, status, new XContentSource(source, XContentType.JSON)); + } + + private static BytesReference emptyWatch() { + try { + XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent()); + builder.startObject().endObject(); + return BytesReference.bytes(builder); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + private static WatchStatus randomWatchStatus() { + long version = randomLongBetween(-1, Long.MAX_VALUE); + WatchStatus.State state = new WatchStatus.State(randomBoolean(), DateTime.now(DateTimeZone.UTC)); + ExecutionState executionState = randomFrom(ExecutionState.values()); + DateTime lastChecked = rarely() ? null : DateTime.now(DateTimeZone.UTC); + DateTime lastMetCondition = rarely() ? null : DateTime.now(DateTimeZone.UTC); + int size = randomIntBetween(0, 5); + Map actionMap = new HashMap<>(); + for (int i = 0; i < size; i++) { + ActionStatus.AckStatus ack = new ActionStatus.AckStatus( + DateTime.now(DateTimeZone.UTC), + randomFrom(ActionStatus.AckStatus.State.values()) + ); + ActionStatus actionStatus = new ActionStatus( + ack, + randomBoolean() ? null : randomExecution(), + randomBoolean() ? null : randomExecution(), + randomBoolean() ? null : randomThrottle() + ); + actionMap.put(randomAlphaOfLength(10), actionStatus); + } + return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actionMap, null); + } + + private static ActionStatus.Throttle randomThrottle() { + return new ActionStatus.Throttle(DateTime.now(DateTimeZone.UTC), randomAlphaOfLengthBetween(10, 20)); + } + + private static ActionStatus.Execution randomExecution() { + if (randomBoolean()) { + return null; + } else if (randomBoolean()) { + return ActionStatus.Execution.failure(DateTime.now(DateTimeZone.UTC), randomAlphaOfLengthBetween(10, 20)); + } else { + return ActionStatus.Execution.successful(DateTime.now(DateTimeZone.UTC)); + } + } + + @Override + public org.elasticsearch.client.watcher.GetWatchResponse doHlrcParseInstance(XContentParser parser) throws IOException { + return org.elasticsearch.client.watcher.GetWatchResponse.fromXContent(parser); + } + + @Override + public GetWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.GetWatchResponse instance) { + if (instance.isFound()) { + return new GetWatchResponse(instance.getId(), instance.getVersion(), convertHlrcToInternal(instance.getStatus()), + new XContentSource(instance.getSource(), instance.getContentType())); + } else { + return new GetWatchResponse(instance.getId()); + } + } + + private static WatchStatus convertHlrcToInternal(org.elasticsearch.client.watcher.WatchStatus status) { + final Map actions = new HashMap<>(); + for (Map.Entry entry : status.getActions().entrySet()) { + actions.put(entry.getKey(), convertHlrcToInternal(entry.getValue())); + } + return new WatchStatus(status.version(), + convertHlrcToInternal(status.state()), + status.getExecutionState() == null ? null : convertHlrcToInternal(status.getExecutionState()), + status.lastChecked(), status.lastMetCondition(), actions, null + ); + } + + private static ActionStatus convertHlrcToInternal(org.elasticsearch.client.watcher.ActionStatus actionStatus) { + return new ActionStatus(convertHlrcToInternal(actionStatus.ackStatus()), + actionStatus.lastExecution() == null ? null : convertHlrcToInternal(actionStatus.lastExecution()), + actionStatus.lastSuccessfulExecution() == null ? null : convertHlrcToInternal(actionStatus.lastSuccessfulExecution()), + actionStatus.lastThrottle() == null ? null : convertHlrcToInternal(actionStatus.lastThrottle()) + ); + } + + private static ActionStatus.AckStatus convertHlrcToInternal(org.elasticsearch.client.watcher.ActionStatus.AckStatus ackStatus) { + return new ActionStatus.AckStatus(ackStatus.timestamp(), convertHlrcToInternal(ackStatus.state())); + } + + private static ActionStatus.AckStatus.State convertHlrcToInternal(org.elasticsearch.client.watcher.ActionStatus.AckStatus.State state) { + return ActionStatus.AckStatus.State.valueOf(state.name()); + } + + private static WatchStatus.State convertHlrcToInternal(org.elasticsearch.client.watcher.WatchStatus.State state) { + return new WatchStatus.State(state.isActive(), state.getTimestamp()); + } + + private static ExecutionState convertHlrcToInternal(org.elasticsearch.client.watcher.ExecutionState executionState) { + return ExecutionState.valueOf(executionState.name()); + } + + private static ActionStatus.Execution convertHlrcToInternal(org.elasticsearch.client.watcher.ActionStatus.Execution execution) { + if (execution.successful()) { + return ActionStatus.Execution.successful(execution.timestamp()); + } else { + return ActionStatus.Execution.failure(execution.timestamp(), execution.reason()); + } + } + + private static ActionStatus.Throttle convertHlrcToInternal(org.elasticsearch.client.watcher.ActionStatus.Throttle throttle) { + return new ActionStatus.Throttle(throttle.timestamp(), throttle.reason()); + } +} From 569aefa4aa4c5e0a53de81f8dd9374303d283995 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 28 Nov 2018 14:57:24 +0100 Subject: [PATCH 04/10] fix checkstyle --- .../org/elasticsearch/test/AbstractSerializingTestCase.java | 2 -- .../org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java | 1 - .../elasticsearch/protocol/AbstractHlrcXContentTestCase.java | 2 -- 3 files changed, 5 deletions(-) diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java index f6b0294b6efc2..5aeb30bfdbd5d 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractSerializingTestCase.java @@ -24,10 +24,8 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; -import java.util.Arrays; import java.util.function.Predicate; public abstract class AbstractSerializingTestCase extends AbstractWireSerializingTestCase { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java index 59715d7607cea..a3f60b8a044e0 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java @@ -22,7 +22,6 @@ import org.joda.time.DateTime; import java.io.IOException; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java index 2fe33923edd26..d6d8f9afe3659 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java @@ -7,11 +7,9 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.AbstractXContentTestCase; import java.io.IOException; -import java.util.Arrays; public abstract class AbstractHlrcXContentTestCase extends AbstractXContentTestCase { From 02286523b93c903ac0663a2b455d51144a4890db Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 28 Nov 2018 15:32:23 +0100 Subject: [PATCH 05/10] add a method to get the watch as a map --- .../client/watcher/GetWatchResponse.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index 86f63ad7ddf37..916bcdfdd7dd0 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -18,15 +18,21 @@ */ package org.elasticsearch.client.watcher; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.uid.Versions; import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; +import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.XContentUtils; import java.io.IOException; +import java.io.InputStream; +import java.util.Map; import java.util.Objects; public class GetWatchResponse { @@ -35,6 +41,7 @@ public class GetWatchResponse { private final WatchStatus status; private final BytesReference source; + private transient Map sourceAsMap; /** * Ctor for missing watch @@ -66,12 +73,33 @@ public WatchStatus getStatus() { return status; } + /** + * Returns the {@link XContentType} of the source + */ + public XContentType getContentType() { + return XContentType.JSON; + } + + /** + * Returns the serialized watch + */ public BytesReference getSource() { return source; } - public XContentType getContentType() { - return XContentType.JSON; + /** + * Returns the source as a map + */ + public Map getSourceAsMap() throws IOException { + if (sourceAsMap == null) { + // EMPTY is safe here because we never use namedObject + try (InputStream stream = source.streamInput(); + XContentParser parser = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, + LoggingDeprecationHandler.INSTANCE, stream)) { + sourceAsMap = (Map) XContentUtils.readValue(parser, parser.nextToken()); + } + } + return sourceAsMap; } @Override From 1b27b2f682aef7998542d9af542195c75074d13e Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 28 Nov 2018 17:17:05 +0100 Subject: [PATCH 06/10] fix map conversion --- .../org/elasticsearch/client/watcher/GetWatchResponse.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index 916bcdfdd7dd0..02b5d7e905e22 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -18,7 +18,6 @@ */ package org.elasticsearch.client.watcher; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.uid.Versions; @@ -91,12 +90,12 @@ public BytesReference getSource() { * Returns the source as a map */ public Map getSourceAsMap() throws IOException { - if (sourceAsMap == null) { + if (sourceAsMap == null && source != null) { // EMPTY is safe here because we never use namedObject try (InputStream stream = source.streamInput(); XContentParser parser = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, stream)) { - sourceAsMap = (Map) XContentUtils.readValue(parser, parser.nextToken()); + return parser.map(); } } return sourceAsMap; From a0466498847aafa39ac7000f89814d5205041cb3 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 28 Nov 2018 18:03:40 +0100 Subject: [PATCH 07/10] checkstyle --- .../java/org/elasticsearch/client/watcher/GetWatchResponse.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index 02b5d7e905e22..ab8834d40cc00 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -27,7 +27,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.common.xcontent.XContentUtils; import java.io.IOException; import java.io.InputStream; From a23bbc21ee4711f191ebd6df3efcbbc2ba0c691f Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 28 Nov 2018 20:14:46 +0100 Subject: [PATCH 08/10] remove deprecation handler that uses log4j --- .../org/elasticsearch/client/watcher/GetWatchResponse.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index ab8834d40cc00..86c881fe5f6aa 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -22,7 +22,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.uid.Versions; import org.elasticsearch.common.xcontent.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; +import org.elasticsearch.common.xcontent.DeprecationHandler; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -93,8 +93,8 @@ public Map getSourceAsMap() throws IOException { // EMPTY is safe here because we never use namedObject try (InputStream stream = source.streamInput(); XContentParser parser = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, - LoggingDeprecationHandler.INSTANCE, stream)) { - return parser.map(); + DeprecationHandler.THROW_UNSUPPORTED_OPERATION, stream)) { + sourceAsMap = parser.map(); } } return sourceAsMap; From c9c9cb597ad289f76410a94a803be78c02733a86 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 29 Nov 2018 00:26:34 +0100 Subject: [PATCH 09/10] iter --- .../client/watcher/GetWatchResponse.java | 33 +++----- .../client/watcher/WatchStatus.java | 9 ++- .../AbstractStreamableXContentTestCase.java | 13 +-- .../test/AbstractXContentTestCase.java | 80 +++---------------- .../support/xcontent/XContentSource.java | 7 ++ .../xpack/core/watcher/watch/WatchStatus.java | 15 ++-- ...bstractHlrcStreamableXContentTestCase.java | 2 +- .../xpack/watcher/GetWatchResponseTests.java | 78 +++++++++++++++--- 8 files changed, 117 insertions(+), 120 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java index 86c881fe5f6aa..9f5934b33eb30 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/GetWatchResponse.java @@ -22,14 +22,12 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.uid.Versions; import org.elasticsearch.common.xcontent.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.DeprecationHandler; -import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; -import java.io.InputStream; import java.util.Map; import java.util.Objects; @@ -39,20 +37,21 @@ public class GetWatchResponse { private final WatchStatus status; private final BytesReference source; - private transient Map sourceAsMap; + private final XContentType xContentType; /** * Ctor for missing watch */ public GetWatchResponse(String id) { - this(id, Versions.NOT_FOUND, null, null); + this(id, Versions.NOT_FOUND, null, null, null); } - public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source) { + public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source, XContentType xContentType) { this.id = id; this.version = version; this.status = status; this.source = source; + this.xContentType = xContentType; } public String getId() { @@ -75,7 +74,7 @@ public WatchStatus getStatus() { * Returns the {@link XContentType} of the source */ public XContentType getContentType() { - return XContentType.JSON; + return xContentType; } /** @@ -88,16 +87,8 @@ public BytesReference getSource() { /** * Returns the source as a map */ - public Map getSourceAsMap() throws IOException { - if (sourceAsMap == null && source != null) { - // EMPTY is safe here because we never use namedObject - try (InputStream stream = source.streamInput(); - XContentParser parser = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, - DeprecationHandler.THROW_UNSUPPORTED_OPERATION, stream)) { - sourceAsMap = parser.map(); - } - } - return sourceAsMap; + public Map getSourceAsMap() { + return source == null ? null : XContentHelper.convertToMap(source, false, getContentType()).v2(); } @Override @@ -108,6 +99,7 @@ public boolean equals(Object o) { return version == that.version && Objects.equals(id, that.id) && Objects.equals(status, that.status) && + Objects.equals(xContentType, that.xContentType) && Objects.equals(source, that.source); } @@ -127,8 +119,9 @@ public int hashCode() { a -> { boolean isFound = (boolean) a[1]; if (isFound) { - BytesReference source = (BytesReference) a[4]; - return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source); + XContentBuilder builder = (XContentBuilder) a[4]; + BytesReference source = BytesReference.bytes(builder); + return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source, builder.contentType()); } else { return new GetWatchResponse((String) a[0]); } @@ -144,7 +137,7 @@ public int hashCode() { (parser, context) -> { try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) { builder.copyCurrentStructure(parser); - return BytesReference.bytes(builder); + return builder; } }, WATCH_FIELD); } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java index bc37dd8de89b1..ab543abbf594a 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/WatchStatus.java @@ -95,6 +95,10 @@ public ExecutionState getExecutionState() { return executionState; } + public Map getHeaders() { + return headers; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -106,7 +110,8 @@ public boolean equals(Object o) { Objects.equals(lastMetCondition, that.lastMetCondition) && Objects.equals(version, that.version) && Objects.equals(executionState, that.executionState) && - Objects.equals(actions, that.actions); + Objects.equals(actions, that.actions) && + Objects.equals(headers, that.headers); } @Override @@ -227,6 +232,8 @@ public static State parse(XContentParser parser) throws IOException { active = parser.booleanValue(); } else if (Field.TIMESTAMP.match(currentFieldName, parser.getDeprecationHandler())) { timestamp = parseDate(currentFieldName, parser); + } else { + parser.skipChildren(); } } return new State(active, timestamp); diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java index 09536bfaa9e1e..5bc9c66d4c9a7 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java @@ -23,11 +23,8 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; -import java.util.Arrays; -import java.util.List; import java.util.function.Predicate; public abstract class AbstractStreamableXContentTestCase extends AbstractStreamableTestCase { @@ -39,7 +36,7 @@ public abstract class AbstractStreamableXContentTestCase supportedContentTypes() { - return Arrays.asList(XContentType.values()); - } - /** * Params that have to be provided when calling calling {@link ToXContent#toXContent(XContentBuilder, ToXContent.Params)} */ diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java index 804f9d851c1aa..767cd6d260ceb 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java @@ -33,8 +33,6 @@ import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; -import java.util.Arrays; -import java.util.List; import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.function.Supplier; @@ -45,30 +43,12 @@ public abstract class AbstractXContentTestCase extends ESTestCase { protected static final int NUMBER_OF_TEST_RUNS = 20; - public static XContentTester xContentTester( - CheckedBiFunction createParser, - Supplier instanceSupplier, - CheckedBiConsumer toXContent, - CheckedFunction fromXContent) { - return new XContentTester<>( - createParser, - instanceSupplier, - (testInstance, xContentType) -> { - try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) { - toXContent.accept(testInstance, builder); - return BytesReference.bytes(builder); - } - }, - fromXContent, Arrays.asList(XContentType.values())); - } - public static XContentTester xContentTester( CheckedBiFunction createParser, Supplier instanceSupplier, CheckedBiConsumer toXContent, - CheckedFunction fromXContent, - List supportedContentTypes) { - return new XContentTester<>( + CheckedFunction fromXContent) { + return new XContentTester( createParser, instanceSupplier, (testInstance, xContentType) -> { @@ -77,7 +57,7 @@ public static XContentTester xContentTester( return BytesReference.bytes(builder); } }, - fromXContent, supportedContentTypes); + fromXContent); } public static XContentTester xContentTester( @@ -87,31 +67,17 @@ public static XContentTester xContentTester( return xContentTester(createParser, instanceSupplier, ToXContent.EMPTY_PARAMS, fromXContent); } - public static XContentTester xContentTester( - CheckedBiFunction createParser, - Supplier instanceSupplier, - ToXContent.Params toXContentParams, - CheckedFunction fromXContent) { - return new XContentTester<>( - createParser, - instanceSupplier, - (testInstance, xContentType) -> - XContentHelper.toXContent(testInstance, xContentType, toXContentParams, false), - fromXContent, Arrays.asList(XContentType.values())); - } - public static XContentTester xContentTester( CheckedBiFunction createParser, Supplier instanceSupplier, ToXContent.Params toXContentParams, - CheckedFunction fromXContent, - List supportedContentTypes) { - return new XContentTester<>( + CheckedFunction fromXContent) { + return new XContentTester( createParser, instanceSupplier, (testInstance, xContentType) -> XContentHelper.toXContent(testInstance, xContentType, toXContentParams, false), - fromXContent, supportedContentTypes); + fromXContent); } /** @@ -122,7 +88,6 @@ public static class XContentTester { private final Supplier instanceSupplier; private final CheckedBiFunction toXContent; private final CheckedFunction fromXContent; - private final List supportedContentTypes; private int numberOfTestRuns = NUMBER_OF_TEST_RUNS; private boolean supportsUnknownFields = false; @@ -139,19 +104,17 @@ private XContentTester( CheckedBiFunction createParser, Supplier instanceSupplier, CheckedBiFunction toXContent, - CheckedFunction fromXContent, - List supportedContentTypes) { + CheckedFunction fromXContent) { this.createParser = createParser; this.instanceSupplier = instanceSupplier; this.toXContent = toXContent; this.fromXContent = fromXContent; - this.supportedContentTypes = supportedContentTypes; } public void test() throws IOException { for (int runs = 0; runs < numberOfTestRuns; runs++) { T testInstance = instanceSupplier.get(); - XContentType xContentType = randomFrom(supportedContentTypes); + XContentType xContentType = randomFrom(XContentType.values()); BytesReference originalXContent = toXContent.apply(testInstance, xContentType); BytesReference shuffledContent = insertRandomFieldsAndShuffle(originalXContent, xContentType, supportsUnknownFields, shuffleFieldsExceptions, randomFieldsExcludeFilter, createParser); @@ -198,28 +161,6 @@ public XContentTester assertToXContentEquivalence(boolean assertToXContentEqu } } - public static void testFromXContent( - int numberOfTestRuns, - Supplier instanceSupplier, - boolean supportsUnknownFields, - String[] shuffleFieldsExceptions, - Predicate randomFieldsExcludeFilter, - CheckedBiFunction createParserFunction, - CheckedFunction fromXContent, - BiConsumer assertEqualsConsumer, - boolean assertToXContentEquivalence, - ToXContent.Params toXContentParams) throws IOException { - xContentTester(createParserFunction, instanceSupplier, toXContentParams, fromXContent, Arrays.asList(XContentType.values())) - .numberOfTestRuns(numberOfTestRuns) - .supportsUnknownFields(supportsUnknownFields) - .shuffleFieldsExceptions(shuffleFieldsExceptions) - .randomFieldsExcludeFilter(randomFieldsExcludeFilter) - .assertEqualsConsumer(assertEqualsConsumer) - .assertToXContentEquivalence(assertToXContentEquivalence) - .test(); - } - - public static void testFromXContent( int numberOfTestRuns, Supplier instanceSupplier, @@ -230,9 +171,8 @@ public static void testFromXContent( CheckedFunction fromXContent, BiConsumer assertEqualsConsumer, boolean assertToXContentEquivalence, - ToXContent.Params toXContentParams, - List supportedContentTypes) throws IOException { - xContentTester(createParserFunction, instanceSupplier, toXContentParams, fromXContent, supportedContentTypes) + ToXContent.Params toXContentParams) throws IOException { + xContentTester(createParserFunction, instanceSupplier, toXContentParams, fromXContent) .numberOfTestRuns(numberOfTestRuns) .supportsUnknownFields(supportsUnknownFields) .shuffleFieldsExceptions(shuffleFieldsExceptions) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java index 27d8c130fcdaa..b54acc441e74a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/support/xcontent/XContentSource.java @@ -52,6 +52,13 @@ public XContentSource(XContentBuilder builder) { this(BytesReference.bytes(builder), builder.contentType()); } + /** + * @return The content type of the source + */ + public XContentType getContentType() { + return contentType; + } + /** * @return The bytes reference of the source */ diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java index a3f60b8a044e0..c65e019780a90 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/watch/WatchStatus.java @@ -22,6 +22,7 @@ import org.joda.time.DateTime; import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -53,7 +54,7 @@ private WatchStatus() { } public WatchStatus(DateTime now, Map actions) { - this(-1, new State(true, now), null, null, null, actions, null); + this(-1, new State(true, now), null, null, null, actions, Collections.emptyMap()); } public WatchStatus(long version, State state, ExecutionState executionState, DateTime lastChecked, DateTime lastMetCondition, @@ -208,7 +209,7 @@ public void writeTo(StreamOutput out) throws IOException { if (executionState != null) { out.writeString(executionState.id()); } - boolean statusHasHeaders = headers != null; + boolean statusHasHeaders = headers != null && headers.isEmpty() == false; out.writeBoolean(statusHasHeaders); if (statusHasHeaders) { out.writeMap(headers, StreamOutput::writeString, StreamOutput::writeString); @@ -233,8 +234,6 @@ public void readFrom(StreamInput in) throws IOException { } if (in.readBoolean()) { headers = in.readMap(StreamInput::readString, StreamInput::readString); - } else { - headers = null; } } @@ -266,7 +265,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (executionState != null) { builder.field(Field.EXECUTION_STATE.getPreferredName(), executionState.id()); } - if (headers != null && WatcherParams.hideHeaders(params) == false) { + if (headers != null && headers.isEmpty() == false && WatcherParams.hideHeaders(params) == false) { builder.field(Field.HEADERS.getPreferredName(), headers); } builder.field(Field.VERSION.getPreferredName(), version); @@ -280,7 +279,7 @@ public static WatchStatus parse(String watchId, WatcherXContentParser parser) th DateTime lastMetCondition = null; Map actions = null; long version = -1; - Map headers = null; + Map headers = Collections.emptyMap(); String currentFieldName = null; XContentParser.Token token; @@ -341,6 +340,8 @@ public static WatchStatus parse(String watchId, WatcherXContentParser parser) th if (token == XContentParser.Token.START_OBJECT) { headers = parser.mapStrings(); } + } else { + parser.skipChildren(); } } @@ -396,6 +397,8 @@ public static State parse(XContentParser parser) throws IOException { active = parser.booleanValue(); } else if (Field.TIMESTAMP.match(currentFieldName, parser.getDeprecationHandler())) { timestamp = parseDate(currentFieldName, parser, UTC); + } else { + parser.skipChildren(); } } return new State(active, timestamp); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java index 24c96a02c9a72..d471a1a03f8ef 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java @@ -23,7 +23,7 @@ public abstract class AbstractHlrcStreamableXContentTestCase convertHlrcToInternal(doHlrcParseInstance(p)), supportedContentTypes()) + p -> convertHlrcToInternal(doHlrcParseInstance(p))) .numberOfTestRuns(NUMBER_OF_TEST_RUNS) .supportsUnknownFields(supportsUnknownFields()) .shuffleFieldsExceptions(getShuffleFieldsExceptions()) diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java index e32731a1e8924..1de0bcd96a339 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java @@ -6,12 +6,19 @@ package org.elasticsearch.protocol.xpack.watcher; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.DeprecationHandler; +import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase; import org.elasticsearch.xpack.core.watcher.actions.ActionStatus; import org.elasticsearch.xpack.core.watcher.execution.ExecutionState; +import org.elasticsearch.xpack.core.watcher.support.xcontent.WatcherParams; import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchResponse; import org.elasticsearch.xpack.core.watcher.watch.WatchStatus; @@ -19,10 +26,13 @@ import org.joda.time.DateTimeZone; import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Predicate; public class GetWatchResponseTests extends AbstractHlrcStreamableXContentTestCase { @@ -35,14 +45,42 @@ protected String[] getShuffleFieldsExceptions() { } @Override - protected boolean supportsUnknownFields() { - return false; + protected ToXContent.Params getToXContentParams() { + return new ToXContent.MapParams(Collections.singletonMap("hide_headers", "false")); } @Override - protected List supportedContentTypes() { - // The get watch API supports JSON output only. - return Arrays.asList(XContentType.JSON); + protected Predicate getRandomFieldsExcludeFilter() { + return f -> f.contains("watch") || f.contains("actions") || f.contains("headers"); + } + + @Override + protected void assertEqualInstances(GetWatchResponse expectedInstance, GetWatchResponse newInstance) { + if (expectedInstance.isFound() && + expectedInstance.getSource().getContentType() != newInstance.getSource().getContentType()) { + /** + * The {@link GetWatchResponse#getContentType()} depends on the content type that + * was used to serialize the main object so we use the same content type than the + * expectedInstance to translate the watch of the newInstance. + */ + XContent from = XContentFactory.xContent(newInstance.getSource().getContentType()); + XContent to = XContentFactory.xContent(expectedInstance.getSource().getContentType()); + final BytesReference newSource; + // It is safe to use EMPTY here because this never uses namedObject + try (InputStream stream = newInstance.getSource().getBytes().streamInput(); + XContentParser parser = XContentFactory.xContent(from.type()).createParser(NamedXContentRegistry.EMPTY, + DeprecationHandler.THROW_UNSUPPORTED_OPERATION, stream)) { + parser.nextToken(); + XContentBuilder builder = XContentFactory.contentBuilder(to.type()); + builder.copyCurrentStructure(parser); + newSource = BytesReference.bytes(builder); + } catch (IOException e) { + throw new AssertionError(e); + } + newInstance = new GetWatchResponse(newInstance.getId(), newInstance.getVersion(), + newInstance.getStatus(), new XContentSource(newSource, expectedInstance.getSource().getContentType())); + } + super.assertEqualInstances(expectedInstance, newInstance); } @Override @@ -58,14 +96,27 @@ protected GetWatchResponse createTestInstance() { } long version = randomLongBetween(0, 10); WatchStatus status = randomWatchStatus(); - BytesReference source = emptyWatch(); + BytesReference source = simpleWatch(); return new GetWatchResponse(id, version, status, new XContentSource(source, XContentType.JSON)); } - private static BytesReference emptyWatch() { + private static BytesReference simpleWatch() { try { XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent()); - builder.startObject().endObject(); + builder.startObject() + .startObject("trigger") + .startObject("schedule") + .field("interval", "10h") + .endObject() + .endObject() + .startObject("input") + .startObject("none").endObject() + .endObject() + .startObject("actions") + .startObject("logme") + .field("text", "{{ctx.payload}}") + .endObject() + .endObject().endObject(); return BytesReference.bytes(builder); } catch (IOException e) { throw new AssertionError(e); @@ -93,7 +144,14 @@ private static WatchStatus randomWatchStatus() { ); actionMap.put(randomAlphaOfLength(10), actionStatus); } - return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actionMap, null); + Map headers = randomBoolean() ? new HashMap<>() : null; + if (headers != null) { + int headerSize = randomIntBetween(1, 5); + for (int i = 0; i < headerSize; i++) { + headers.put(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(1, 10)); + } + } + return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actionMap, headers); } private static ActionStatus.Throttle randomThrottle() { @@ -133,7 +191,7 @@ private static WatchStatus convertHlrcToInternal(org.elasticsearch.client.watche return new WatchStatus(status.version(), convertHlrcToInternal(status.state()), status.getExecutionState() == null ? null : convertHlrcToInternal(status.getExecutionState()), - status.lastChecked(), status.lastMetCondition(), actions, null + status.lastChecked(), status.lastMetCondition(), actions, status.getHeaders() ); } From d10e9763e5dd3af69202ebf7eacc0a56f6fe4739 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 29 Nov 2018 00:38:49 +0100 Subject: [PATCH 10/10] cleanup --- .../java/org/elasticsearch/client/watcher/ActionStatus.java | 2 +- .../protocol/xpack/watcher/GetWatchResponseTests.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java index 1a838afde85aa..ec413c10fa728 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActionStatus.java @@ -193,7 +193,7 @@ public static Execution failure(DateTime timestamp, String reason) { private final boolean successful; private final String reason; - Execution(DateTime timestamp, boolean successful, String reason) { + private Execution(DateTime timestamp, boolean successful, String reason) { this.timestamp = timestamp.toDateTime(DateTimeZone.UTC); this.successful = successful; this.reason = reason; diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java index 1de0bcd96a339..bcfed1c7b0be4 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/GetWatchResponseTests.java @@ -12,13 +12,11 @@ import org.elasticsearch.common.xcontent.XContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase; import org.elasticsearch.xpack.core.watcher.actions.ActionStatus; import org.elasticsearch.xpack.core.watcher.execution.ExecutionState; -import org.elasticsearch.xpack.core.watcher.support.xcontent.WatcherParams; import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchResponse; import org.elasticsearch.xpack.core.watcher.watch.WatchStatus; @@ -27,10 +25,8 @@ import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Predicate;