From 3db51c3a02971aec922ee0b2ff61b451a0a7b4de Mon Sep 17 00:00:00 2001 From: markharwood Date: Wed, 24 Oct 2018 10:33:18 +0100 Subject: [PATCH 1/9] HLRC support for getTask. Given a GetTaskRequest the API returns an Optional which is empty in the case of 404s or returns a TaskInfo object if found. Added Helper methods in RestHighLevelClient for returning empty Optionals when hitting 404s --- .../client/RestHighLevelClient.java | 95 +++++++++++++++ .../org/elasticsearch/client/TasksClient.java | 34 ++++++ .../client/TasksRequestConverters.java | 9 ++ .../client/tasks/GetTaskRequest.java | 112 ++++++++++++++++++ .../client/tasks/GetTaskResponse.java | 55 +++++++++ .../CustomRestHighLevelClientTests.java | 5 +- .../org/elasticsearch/client/TasksIT.java | 60 ++++++++++ 7 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java index 8b740994e3b6c..1fc0a57e9c28c 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java @@ -1417,6 +1417,39 @@ private Resp internalPerformRequest(Req request, throw new IOException("Unable to parse response body for " + response, e); } } + + + /** + * Defines a helper method for requests that can 404 and in which case will return an empty Optional + * otherwise tries to parse the response body + */ + protected final Optional performRequestAndParseOptionalEntity(Req request, + CheckedFunction requestConverter, + RequestOptions options, + CheckedFunction entityParser + ) throws IOException { + Optional validationException = request.validate(); + if (validationException != null && validationException.isPresent()) { + throw validationException.get(); + } + Request req = requestConverter.apply(request); + req.setOptions(options); + Response response; + try { + response = client.performRequest(req); + } catch (ResponseException e) { + if (404 == e.getResponse().getStatusLine().getStatusCode()) { + return Optional.empty(); + } + throw parseResponseException(e); + } + + try { + return Optional.of(parseEntity(response.getEntity(), entityParser)); + } catch (Exception e) { + throw new IOException("Unable to parse response body for " + response, e); + } + } /** * @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation @@ -1538,6 +1571,68 @@ public void onFailure(Exception exception) { } }; } + + /** + * Async request which returns empty Optionals in the case of 404s or parses entity into an Optional + * + * @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation + * layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}. + */ + @Deprecated + protected final void performRequestAsyncAndParseOptionalEntity(Req request, + CheckedFunction requestConverter, + RequestOptions options, + CheckedFunction entityParser, + ActionListener> listener) { + Optional validationException = request.validate(); + if (validationException != null && validationException.isPresent()) { + listener.onFailure(validationException.get()); + return; + } + Request req; + try { + req = requestConverter.apply(request); + } catch (Exception e) { + listener.onFailure(e); + return; + } + req.setOptions(options); + + ResponseListener responseListener = wrapResponseListener404sOptional(response -> parseEntity(response.getEntity(), + entityParser), listener); + client.performRequestAsync(req, responseListener); + } + + + final ResponseListener wrapResponseListener404sOptional(CheckedFunction responseConverter, + ActionListener> actionListener) { + return new ResponseListener() { + @Override + public void onSuccess(Response response) { + try { + actionListener.onResponse(Optional.of(responseConverter.apply(response))); + } catch (Exception e) { + IOException ioe = new IOException("Unable to parse response body for " + response, e); + onFailure(ioe); + } + } + + @Override + public void onFailure(Exception exception) { + if (exception instanceof ResponseException) { + ResponseException responseException = (ResponseException) exception; + Response response = responseException.getResponse(); + if (404 ==response.getStatusLine().getStatusCode()) { + actionListener.onResponse(Optional.empty()); + } else { + actionListener.onFailure(parseResponseException(responseException)); + } + } else { + actionListener.onFailure(exception); + } + } + }; + } /** * Converts a {@link ResponseException} obtained from the low level REST client into an {@link ElasticsearchException}. diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java index 3b957b2defb0d..db7b3e8d8b7c2 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java @@ -24,8 +24,12 @@ import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; +import org.elasticsearch.client.tasks.GetTaskRequest; +import org.elasticsearch.client.tasks.GetTaskResponse; +import org.elasticsearch.tasks.TaskInfo; import java.io.IOException; +import java.util.Optional; import static java.util.Collections.emptySet; @@ -67,6 +71,36 @@ public void listAsync(ListTasksRequest request, RequestOptions options, ActionLi restHighLevelClient.performRequestAsyncAndParseEntity(request, TasksRequestConverters::listTasks, options, ListTasksResponse::fromXContent, listener, emptySet()); } + + /** + * Get a task using the Task Management API. + * See + * Task Management API on elastic.co + * @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 Optional get(GetTaskRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseOptionalEntity(request, TasksRequestConverters::getTask, options, + GetTaskResponse::fromXContent); + + } + + /** + * Get a task using the Task Management API. + * See + * Task Management API on elastic.co + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener an actionlistener that takes an optional response (404s are returned as an empty Optional) + */ + public void getAsync(GetTaskRequest request, RequestOptions options, ActionListener> listener) { + + restHighLevelClient.performRequestAsyncAndParseOptionalEntity(request, TasksRequestConverters::getTask, options, + GetTaskResponse::fromXContent, listener); + } + /** * Cancel one or more cluster tasks using the Task Management API. diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java index 45723dcc938c5..1bc5a54cf0100 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java @@ -23,6 +23,7 @@ import org.apache.http.client.methods.HttpPost; import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; +import org.elasticsearch.client.tasks.GetTaskRequest; final class TasksRequestConverters { @@ -54,4 +55,12 @@ static Request listTasks(ListTasksRequest listTaskRequest) { .putParam("group_by", "none"); return request; } + + static Request getTask(GetTaskRequest getTaskRequest) { + Request request = new Request(HttpGet.METHOD_NAME, "_tasks/" + getTaskRequest.getNodeId() + ":" + getTaskRequest.getTaskId()); + RequestConverters.Params params = new RequestConverters.Params(request); + params.withTimeout(getTaskRequest.getTimeout()).withWaitForCompletion(getTaskRequest.getWaitForCompletion()); + return request; + } + } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java new file mode 100644 index 0000000000000..8e9474d4a173b --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java @@ -0,0 +1,112 @@ +/* + * 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.tasks; + +import org.elasticsearch.client.Validatable; +import org.elasticsearch.client.ValidationException; +import org.elasticsearch.common.unit.TimeValue; + +import java.util.Objects; +import java.util.Optional; + +public class GetTaskRequest implements Validatable { + private final String nodeId; + private final long taskId; + private boolean waitForCompletion = false; + private TimeValue timeout = null; + + + public GetTaskRequest(String nodeId, long taskId) { + this.nodeId = nodeId; + this.taskId = taskId; + } + + + + public String getNodeId() { + return nodeId; + } + + public long getTaskId() { + return taskId; + } + + /** + * Should this request wait for all found tasks to complete? + */ + public boolean getWaitForCompletion() { + return waitForCompletion; + } + + /** + * Should this request wait for all found tasks to complete? + */ + public GetTaskRequest setWaitForCompletion(boolean waitForCompletion) { + this.waitForCompletion = waitForCompletion; + return this; + } + + /** + * Timeout to wait for any async actions this request must take. It must take anywhere from 0 to 2. + */ + public TimeValue getTimeout() { + return timeout; + } + + /** + * Timeout to wait for any async actions this request must take. It must take anywhere from 0 to 2. + */ + public GetTaskRequest setTimeout(TimeValue timeout) { + this.timeout = timeout; + return this; + } + + + @Override + public Optional validate() { + final ValidationException validationException = new ValidationException(); + if (timeout != null && !waitForCompletion) { + validationException.addValidationError("Timeout settings are only accepted if waitForCompletion is also set"); + } + if (validationException.validationErrors().isEmpty()) { + return Optional.empty(); + } + return Optional.of(validationException); + } + + @Override + public int hashCode() { + return Objects.hash(nodeId, taskId, waitForCompletion, timeout); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GetTaskRequest other = (GetTaskRequest) obj; + return Objects.equals(nodeId, other.nodeId) && + taskId == other.taskId && + waitForCompletion == other.waitForCompletion && + Objects.equals(timeout, other.timeout); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java new file mode 100644 index 0000000000000..b62a3f77f12dc --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java @@ -0,0 +1,55 @@ +/* + * 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.tasks; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.tasks.TaskInfo; + +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + +public class GetTaskResponse { + private final boolean completed; + private final TaskInfo taskInfo; + public GetTaskResponse(boolean completed, TaskInfo taskInfo) { + this.completed = completed; + this.taskInfo = taskInfo; + } + public boolean isCompleted() { + return completed; + } + public TaskInfo getTaskInfo() { + return taskInfo; + } + + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("get_task", + true, a -> new GetTaskResponse((boolean) a[0], (TaskInfo) a[1])); + static { + PARSER.declareBoolean(constructorArg(), new ParseField("completed")); + PARSER.declareObject(constructorArg(), (p, c) -> TaskInfo.fromXContent(p), new ParseField("task")); + } + + + public static GetTaskResponse fromXContent(XContentParser parser) { + return PARSER.apply(parser, null); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/CustomRestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/CustomRestHighLevelClientTests.java index ff27fe21c27e6..3b69f10344a0d 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/CustomRestHighLevelClientTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/CustomRestHighLevelClientTests.java @@ -126,8 +126,11 @@ public void testMethodsVisibility() { "parseResponseException", "performRequest", "performRequestAndParseEntity", + "performRequestAndParseOptionalEntity", "performRequestAsync", - "performRequestAsyncAndParseEntity"}; + "performRequestAsyncAndParseEntity", + "performRequestAsyncAndParseOptionalEntity" + }; final Set protectedMethods = Arrays.stream(RestHighLevelClient.class.getDeclaredMethods()) .filter(method -> Modifier.isProtected(method.getModifiers())) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java index baa97cfa5b4ef..c1ac90c0de11c 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java @@ -19,15 +19,29 @@ package org.elasticsearch.client; +import org.apache.http.util.EntityUtils; import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.support.WriteRequest.RefreshPolicy; +import org.elasticsearch.client.tasks.GetTaskRequest; +import org.elasticsearch.client.tasks.GetTaskResponse; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskInfo; import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; import static java.util.Collections.emptyList; import static org.hamcrest.Matchers.equalTo; @@ -60,6 +74,52 @@ public void testListTasks() throws IOException { } assertTrue("List tasks were not found", listTasksFound); } + + public void testGetValidTask() throws IOException { + + // Run a Reindex to create a task + + final String sourceIndex = "source1"; + final String destinationIndex = "dest"; + Settings settings = Settings.builder().put("number_of_shards", 1).put("number_of_replicas", 0).build(); + createIndex(sourceIndex, settings); + createIndex(destinationIndex, settings); + BulkRequest bulkRequest = new BulkRequest() + .add(new IndexRequest(sourceIndex, "type", "1").source(Collections.singletonMap("foo", "bar"), XContentType.JSON)) + .add(new IndexRequest(sourceIndex, "type", "2").source(Collections.singletonMap("foo2", "bar2"), XContentType.JSON)) + .setRefreshPolicy(RefreshPolicy.IMMEDIATE); + assertEquals(RestStatus.OK, highLevelClient().bulk(bulkRequest, RequestOptions.DEFAULT).status()); + + // (need to use low level client because currently high level client + // doesn't support async return of task id - needs + // https://github.com/elastic/elasticsearch/pull/35202 ) + RestClient lowClient = highLevelClient().getLowLevelClient(); + Request request = new Request("POST", "_reindex"); + request.addParameter("wait_for_completion", "false"); + request.setJsonEntity("{" + " \"source\": {\n" + " \"index\": \"source1\"\n" + " },\n" + " \"dest\": {\n" + + " \"index\": \"dest\"\n" + " }" + "}"); + Response response = lowClient.performRequest(request); + String responseBody = EntityUtils.toString(response.getEntity()); + Map map = XContentHelper.convertToMap(JsonXContent.jsonXContent, responseBody, false); + Object taskId = map.get("task"); + assertNotNull(taskId); + + TaskId childTaskId = new TaskId(taskId.toString()); + GetTaskRequest gtr = new GetTaskRequest(childTaskId.getNodeId(), childTaskId.getId()); + Optional getTaskResponse = execute(gtr, highLevelClient().tasks()::get, highLevelClient().tasks()::getAsync); + assertTrue(getTaskResponse.isPresent()); + TaskInfo info = getTaskResponse.get().getTaskInfo(); + assertTrue(info.isCancellable()); + assertEquals("reindex from [source1] to [dest]", info.getDescription()); + assertEquals("indices:data/write/reindex", info.getAction()); + } + + public void testGetInvalidTask() throws IOException { + // Check 404s are returned as empty Optionals + GetTaskRequest gtr = new GetTaskRequest("doesNotExistNodeName", 123); + Optional getTaskResponse = execute(gtr, highLevelClient().tasks()::get, highLevelClient().tasks()::getAsync); + assertFalse(getTaskResponse.isPresent()); + } public void testCancelTasks() throws IOException { ListTasksRequest listRequest = new ListTasksRequest(); From 438dbe7d95c9fbf93859ada236f276ef2c7839eb Mon Sep 17 00:00:00 2001 From: markharwood Date: Fri, 2 Nov 2018 16:50:45 +0000 Subject: [PATCH 2/9] Unused import --- .../src/main/java/org/elasticsearch/client/TasksClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java index db7b3e8d8b7c2..df9f4ba7a1b78 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java @@ -26,7 +26,6 @@ import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; import org.elasticsearch.client.tasks.GetTaskRequest; import org.elasticsearch.client.tasks.GetTaskResponse; -import org.elasticsearch.tasks.TaskInfo; import java.io.IOException; import java.util.Optional; From 7ae45d2f4f15be0aef86fb34785b3d416d65db3d Mon Sep 17 00:00:00 2001 From: markharwood Date: Mon, 5 Nov 2018 09:48:05 +0000 Subject: [PATCH 3/9] Relaxed RestHighLevelClientTests to allow methods to return Optionals (this is acceptable for 404s) --- .../client/RestHighLevelClientTests.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java index 2c5d279592f48..b75dd1dcdba07 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java @@ -89,6 +89,8 @@ import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.Arrays; @@ -97,6 +99,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -675,8 +678,7 @@ public void testApiNamingConventions() throws Exception { "indices.put_alias", "mtermvectors", "render_search_template", - "scripts_painless_execute", - "tasks.get" + "scripts_painless_execute" }; //These API are not required for high-level client feature completeness String[] notRequiredApi = new String[] { @@ -777,8 +779,11 @@ private void assertSyncMethod(Method method, String apiName) { assertThat("the return type for method [" + method + "] is incorrect", method.getReturnType().getSimpleName(), equalTo("boolean")); } else { - assertThat("the return type for method [" + method + "] is incorrect", - method.getReturnType().getSimpleName(), endsWith("Response")); + // It's acceptable for 404s to be represented as empty Optionals + if (!method.getReturnType().isAssignableFrom(Optional.class)) { + assertThat("the return type for method [" + method + "] is incorrect", + method.getReturnType().getSimpleName(), endsWith("Response")); + } } assertEquals("incorrect number of exceptions for method [" + method + "]", 1, method.getExceptionTypes().length); From 3b5aaf40995804d163e4f2d0eb75efbdb3010e6e Mon Sep 17 00:00:00 2001 From: markharwood Date: Mon, 5 Nov 2018 11:02:13 +0000 Subject: [PATCH 4/9] Remove unused imports --- .../java/org/elasticsearch/client/RestHighLevelClientTests.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java index b75dd1dcdba07..62e6afe6ffb97 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java @@ -89,8 +89,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.Arrays; From dd4cb00fa44c31de4281bf526850889c19ce7dc0 Mon Sep 17 00:00:00 2001 From: markharwood Date: Mon, 5 Nov 2018 13:47:24 +0000 Subject: [PATCH 5/9] Javadoc fix for new method --- .../java/org/elasticsearch/client/RestHighLevelClient.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java index 1fc0a57e9c28c..ccafca5702b54 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java @@ -1574,11 +1574,7 @@ public void onFailure(Exception exception) { /** * Async request which returns empty Optionals in the case of 404s or parses entity into an Optional - * - * @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation - * layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}. */ - @Deprecated protected final void performRequestAsyncAndParseOptionalEntity(Req request, CheckedFunction requestConverter, RequestOptions options, @@ -1597,7 +1593,6 @@ protected final void performRequestAsyncAndParse return; } req.setOptions(options); - ResponseListener responseListener = wrapResponseListener404sOptional(response -> parseEntity(response.getEntity(), entityParser), listener); client.performRequestAsync(req, responseListener); @@ -1622,7 +1617,7 @@ public void onFailure(Exception exception) { if (exception instanceof ResponseException) { ResponseException responseException = (ResponseException) exception; Response response = responseException.getResponse(); - if (404 ==response.getStatusLine().getStatusCode()) { + if (404 == response.getStatusLine().getStatusCode()) { actionListener.onResponse(Optional.empty()); } else { actionListener.onFailure(parseResponseException(responseException)); From d43d0088fde4a5256709a59e583931b3bdfa2e9a Mon Sep 17 00:00:00 2001 From: markharwood Date: Tue, 6 Nov 2018 11:23:53 +0000 Subject: [PATCH 6/9] Fixed various whitespace violations, added use of EndpointBuilder (with new method), added (inconclusive) test for situation where GetTaskRequest has waitForCompletion=true. Conclusive test would require long-running tasks. --- .../org/elasticsearch/client/RequestConverters.java | 5 +++++ .../org/elasticsearch/client/RestHighLevelClient.java | 6 ++---- .../java/org/elasticsearch/client/TasksClient.java | 2 -- .../elasticsearch/client/TasksRequestConverters.java | 9 +++++++-- .../org/elasticsearch/client/tasks/GetTaskRequest.java | 4 ---- .../elasticsearch/client/tasks/GetTaskResponse.java | 7 ++++--- .../test/java/org/elasticsearch/client/TasksIT.java | 10 +++++++--- 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index d448275d35845..d3f2603597286 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -1020,6 +1020,11 @@ EndpointBuilder addPathPart(String... parts) { return this; } + EndpointBuilder addColonSeparatedPathParts(String... parts) { + addPathPart(String.join(":", parts)); + return this; + } + EndpointBuilder addCommaSeparatedPathParts(String[] parts) { addPathPart(String.join(",", parts)); return this; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java index ccafca5702b54..09006db1d8e04 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java @@ -1418,7 +1418,6 @@ private Resp internalPerformRequest(Req request, } } - /** * Defines a helper method for requests that can 404 and in which case will return an empty Optional * otherwise tries to parse the response body @@ -1438,7 +1437,7 @@ protected final Optional performRequestAnd try { response = client.performRequest(req); } catch (ResponseException e) { - if (404 == e.getResponse().getStatusLine().getStatusCode()) { + if (RestStatus.NOT_FOUND.getStatus() == e.getResponse().getStatusLine().getStatusCode()) { return Optional.empty(); } throw parseResponseException(e); @@ -1598,7 +1597,6 @@ protected final void performRequestAsyncAndParse client.performRequestAsync(req, responseListener); } - final ResponseListener wrapResponseListener404sOptional(CheckedFunction responseConverter, ActionListener> actionListener) { return new ResponseListener() { @@ -1617,7 +1615,7 @@ public void onFailure(Exception exception) { if (exception instanceof ResponseException) { ResponseException responseException = (ResponseException) exception; Response response = responseException.getResponse(); - if (404 == response.getStatusLine().getStatusCode()) { + if (RestStatus.NOT_FOUND.getStatus() == response.getStatusLine().getStatusCode()) { actionListener.onResponse(Optional.empty()); } else { actionListener.onFailure(parseResponseException(responseException)); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java index df9f4ba7a1b78..4bf7565222a73 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksClient.java @@ -83,7 +83,6 @@ public void listAsync(ListTasksRequest request, RequestOptions options, ActionLi public Optional get(GetTaskRequest request, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseOptionalEntity(request, TasksRequestConverters::getTask, options, GetTaskResponse::fromXContent); - } /** @@ -99,7 +98,6 @@ public void getAsync(GetTaskRequest request, RequestOptions options, ActionListe restHighLevelClient.performRequestAsyncAndParseOptionalEntity(request, TasksRequestConverters::getTask, options, GetTaskResponse::fromXContent, listener); } - /** * Cancel one or more cluster tasks using the Task Management API. diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java index 1bc5a54cf0100..065320e001470 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java @@ -23,6 +23,7 @@ import org.apache.http.client.methods.HttpPost; import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; +import org.elasticsearch.client.RequestConverters.EndpointBuilder; import org.elasticsearch.client.tasks.GetTaskRequest; final class TasksRequestConverters { @@ -57,9 +58,13 @@ static Request listTasks(ListTasksRequest listTaskRequest) { } static Request getTask(GetTaskRequest getTaskRequest) { - Request request = new Request(HttpGet.METHOD_NAME, "_tasks/" + getTaskRequest.getNodeId() + ":" + getTaskRequest.getTaskId()); + String endpoint = new EndpointBuilder().addPathPartAsIs("_tasks") + .addColonSeparatedPathParts(getTaskRequest.getNodeId(), Long.toString(getTaskRequest.getTaskId())) + .build(); + Request request = new Request(HttpGet.METHOD_NAME, endpoint); RequestConverters.Params params = new RequestConverters.Params(request); - params.withTimeout(getTaskRequest.getTimeout()).withWaitForCompletion(getTaskRequest.getWaitForCompletion()); + params.withTimeout(getTaskRequest.getTimeout()) + .withWaitForCompletion(getTaskRequest.getWaitForCompletion()); return request; } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java index 8e9474d4a173b..423658341d01b 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java @@ -31,13 +31,10 @@ public class GetTaskRequest implements Validatable { private boolean waitForCompletion = false; private TimeValue timeout = null; - public GetTaskRequest(String nodeId, long taskId) { this.nodeId = nodeId; this.taskId = taskId; } - - public String getNodeId() { return nodeId; @@ -77,7 +74,6 @@ public GetTaskRequest setTimeout(TimeValue timeout) { return this; } - @Override public Optional validate() { final ValidationException validationException = new ValidationException(); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java index b62a3f77f12dc..3b5c6a3778ad3 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java @@ -29,25 +29,26 @@ public class GetTaskResponse { private final boolean completed; private final TaskInfo taskInfo; + public GetTaskResponse(boolean completed, TaskInfo taskInfo) { this.completed = completed; this.taskInfo = taskInfo; } + public boolean isCompleted() { return completed; } + public TaskInfo getTaskInfo() { return taskInfo; } - - + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("get_task", true, a -> new GetTaskResponse((boolean) a[0], (TaskInfo) a[1])); static { PARSER.declareBoolean(constructorArg(), new ParseField("completed")); PARSER.declareObject(constructorArg(), (p, c) -> TaskInfo.fromXContent(p), new ParseField("task")); } - public static GetTaskResponse fromXContent(XContentParser parser) { return PARSER.apply(parser, null); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java index c1ac90c0de11c..255a450e5d42b 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java @@ -99,16 +99,20 @@ public void testGetValidTask() throws IOException { request.setJsonEntity("{" + " \"source\": {\n" + " \"index\": \"source1\"\n" + " },\n" + " \"dest\": {\n" + " \"index\": \"dest\"\n" + " }" + "}"); Response response = lowClient.performRequest(request); - String responseBody = EntityUtils.toString(response.getEntity()); - Map map = XContentHelper.convertToMap(JsonXContent.jsonXContent, responseBody, false); + Map map = entityAsMap(response); Object taskId = map.get("task"); assertNotNull(taskId); TaskId childTaskId = new TaskId(taskId.toString()); GetTaskRequest gtr = new GetTaskRequest(childTaskId.getNodeId(), childTaskId.getId()); + gtr.setWaitForCompletion(randomBoolean()); Optional getTaskResponse = execute(gtr, highLevelClient().tasks()::get, highLevelClient().tasks()::getAsync); assertTrue(getTaskResponse.isPresent()); - TaskInfo info = getTaskResponse.get().getTaskInfo(); + GetTaskResponse taskResponse = getTaskResponse.get(); + if (gtr.getWaitForCompletion()) { + assertTrue(taskResponse.isCompleted()); + } + TaskInfo info = taskResponse.getTaskInfo(); assertTrue(info.isCancellable()); assertEquals("reindex from [source1] to [dest]", info.getDescription()); assertEquals("indices:data/write/reindex", info.getAction()); From 6ab1881d32d2c7a6702844e100b6f6a33e1c6374 Mon Sep 17 00:00:00 2001 From: markharwood Date: Tue, 6 Nov 2018 12:04:40 +0000 Subject: [PATCH 7/9] Unused imports --- .../src/test/java/org/elasticsearch/client/TasksIT.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java index 255a450e5d42b..52e6d7d3bd756 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/TasksIT.java @@ -19,7 +19,6 @@ package org.elasticsearch.client; -import org.apache.http.util.EntityUtils; import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; @@ -31,9 +30,7 @@ import org.elasticsearch.client.tasks.GetTaskRequest; import org.elasticsearch.client.tasks.GetTaskResponse; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskInfo; From 4a1e344a110228bddc4131efb396e25bf1ee5965 Mon Sep 17 00:00:00 2001 From: markharwood Date: Thu, 8 Nov 2018 15:43:46 +0000 Subject: [PATCH 8/9] Added GetTaskResponseTest, tidied endpoint building, removed weird Javadoc --- .../client/RequestConverters.java | 5 - .../client/TasksRequestConverters.java | 2 +- .../client/tasks/GetTaskRequest.java | 2 +- .../client/tasks/GetTaskResponse.java | 6 +- .../core/tasks/GetTaskResponseTest.java | 107 ++++++++++++++++++ 5 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index d3f2603597286..d448275d35845 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -1020,11 +1020,6 @@ EndpointBuilder addPathPart(String... parts) { return this; } - EndpointBuilder addColonSeparatedPathParts(String... parts) { - addPathPart(String.join(":", parts)); - return this; - } - EndpointBuilder addCommaSeparatedPathParts(String[] parts) { addPathPart(String.join(",", parts)); return this; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java index 065320e001470..f0e9cf4e025f6 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/TasksRequestConverters.java @@ -59,7 +59,7 @@ static Request listTasks(ListTasksRequest listTaskRequest) { static Request getTask(GetTaskRequest getTaskRequest) { String endpoint = new EndpointBuilder().addPathPartAsIs("_tasks") - .addColonSeparatedPathParts(getTaskRequest.getNodeId(), Long.toString(getTaskRequest.getTaskId())) + .addPathPartAsIs(getTaskRequest.getNodeId() + ":" + Long.toString(getTaskRequest.getTaskId())) .build(); Request request = new Request(HttpGet.METHOD_NAME, endpoint); RequestConverters.Params params = new RequestConverters.Params(request); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java index 423658341d01b..0dc3168937573 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskRequest.java @@ -67,7 +67,7 @@ public TimeValue getTimeout() { } /** - * Timeout to wait for any async actions this request must take. It must take anywhere from 0 to 2. + * Timeout to wait for any async actions this request must take. */ public GetTaskRequest setTimeout(TimeValue timeout) { this.timeout = timeout; diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java index 3b5c6a3778ad3..05d40f12f5b21 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/tasks/GetTaskResponse.java @@ -29,6 +29,8 @@ public class GetTaskResponse { private final boolean completed; private final TaskInfo taskInfo; + public static final ParseField COMPLETED = new ParseField("completed"); + public static final ParseField TASK = new ParseField("task"); public GetTaskResponse(boolean completed, TaskInfo taskInfo) { this.completed = completed; @@ -46,8 +48,8 @@ public TaskInfo getTaskInfo() { private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("get_task", true, a -> new GetTaskResponse((boolean) a[0], (TaskInfo) a[1])); static { - PARSER.declareBoolean(constructorArg(), new ParseField("completed")); - PARSER.declareObject(constructorArg(), (p, c) -> TaskInfo.fromXContent(p), new ParseField("task")); + PARSER.declareBoolean(constructorArg(), COMPLETED); + PARSER.declareObject(constructorArg(), (p, c) -> TaskInfo.fromXContent(p), TASK); } public static GetTaskResponse fromXContent(XContentParser parser) { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java new file mode 100644 index 0000000000000..ccae222e5b498 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java @@ -0,0 +1,107 @@ +/* + * 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.core.tasks; + +import org.elasticsearch.client.Requests; +import org.elasticsearch.client.tasks.GetTaskResponse; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.tasks.RawTaskStatus; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.tasks.TaskId; +import org.elasticsearch.tasks.TaskInfo; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester; + +public class GetTaskResponseTest extends ESTestCase { + + public void testFromXContent() throws IOException { + xContentTester( + this::createParser, + this::createTestInstance, + this::toXContent, + GetTaskResponse::fromXContent) + .supportsUnknownFields(true) + .assertEqualsConsumer(this::assertEqualInstances) + .assertToXContentEquivalence(true) + .randomFieldsExcludeFilter(field ->field.endsWith("headers") || field.endsWith("status")) + .test(); + } + + private GetTaskResponse createTestInstance() { + return new GetTaskResponse(randomBoolean(), randomTaskInfo()); + } + + private void toXContent(GetTaskResponse response, XContentBuilder builder) throws IOException { + builder.startObject(); + { + builder.field(GetTaskResponse.COMPLETED.getPreferredName(), response.isCompleted()); + builder.startObject(GetTaskResponse.TASK.getPreferredName()); + response.getTaskInfo().toXContent(builder, ToXContent.EMPTY_PARAMS); + builder.endObject(); + } + builder.endObject(); + } + + private void assertEqualInstances(GetTaskResponse expectedInstance, GetTaskResponse newInstance) { + assertEquals(expectedInstance.isCompleted(), newInstance.isCompleted()); + assertEquals(expectedInstance.getTaskInfo(), newInstance.getTaskInfo()); + } + + static TaskInfo randomTaskInfo() { + TaskId taskId = randomTaskId(); + String type = randomAlphaOfLength(5); + String action = randomAlphaOfLength(5); + Task.Status status = randomBoolean() ? randomRawTaskStatus() : null; + String description = randomBoolean() ? randomAlphaOfLength(5) : null; + long startTime = randomLong(); + long runningTimeNanos = randomLong(); + boolean cancellable = randomBoolean(); + TaskId parentTaskId = randomBoolean() ? TaskId.EMPTY_TASK_ID : randomTaskId(); + Map headers = randomBoolean() ? + Collections.emptyMap() : + Collections.singletonMap(randomAlphaOfLength(5), randomAlphaOfLength(5)); + return new TaskInfo(taskId, type, action, description, status, startTime, runningTimeNanos, cancellable, parentTaskId, headers); + } + + private static TaskId randomTaskId() { + return new TaskId(randomAlphaOfLength(5), randomLong()); + } + + private static RawTaskStatus randomRawTaskStatus() { + try (XContentBuilder builder = XContentBuilder.builder(Requests.INDEX_CONTENT_TYPE.xContent())) { + builder.startObject(); + int fields = between(0, 10); + for (int f = 0; f < fields; f++) { + builder.field(randomAlphaOfLength(5), randomAlphaOfLength(5)); + } + builder.endObject(); + return new RawTaskStatus(BytesReference.bytes(builder)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} From ff8436fd4dd7c4350bebad758c8ada641bad384e Mon Sep 17 00:00:00 2001 From: markharwood Date: Thu, 8 Nov 2018 17:19:40 +0000 Subject: [PATCH 9/9] Renamed due to failing name convention checks --- .../{GetTaskResponseTest.java => GetTaskResponseTests.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/{GetTaskResponseTest.java => GetTaskResponseTests.java} (98%) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTests.java similarity index 98% rename from client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java rename to client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTests.java index ccae222e5b498..60a52a7ff3d37 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTest.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/core/tasks/GetTaskResponseTests.java @@ -36,7 +36,7 @@ import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester; -public class GetTaskResponseTest extends ESTestCase { +public class GetTaskResponseTests extends ESTestCase { public void testFromXContent() throws IOException { xContentTester(