From e401710f6ea7fd43b1ddb70dd3f5a017d90a1eaf Mon Sep 17 00:00:00 2001 From: olcbean Date: Sun, 24 Jun 2018 04:14:34 +0200 Subject: [PATCH 01/23] TEST: Correct the assertion arguments order (#31540) This commit corrects the order of the assertion arguments in HLRest client. --- .../documentation/CRUDDocumentationIT.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CRUDDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CRUDDocumentationIT.java index 4193685f14bc2..b8a6b7d2d8ad2 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CRUDDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CRUDDocumentationIT.java @@ -113,7 +113,7 @@ public void testIndex() throws Exception { .source(jsonMap); // <1> //end::index-request-map IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); - assertEquals(indexResponse.getResult(), DocWriteResponse.Result.CREATED); + assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult()); } { //tag::index-request-xcontent @@ -129,7 +129,7 @@ public void testIndex() throws Exception { .source(builder); // <1> //end::index-request-xcontent IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); - assertEquals(indexResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, indexResponse.getResult()); } { //tag::index-request-shortcut @@ -139,7 +139,7 @@ public void testIndex() throws Exception { "message", "trying out Elasticsearch"); // <1> //end::index-request-shortcut IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); - assertEquals(indexResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, indexResponse.getResult()); } { //tag::index-request-string @@ -158,7 +158,7 @@ public void testIndex() throws Exception { // tag::index-execute IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT); // end::index-execute - assertEquals(indexResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, indexResponse.getResult()); // tag::index-response String index = indexResponse.getIndex(); @@ -269,7 +269,7 @@ public void testUpdate() throws Exception { { IndexRequest indexRequest = new IndexRequest("posts", "doc", "1").source("field", 0); IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); - assertSame(indexResponse.status(), RestStatus.CREATED); + assertSame(RestStatus.CREATED, indexResponse.status()); Request request = new Request("POST", "/_scripts/increment-field"); request.setJsonEntity(Strings.toString(JsonXContent.contentBuilder() @@ -280,7 +280,7 @@ public void testUpdate() throws Exception { .endObject() .endObject())); Response response = client().performRequest(request); - assertEquals(response.getStatusLine().getStatusCode(), RestStatus.OK.getStatus()); + assertEquals(RestStatus.OK.getStatus(), response.getStatusLine().getStatusCode()); } { //tag::update-request @@ -298,7 +298,7 @@ public void testUpdate() throws Exception { request.script(inline); // <3> //end::update-request-with-inline-script UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); assertEquals(4, updateResponse.getGetResult().getSource().get("field")); request = new UpdateRequest("posts", "doc", "1").fetchSource(true); @@ -308,7 +308,7 @@ public void testUpdate() throws Exception { request.script(stored); // <2> //end::update-request-with-stored-script updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); assertEquals(8, updateResponse.getGetResult().getSource().get("field")); } { @@ -320,7 +320,7 @@ public void testUpdate() throws Exception { .doc(jsonMap); // <1> //end::update-request-with-doc-as-map UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); } { //tag::update-request-with-doc-as-xcontent @@ -335,7 +335,7 @@ public void testUpdate() throws Exception { .doc(builder); // <1> //end::update-request-with-doc-as-xcontent UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); } { //tag::update-request-shortcut @@ -344,7 +344,7 @@ public void testUpdate() throws Exception { "reason", "daily update"); // <1> //end::update-request-shortcut UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); } { //tag::update-request-with-doc-as-string @@ -359,7 +359,7 @@ public void testUpdate() throws Exception { // tag::update-execute UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); // end::update-execute - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); // tag::update-response String index = updateResponse.getIndex(); @@ -434,7 +434,7 @@ public void testUpdate() throws Exception { request.fetchSource(true); // <1> //end::update-request-no-source UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); assertNotNull(updateResponse.getGetResult()); assertEquals(3, updateResponse.getGetResult().sourceAsMap().size()); } @@ -446,7 +446,7 @@ public void testUpdate() throws Exception { request.fetchSource(new FetchSourceContext(true, includes, excludes)); // <1> //end::update-request-source-include UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); Map sourceAsMap = updateResponse.getGetResult().sourceAsMap(); assertEquals(2, sourceAsMap.size()); assertEquals("source includes", sourceAsMap.get("reason")); @@ -460,7 +460,7 @@ public void testUpdate() throws Exception { request.fetchSource(new FetchSourceContext(true, includes, excludes)); // <1> //end::update-request-source-exclude UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT); - assertEquals(updateResponse.getResult(), DocWriteResponse.Result.UPDATED); + assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult()); Map sourceAsMap = updateResponse.getGetResult().sourceAsMap(); assertEquals(2, sourceAsMap.size()); assertEquals("source excludes", sourceAsMap.get("reason")); @@ -538,7 +538,7 @@ public void testDelete() throws Exception { { IndexRequest indexRequest = new IndexRequest("posts", "doc", "1").source("field", "value"); IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); - assertSame(indexResponse.status(), RestStatus.CREATED); + assertSame(RestStatus.CREATED, indexResponse.status()); } { @@ -552,7 +552,7 @@ public void testDelete() throws Exception { // tag::delete-execute DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT); // end::delete-execute - assertSame(deleteResponse.getResult(), DocWriteResponse.Result.DELETED); + assertSame(DocWriteResponse.Result.DELETED, deleteResponse.getResult()); // tag::delete-response String index = deleteResponse.getIndex(); @@ -605,7 +605,7 @@ public void testDelete() throws Exception { { IndexResponse indexResponse = client.index(new IndexRequest("posts", "doc", "1").source("field", "value") , RequestOptions.DEFAULT); - assertSame(indexResponse.status(), RestStatus.CREATED); + assertSame(RestStatus.CREATED, indexResponse.status()); // tag::delete-conflict try { @@ -621,7 +621,7 @@ public void testDelete() throws Exception { { IndexResponse indexResponse = client.index(new IndexRequest("posts", "doc", "async").source("field", "value"), RequestOptions.DEFAULT); - assertSame(indexResponse.status(), RestStatus.CREATED); + assertSame(RestStatus.CREATED, indexResponse.status()); DeleteRequest request = new DeleteRequest("posts", "doc", "async"); @@ -666,7 +666,7 @@ public void testBulk() throws Exception { // tag::bulk-execute BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT); // end::bulk-execute - assertSame(bulkResponse.status(), RestStatus.OK); + assertSame(RestStatus.OK, bulkResponse.status()); assertFalse(bulkResponse.hasFailures()); } { @@ -679,7 +679,7 @@ public void testBulk() throws Exception { .source(XContentType.JSON,"field", "baz")); // end::bulk-request-with-mixed-operations BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT); - assertSame(bulkResponse.status(), RestStatus.OK); + assertSame(RestStatus.OK, bulkResponse.status()); assertFalse(bulkResponse.hasFailures()); // tag::bulk-response @@ -778,7 +778,7 @@ public void testGet() throws Exception { "postDate", new Date(), "message", "trying out Elasticsearch"); IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); - assertEquals(indexResponse.getResult(), DocWriteResponse.Result.CREATED); + assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult()); } { //tag::get-request From 9efb0fe9bafef8c681e39cc143e864be61949f8f Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Sun, 24 Jun 2018 11:08:45 -0700 Subject: [PATCH 02/23] Ingest Attachment: Upgrade Tika to 1.18 (#31252) Fixes ES from hanging when a bad zip file is loaded through Tika. --- plugins/ingest-attachment/build.gradle | 18 +++++++++++------- .../licenses/commons-compress-1.14.jar.sha1 | 1 - .../licenses/commons-compress-1.16.1.jar.sha1 | 1 + .../licenses/commons-io-2.5.jar.sha1 | 1 - .../licenses/commons-io-2.6.jar.sha1 | 1 + .../licenses/fontbox-2.0.8.jar.sha1 | 1 - .../licenses/fontbox-2.0.9.jar.sha1 | 1 + .../licenses/pdfbox-2.0.8.jar.sha1 | 1 - .../licenses/pdfbox-2.0.9.jar.sha1 | 1 + .../licenses/tika-core-1.17.jar.sha1 | 1 - .../licenses/tika-core-1.18.jar.sha1 | 1 + .../licenses/tika-parsers-1.17.jar.sha1 | 1 - .../licenses/tika-parsers-1.18.jar.sha1 | 1 + .../licenses/xz-1.6.jar.sha1 | 1 - .../licenses/xz-1.8.jar.sha1 | 1 + .../ingest/attachment/TikaImpl.java | 1 + .../plugin-metadata/plugin-security.policy | 2 ++ .../attachment/AttachmentProcessorTests.java | 6 ++++++ .../attachment/test/sample-files/bad_tika.zip | Bin 0 -> 416772 bytes 19 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 plugins/ingest-attachment/licenses/commons-compress-1.14.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/commons-compress-1.16.1.jar.sha1 delete mode 100644 plugins/ingest-attachment/licenses/commons-io-2.5.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/commons-io-2.6.jar.sha1 delete mode 100644 plugins/ingest-attachment/licenses/fontbox-2.0.8.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/fontbox-2.0.9.jar.sha1 delete mode 100644 plugins/ingest-attachment/licenses/pdfbox-2.0.8.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/pdfbox-2.0.9.jar.sha1 delete mode 100644 plugins/ingest-attachment/licenses/tika-core-1.17.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/tika-core-1.18.jar.sha1 delete mode 100644 plugins/ingest-attachment/licenses/tika-parsers-1.17.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/tika-parsers-1.18.jar.sha1 delete mode 100644 plugins/ingest-attachment/licenses/xz-1.6.jar.sha1 create mode 100644 plugins/ingest-attachment/licenses/xz-1.8.jar.sha1 create mode 100644 plugins/ingest-attachment/src/test/resources/org/elasticsearch/ingest/attachment/test/sample-files/bad_tika.zip diff --git a/plugins/ingest-attachment/build.gradle b/plugins/ingest-attachment/build.gradle index 3bca078bd59c4..f000fdfeef5e0 100644 --- a/plugins/ingest-attachment/build.gradle +++ b/plugins/ingest-attachment/build.gradle @@ -23,8 +23,8 @@ esplugin { } versions << [ - 'tika': '1.17', - 'pdfbox': '2.0.8', + 'tika': '1.18', + 'pdfbox': '2.0.9', 'bouncycastle': '1.55', 'poi': '3.17', 'mime4j': '0.8.1' @@ -33,9 +33,10 @@ versions << [ dependencies { // mandatory for tika compile "org.apache.tika:tika-core:${versions.tika}" + // build against Jackson 2.9.5, but still works on our current version compile "org.apache.tika:tika-parsers:${versions.tika}" - compile 'org.tukaani:xz:1.6' - compile 'commons-io:commons-io:2.5' + compile 'org.tukaani:xz:1.8' + compile 'commons-io:commons-io:2.6' compile "org.slf4j:slf4j-api:${versions.slf4j}" // character set detection @@ -62,7 +63,7 @@ dependencies { // MS Office compile "org.apache.poi:poi-scratchpad:${versions.poi}" // Apple iWork - compile 'org.apache.commons:commons-compress:1.14' + compile 'org.apache.commons:commons-compress:1.16.1' // Outlook documents compile "org.apache.james:apache-mime4j-core:${versions.mime4j}" compile "org.apache.james:apache-mime4j-dom:${versions.mime4j}" @@ -118,6 +119,10 @@ thirdPartyAudit.excludes = [ 'com.drew.metadata.jpeg.JpegDirectory', 'com.github.junrar.Archive', 'com.github.junrar.rarfile.FileHeader', + 'com.github.luben.zstd.ZstdInputStream', + 'com.github.luben.zstd.ZstdOutputStream', + 'com.github.openjson.JSONArray', + 'com.github.openjson.JSONObject', 'com.google.common.reflect.TypeToken', 'com.google.gson.Gson', 'com.googlecode.mp4parser.DataSource', @@ -531,6 +536,7 @@ thirdPartyAudit.excludes = [ 'org.apache.commons.exec.PumpStreamHandler', 'org.apache.commons.exec.environment.EnvironmentUtils', 'org.apache.commons.lang.StringUtils', + 'org.apache.commons.lang.SystemUtils', 'org.apache.ctakes.typesystem.type.refsem.UmlsConcept', 'org.apache.ctakes.typesystem.type.textsem.IdentifiedAnnotation', 'org.apache.cxf.jaxrs.client.WebClient', @@ -635,8 +641,6 @@ thirdPartyAudit.excludes = [ 'org.etsi.uri.x01903.v13.impl.UnsignedSignaturePropertiesTypeImpl$1SignatureTimeStampList', 'org.etsi.uri.x01903.v14.ValidationDataType$Factory', 'org.etsi.uri.x01903.v14.ValidationDataType', - 'org.json.JSONArray', - 'org.json.JSONObject', 'org.json.simple.JSONArray', 'org.json.simple.JSONObject', 'org.json.simple.parser.JSONParser', diff --git a/plugins/ingest-attachment/licenses/commons-compress-1.14.jar.sha1 b/plugins/ingest-attachment/licenses/commons-compress-1.14.jar.sha1 deleted file mode 100644 index a93cac2243e69..0000000000000 --- a/plugins/ingest-attachment/licenses/commons-compress-1.14.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -7b18320d668ab080758bf5383d6d8fcf750babce \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/commons-compress-1.16.1.jar.sha1 b/plugins/ingest-attachment/licenses/commons-compress-1.16.1.jar.sha1 new file mode 100644 index 0000000000000..93be07c90a41c --- /dev/null +++ b/plugins/ingest-attachment/licenses/commons-compress-1.16.1.jar.sha1 @@ -0,0 +1 @@ +7b5cdabadb4cf12f5ee0f801399e70635583193f \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/commons-io-2.5.jar.sha1 b/plugins/ingest-attachment/licenses/commons-io-2.5.jar.sha1 deleted file mode 100644 index b7f1d93e89702..0000000000000 --- a/plugins/ingest-attachment/licenses/commons-io-2.5.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -2852e6e05fbb95076fc091f6d1780f1f8fe35e0f \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/commons-io-2.6.jar.sha1 b/plugins/ingest-attachment/licenses/commons-io-2.6.jar.sha1 new file mode 100644 index 0000000000000..75f7934c08267 --- /dev/null +++ b/plugins/ingest-attachment/licenses/commons-io-2.6.jar.sha1 @@ -0,0 +1 @@ +815893df5f31da2ece4040fe0a12fd44b577afaf \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/fontbox-2.0.8.jar.sha1 b/plugins/ingest-attachment/licenses/fontbox-2.0.8.jar.sha1 deleted file mode 100644 index f8abddbc755eb..0000000000000 --- a/plugins/ingest-attachment/licenses/fontbox-2.0.8.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -52f852fcfc7481d45efdffd224eb78b85981b17b \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/fontbox-2.0.9.jar.sha1 b/plugins/ingest-attachment/licenses/fontbox-2.0.9.jar.sha1 new file mode 100644 index 0000000000000..4ded3b5488825 --- /dev/null +++ b/plugins/ingest-attachment/licenses/fontbox-2.0.9.jar.sha1 @@ -0,0 +1 @@ +f961f17ebdbc307e9055e3cf7c0e207f0895ae55 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/pdfbox-2.0.8.jar.sha1 b/plugins/ingest-attachment/licenses/pdfbox-2.0.8.jar.sha1 deleted file mode 100644 index 1c346871e2119..0000000000000 --- a/plugins/ingest-attachment/licenses/pdfbox-2.0.8.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -17bdf273d66f3afe41eedb9d3ab6a7b819c44a0c \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/pdfbox-2.0.9.jar.sha1 b/plugins/ingest-attachment/licenses/pdfbox-2.0.9.jar.sha1 new file mode 100644 index 0000000000000..9bf91e07976c2 --- /dev/null +++ b/plugins/ingest-attachment/licenses/pdfbox-2.0.9.jar.sha1 @@ -0,0 +1 @@ +d0425578218624388f2ec84a0b3a11efd55df0f5 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/tika-core-1.17.jar.sha1 b/plugins/ingest-attachment/licenses/tika-core-1.17.jar.sha1 deleted file mode 100644 index 571314b3378da..0000000000000 --- a/plugins/ingest-attachment/licenses/tika-core-1.17.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -b450102c2aee98107474d2f92661d947b9cef183 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/tika-core-1.18.jar.sha1 b/plugins/ingest-attachment/licenses/tika-core-1.18.jar.sha1 new file mode 100644 index 0000000000000..ef162f03439cc --- /dev/null +++ b/plugins/ingest-attachment/licenses/tika-core-1.18.jar.sha1 @@ -0,0 +1 @@ +69556697de96cf0b22df846e970dafd29866eee0 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/tika-parsers-1.17.jar.sha1 b/plugins/ingest-attachment/licenses/tika-parsers-1.17.jar.sha1 deleted file mode 100644 index c4487e4970f25..0000000000000 --- a/plugins/ingest-attachment/licenses/tika-parsers-1.17.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4277c54fcaed542fbc8a0001fdb4c23baccc0132 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/tika-parsers-1.18.jar.sha1 b/plugins/ingest-attachment/licenses/tika-parsers-1.18.jar.sha1 new file mode 100644 index 0000000000000..6441e8b64e7b7 --- /dev/null +++ b/plugins/ingest-attachment/licenses/tika-parsers-1.18.jar.sha1 @@ -0,0 +1 @@ +7d9b6dea91d783165f3313d320d3aaaa9a4dfc13 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/xz-1.6.jar.sha1 b/plugins/ingest-attachment/licenses/xz-1.6.jar.sha1 deleted file mode 100644 index d91cd44c0b4d3..0000000000000 --- a/plugins/ingest-attachment/licenses/xz-1.6.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -05b6f921f1810bdf90e25471968f741f87168b64 \ No newline at end of file diff --git a/plugins/ingest-attachment/licenses/xz-1.8.jar.sha1 b/plugins/ingest-attachment/licenses/xz-1.8.jar.sha1 new file mode 100644 index 0000000000000..7455feac7983b --- /dev/null +++ b/plugins/ingest-attachment/licenses/xz-1.8.jar.sha1 @@ -0,0 +1 @@ +c4f7d054303948eb6a4066194253886c8af07128 \ No newline at end of file diff --git a/plugins/ingest-attachment/src/main/java/org/elasticsearch/ingest/attachment/TikaImpl.java b/plugins/ingest-attachment/src/main/java/org/elasticsearch/ingest/attachment/TikaImpl.java index 97ca1c0b19774..6606d1bc72727 100644 --- a/plugins/ingest-attachment/src/main/java/org/elasticsearch/ingest/attachment/TikaImpl.java +++ b/plugins/ingest-attachment/src/main/java/org/elasticsearch/ingest/attachment/TikaImpl.java @@ -159,6 +159,7 @@ static PermissionCollection getRestrictedPermissions() { perms.add(new SecurityPermission("putProviderProperty.BC")); perms.add(new SecurityPermission("insertProvider")); perms.add(new ReflectPermission("suppressAccessChecks")); + perms.add(new RuntimePermission("accessClassInPackage.sun.java2d.cmm.kcms")); // xmlbeans, use by POI, needs to get the context classloader perms.add(new RuntimePermission("getClassLoader")); // ZipFile needs accessDeclaredMembers on JDK 10; cf. https://bugs.openjdk.java.net/browse/JDK-8187485 diff --git a/plugins/ingest-attachment/src/main/plugin-metadata/plugin-security.policy b/plugins/ingest-attachment/src/main/plugin-metadata/plugin-security.policy index 0cd359a99731b..bcc5eef3193d7 100644 --- a/plugins/ingest-attachment/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/ingest-attachment/src/main/plugin-metadata/plugin-security.policy @@ -31,4 +31,6 @@ grant { permission java.lang.RuntimePermission "getClassLoader"; // ZipFile needs accessDeclaredMembers on Java 10 permission java.lang.RuntimePermission "accessDeclaredMembers"; + // PDFBox checks for the existence of this class + permission java.lang.RuntimePermission "accessClassInPackage.sun.java2d.cmm.kcms"; }; diff --git a/plugins/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java b/plugins/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java index 598d3f4e8175c..654bc361f53ad 100644 --- a/plugins/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java +++ b/plugins/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java @@ -214,6 +214,12 @@ public void testAsciidocDocument() throws Exception { assertThat(attachmentData.get("content_type").toString(), containsString("text/plain")); } + // See (https://issues.apache.org/jira/browse/COMPRESS-432) for information + // about the issue that causes a zip file to hang in Tika versions prior to 1.18. + public void testZipFileDoesNotHang() { + expectThrows(Exception.class, () -> parseDocument("bad_tika.zip", processor)); + } + public void testParseAsBytesArray() throws Exception { String path = "/org/elasticsearch/ingest/attachment/test/sample-files/text-in-english.txt"; byte[] bytes; diff --git a/plugins/ingest-attachment/src/test/resources/org/elasticsearch/ingest/attachment/test/sample-files/bad_tika.zip b/plugins/ingest-attachment/src/test/resources/org/elasticsearch/ingest/attachment/test/sample-files/bad_tika.zip new file mode 100644 index 0000000000000000000000000000000000000000..58ebd8411edcea1a51091369feeddae52719f1d1 GIT binary patch literal 416772 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

xh_eRE(`EKSUvbHTHHs-7$M(Q5vO*c03Jkd+r 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 z

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

X2?AtPFvy-nlgfvzliaIh@| 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%0DP3op-zwArd@a;kw40Dx+ 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 O&k`QqW8jw|Ap8$J?>Jci literal 0 HcmV?d00001 From 629c376f02440fdbc704645c9568327044b939dc Mon Sep 17 00:00:00 2001 From: Tom Callahan Date: Sun, 24 Jun 2018 15:39:56 -0400 Subject: [PATCH 03/23] Close xcontent parsers (partial) (#31513) Partial pass at closing XContentParsers in server. This mostly involved adding try-with-resources statements around the usage of XContentParsers. --- .../template/put/PutIndexTemplateRequest.java | 7 +- .../ClusterUpdateSettingsRequestTests.java | 11 +- .../create/CreateIndexRequestTests.java | 9 +- .../mapping/put/PutMappingRequestTests.java | 7 +- .../indices/shrink/ResizeRequestTests.java | 5 +- .../action/get/MultiGetRequestTests.java | 30 +- .../action/get/MultiGetResponseTests.java | 10 +- .../search/MultiSearchResponseTests.java | 8 +- .../cluster/metadata/MetaDataTests.java | 13 +- .../common/geo/BaseGeoParsingTestCase.java | 14 +- .../common/geo/GeoJsonShapeParserTests.java | 260 ++++++++++------- .../common/geo/GeoUtilTests.java | 17 +- .../AbstractShapeBuilderTestCase.java | 13 +- .../common/unit/FuzzinessTests.java | 94 +++--- .../common/xcontent/BaseXContentTestCase.java | 211 ++++++------- .../builder/XContentBuilderTests.java | 61 ++-- .../cbor/CborXContentParserTests.java | 7 +- .../common/xcontent/cbor/JsonVsCborTests.java | 6 +- .../xcontent/smile/JsonVsSmileTests.java | 6 +- .../AbstractXContentFilteringTestCase.java | 6 +- .../org/elasticsearch/index/IndexTests.java | 7 +- .../index/query/BoolQueryBuilderTests.java | 7 +- .../index/query/InnerHitBuilderTests.java | 11 +- .../search/geo/GeoPointParsingTests.java | 93 +++--- .../index/search/geo/GeoUtilsTests.java | 191 ++++++------ .../ingest/IngestMetadataTests.java | 19 +- .../PersistentTasksCustomMetaDataTests.java | 6 +- .../repositories/RepositoryDataTests.java | 35 ++- .../admin/indices/RestAnalyzeActionTests.java | 141 ++++----- .../org/elasticsearch/script/ScriptTests.java | 8 +- .../search/NestedIdentityTests.java | 9 +- .../AggregationCollectorTests.java | 15 +- .../BasePipelineAggregationTestCase.java | 15 +- .../aggregations/bucket/FiltersTests.java | 59 ++-- .../SignificanceHeuristicTests.java | 12 +- .../support/IncludeExcludeTests.java | 70 ++--- .../builder/SearchSourceBuilderTests.java | 4 +- .../highlight/HighlightBuilderTests.java | 76 ++--- .../highlight/HighlightFieldTests.java | 19 +- .../rescore/QueryRescorerBuilderTests.java | 71 +++-- .../searchafter/SearchAfterBuilderTests.java | 28 +- .../search/slice/SliceBuilderTests.java | 11 +- .../search/sort/AbstractSortTestCase.java | 31 +- .../search/sort/FieldSortBuilderTests.java | 17 +- .../sort/GeoDistanceSortBuilderTests.java | 25 +- .../search/sort/NestedSortBuilderTests.java | 13 +- .../search/sort/ScriptSortBuilderTests.java | 97 +++--- .../search/sort/SortBuilderTests.java | 13 +- .../AbstractSuggestionBuilderTestCase.java | 15 +- .../search/suggest/SuggestBuilderTests.java | 11 +- .../CategoryContextMappingTests.java | 276 +++++++++--------- .../phrase/DirectCandidateGeneratorTests.java | 20 +- .../phrase/SmoothingModelTestCase.java | 13 +- 53 files changed, 1197 insertions(+), 1036 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java index 5d4e558dbb25b..5afba8f66aed3 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java @@ -558,9 +558,10 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject("mappings"); for (Map.Entry entry : mappings.entrySet()) { builder.field(entry.getKey()); - XContentParser parser = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, - DeprecationHandler.THROW_UNSUPPORTED_OPERATION, entry.getValue()); - builder.copyCurrentStructure(parser); + try (XContentParser parser = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, + DeprecationHandler.THROW_UNSUPPORTED_OPERATION, entry.getValue())) { + builder.copyCurrentStructure(parser); + } } builder.endObject(); diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java index c358d0fb6ca52..9701e76619824 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java @@ -58,12 +58,13 @@ private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws assertThat(iae.getMessage(), containsString("[cluster_update_settings_request] unknown field [" + unsupportedField + "], parser not found")); } else { - XContentParser parser = createParser(xContentType.xContent(), originalBytes); - ClusterUpdateSettingsRequest parsedRequest = ClusterUpdateSettingsRequest.fromXContent(parser); + try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) { + ClusterUpdateSettingsRequest parsedRequest = ClusterUpdateSettingsRequest.fromXContent(parser); - assertNull(parser.nextToken()); - assertThat(parsedRequest.transientSettings(), equalTo(request.transientSettings())); - assertThat(parsedRequest.persistentSettings(), equalTo(request.persistentSettings())); + assertNull(parser.nextToken()); + assertThat(parsedRequest.transientSettings(), equalTo(request.transientSettings())); + assertThat(parsedRequest.persistentSettings(), equalTo(request.persistentSettings())); + } } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java index e50805ab5b263..1c27934927413 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java @@ -134,11 +134,12 @@ public static void assertMappingsEqual(Map expected, Map expectedEntry : expected.entrySet()) { String expectedValue = expectedEntry.getValue(); String actualValue = actual.get(expectedEntry.getKey()); - XContentParser expectedJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, + try (XContentParser expectedJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, expectedValue); - XContentParser actualJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, - LoggingDeprecationHandler.INSTANCE, actualValue); - assertEquals(expectedJson.map(), actualJson.map()); + XContentParser actualJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, + LoggingDeprecationHandler.INSTANCE, actualValue)){ + assertEquals(expectedJson.map(), actualJson.map()); + } } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java index e816b08187f1b..be44d790b4004 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java @@ -147,9 +147,10 @@ public void testToAndFromXContent() throws IOException { private void assertMappingsEqual(String expected, String actual) throws IOException { - XContentParser expectedJson = createParser(XContentType.JSON.xContent(), expected); - XContentParser actualJson = createParser(XContentType.JSON.xContent(), actual); - assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered()); + try (XContentParser expectedJson = createParser(XContentType.JSON.xContent(), expected); + XContentParser actualJson = createParser(XContentType.JSON.xContent(), actual)) { + assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered()); + } } /** diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java index 4fa99374f0fab..ffbab5805c0a6 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.test.ESTestCase; @@ -93,7 +94,9 @@ public void testToAndFromXContent() throws IOException { ResizeRequest parsedResizeRequest = new ResizeRequest(resizeRequest.getTargetIndexRequest().index(), resizeRequest.getSourceIndex()); - parsedResizeRequest.fromXContent(createParser(xContentType.xContent(), originalBytes)); + try (XContentParser xParser = createParser(xContentType.xContent(), originalBytes)) { + parsedResizeRequest.fromXContent(xParser); + } assertEquals(resizeRequest.getSourceIndex(), parsedResizeRequest.getSourceIndex()); assertEquals(resizeRequest.getTargetIndexRequest().index(), parsedResizeRequest.getTargetIndexRequest().index()); diff --git a/server/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java b/server/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java index f1de226704e53..fcb4539c9afe7 100644 --- a/server/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java @@ -54,9 +54,9 @@ public void testAddWithInvalidKey() throws IOException { builder.endArray(); } builder.endObject(); - final XContentParser parser = createParser(builder); - final MultiGetRequest mgr = new MultiGetRequest(); - final ParsingException e = expectThrows( + try (XContentParser parser = createParser(builder)) { + final MultiGetRequest mgr = new MultiGetRequest(); + final ParsingException e = expectThrows( ParsingException.class, () -> { final String defaultIndex = randomAlphaOfLength(5); @@ -64,9 +64,10 @@ public void testAddWithInvalidKey() throws IOException { final FetchSourceContext fetchSource = FetchSourceContext.FETCH_SOURCE; mgr.add(defaultIndex, defaultType, null, fetchSource, null, parser, true); }); - assertThat( + assertThat( e.toString(), containsString("unknown key [doc] for a START_ARRAY, expected [docs] or [ids]")); + } } public void testUnexpectedField() throws IOException { @@ -141,16 +142,17 @@ public void testXContentSerialization() throws IOException { MultiGetRequest expected = createTestInstance(); XContentType xContentType = randomFrom(XContentType.values()); BytesReference shuffled = toShuffledXContent(expected, xContentType, ToXContent.EMPTY_PARAMS, false); - XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled); - MultiGetRequest actual = new MultiGetRequest(); - actual.add(null, null, null, null, null, parser, true); - assertThat(parser.nextToken(), nullValue()); - - assertThat(actual.items.size(), equalTo(expected.items.size())); - for (int i = 0; i < expected.items.size(); i++) { - MultiGetRequest.Item expectedItem = expected.items.get(i); - MultiGetRequest.Item actualItem = actual.items.get(i); - assertThat(actualItem, equalTo(expectedItem)); + try (XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled)) { + MultiGetRequest actual = new MultiGetRequest(); + actual.add(null, null, null, null, null, parser, true); + assertThat(parser.nextToken(), nullValue()); + + assertThat(actual.items.size(), equalTo(expected.items.size())); + for (int i = 0; i < expected.items.size(); i++) { + MultiGetRequest.Item expectedItem = expected.items.get(i); + MultiGetRequest.Item actualItem = actual.items.get(i); + assertThat(actualItem, equalTo(expectedItem)); + } } } } diff --git a/server/src/test/java/org/elasticsearch/action/get/MultiGetResponseTests.java b/server/src/test/java/org/elasticsearch/action/get/MultiGetResponseTests.java index 1eae583316e15..6331d5ef31dff 100644 --- a/server/src/test/java/org/elasticsearch/action/get/MultiGetResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/get/MultiGetResponseTests.java @@ -39,10 +39,11 @@ public void testFromXContent() throws IOException { MultiGetResponse expected = createTestInstance(); XContentType xContentType = randomFrom(XContentType.values()); BytesReference shuffled = toShuffledXContent(expected, xContentType, ToXContent.EMPTY_PARAMS, false); - - XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled); - MultiGetResponse parsed = MultiGetResponse.fromXContent(parser); - assertNull(parser.nextToken()); + MultiGetResponse parsed; + try (XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled)) { + parsed = MultiGetResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } assertNotSame(expected, parsed); assertThat(parsed.getResponses().length, equalTo(expected.getResponses().length)); @@ -60,6 +61,7 @@ public void testFromXContent() throws IOException { assertThat(actualItem.getResponse(), equalTo(expectedItem.getResponse())); } } + } } diff --git a/server/src/test/java/org/elasticsearch/action/search/MultiSearchResponseTests.java b/server/src/test/java/org/elasticsearch/action/search/MultiSearchResponseTests.java index 874bea5ff657e..4f1fa4cf06116 100644 --- a/server/src/test/java/org/elasticsearch/action/search/MultiSearchResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/MultiSearchResponseTests.java @@ -40,9 +40,11 @@ public void testFromXContent() throws IOException { MultiSearchResponse expected = createTestInstance(); XContentType xContentType = randomFrom(XContentType.values()); BytesReference shuffled = toShuffledXContent(expected, xContentType, ToXContent.EMPTY_PARAMS, false); - XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled); - MultiSearchResponse actual = MultiSearchResponse.fromXContext(parser); - assertThat(parser.nextToken(), nullValue()); + MultiSearchResponse actual; + try (XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled)) { + actual = MultiSearchResponse.fromXContext(parser); + assertThat(parser.nextToken(), nullValue()); + } assertThat(actual.getTook(), equalTo(expected.getTook())); assertThat(actual.getResponses().length, equalTo(expected.getResponses().length)); diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java index 96a533118c8da..32dd4324ff835 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java @@ -181,8 +181,7 @@ public void testUnknownFieldClusterMetaData() throws IOException { .field("random", "value") .endObject() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, metadata); - try { + try (XContentParser parser = createParser(JsonXContent.jsonXContent, metadata)) { MetaData.Builder.fromXContent(parser); fail(); } catch (IllegalArgumentException e) { @@ -197,8 +196,7 @@ public void testUnknownFieldIndexMetaData() throws IOException { .field("random", "value") .endObject() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, metadata); - try { + try (XContentParser parser = createParser(JsonXContent.jsonXContent, metadata)) { IndexMetaData.Builder.fromXContent(parser); fail(); } catch (IllegalArgumentException e) { @@ -225,9 +223,10 @@ public void testXContentWithIndexGraveyard() throws IOException { builder.startObject(); originalMeta.toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - final MetaData fromXContentMeta = MetaData.fromXContent(parser); - assertThat(fromXContentMeta.indexGraveyard(), equalTo(originalMeta.indexGraveyard())); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + final MetaData fromXContentMeta = MetaData.fromXContent(parser); + assertThat(fromXContentMeta.indexGraveyard(), equalTo(originalMeta.indexGraveyard())); + } } public void testSerializationWithIndexGraveyard() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java b/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java index f7771f0f84466..023932be6a9d0 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java @@ -50,15 +50,17 @@ abstract class BaseGeoParsingTestCase extends ESTestCase { public abstract void testParseGeometryCollection() throws IOException; protected void assertValidException(XContentBuilder builder, Class expectedException) throws IOException { - XContentParser parser = createParser(builder); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, expectedException); + try (XContentParser parser = createParser(builder)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, expectedException); + } } protected void assertGeometryEquals(Shape expected, XContentBuilder geoJson) throws IOException { - XContentParser parser = createParser(geoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertEquals(expected, ShapeParser.parse(parser).build()); + try (XContentParser parser = createParser(geoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertEquals(expected, ShapeParser.parse(parser).build()); + } } protected ShapeCollection shapeCollection(Shape... shapes) { diff --git a/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java b/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java index 6f9128454f374..bb462ac60342f 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java @@ -193,18 +193,20 @@ public void testParseEnvelope() throws IOException { .startArray().value(50).value(-39).endArray() .endArray() .endObject(); - XContentParser parser = createParser(multilinesGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(multilinesGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test #4: "envelope" with empty coordinates multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "envelope") .startArray("coordinates") .endArray() .endObject(); - parser = createParser(multilinesGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(multilinesGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } } @Override @@ -266,9 +268,10 @@ public void testParse3DPolygon() throws IOException { Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, null); Mapper.BuilderContext mockBuilderContext = new Mapper.BuilderContext(indexSettings, new ContentPath()); final GeoShapeFieldMapper mapperBuilder = new GeoShapeFieldMapper.Builder("test").ignoreZValue(true).build(mockBuilderContext); - XContentParser parser = createParser(polygonGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertEquals(jtsGeom(expected), ShapeParser.parse(parser, mapperBuilder).build()); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertEquals(jtsGeom(expected), ShapeParser.parse(parser, mapperBuilder).build()); + } } public void testInvalidDimensionalPolygon() throws IOException { @@ -285,9 +288,10 @@ public void testInvalidDimensionalPolygon() throws IOException { .endArray() .endArray() .endObject(); - XContentParser parser = createParser(polygonGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } } public void testParseInvalidPoint() throws IOException { @@ -299,9 +303,10 @@ public void testParseInvalidPoint() throws IOException { .startArray().value(-74.011).value(40.753).endArray() .endArray() .endObject(); - XContentParser parser = createParser(invalidPoint1); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(invalidPoint1)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 2: create an invalid point object with an empty number of coordinates XContentBuilder invalidPoint2 = XContentFactory.jsonBuilder() @@ -310,9 +315,10 @@ public void testParseInvalidPoint() throws IOException { .startArray("coordinates") .endArray() .endObject(); - parser = createParser(invalidPoint2); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(invalidPoint2)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } } public void testParseInvalidMultipoint() throws IOException { @@ -322,9 +328,10 @@ public void testParseInvalidMultipoint() throws IOException { .field("type", "multipoint") .startArray("coordinates").value(-74.011).value(40.753).endArray() .endObject(); - XContentParser parser = createParser(invalidMultipoint1); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(invalidMultipoint1)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 2: create an invalid multipoint object with null coordinate XContentBuilder invalidMultipoint2 = XContentFactory.jsonBuilder() @@ -333,9 +340,10 @@ public void testParseInvalidMultipoint() throws IOException { .startArray("coordinates") .endArray() .endObject(); - parser = createParser(invalidMultipoint2); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(invalidMultipoint2)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 3: create a valid formatted multipoint object with invalid number (0) of coordinates XContentBuilder invalidMultipoint3 = XContentFactory.jsonBuilder() @@ -345,9 +353,10 @@ public void testParseInvalidMultipoint() throws IOException { .startArray().endArray() .endArray() .endObject(); - parser = createParser(invalidMultipoint3); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(invalidMultipoint3)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } } public void testParseInvalidMultiPolygon() throws IOException { @@ -380,9 +389,10 @@ public void testParseInvalidMultiPolygon() throws IOException { .endArray() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, multiPolygonGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, multiPolygonGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class); + } } public void testParseInvalidDimensionalMultiPolygon() throws IOException { @@ -419,9 +429,10 @@ public void testParseInvalidDimensionalMultiPolygon() throws IOException { .endArray() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, multiPolygonGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, multiPolygonGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } } @@ -440,11 +451,12 @@ public void testParseOGCPolygonWithoutHoles() throws IOException { .endArray() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - Shape shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertPolygon(shape); + ElasticsearchGeoAssertions.assertPolygon(shape); + } // test 2: ccw poly crossing dateline polygonGeoJson = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "Polygon") @@ -460,11 +472,12 @@ public void testParseOGCPolygonWithoutHoles() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } // test 3: cw poly not crossing dateline polygonGeoJson = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "Polygon") @@ -480,11 +493,12 @@ public void testParseOGCPolygonWithoutHoles() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertPolygon(shape); + ElasticsearchGeoAssertions.assertPolygon(shape); + } // test 4: cw poly crossing dateline polygonGeoJson = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "Polygon") @@ -500,11 +514,12 @@ public void testParseOGCPolygonWithoutHoles() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } } public void testParseOGCPolygonWithHoles() throws IOException { @@ -528,11 +543,12 @@ public void testParseOGCPolygonWithHoles() throws IOException { .endArray() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - Shape shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertPolygon(shape); + ElasticsearchGeoAssertions.assertPolygon(shape); + } // test 2: ccw poly crossing dateline polygonGeoJson = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "Polygon") @@ -554,11 +570,12 @@ public void testParseOGCPolygonWithHoles() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } // test 3: cw poly not crossing dateline polygonGeoJson = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "Polygon") @@ -580,11 +597,13 @@ public void testParseOGCPolygonWithHoles() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); + + ElasticsearchGeoAssertions.assertPolygon(shape); + } - ElasticsearchGeoAssertions.assertPolygon(shape); // test 4: cw poly crossing dateline polygonGeoJson = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "Polygon") @@ -606,11 +625,12 @@ public void testParseOGCPolygonWithHoles() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } } public void testParseInvalidPolygon() throws IOException { @@ -627,9 +647,10 @@ public void testParseInvalidPolygon() throws IOException { .endArray() .endArray() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 2: create an invalid polygon with only 1 point invalidPoly = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "polygon") @@ -640,9 +661,10 @@ public void testParseInvalidPolygon() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 3: create an invalid polygon with 0 points invalidPoly = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "polygon") @@ -653,9 +675,10 @@ public void testParseInvalidPolygon() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 4: create an invalid polygon with null value points invalidPoly = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "polygon") @@ -666,9 +689,10 @@ public void testParseInvalidPolygon() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, IllegalArgumentException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, IllegalArgumentException.class); + } // test case 5: create an invalid polygon with 1 invalid LinearRing invalidPoly = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "polygon") @@ -677,18 +701,20 @@ public void testParseInvalidPolygon() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, IllegalArgumentException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, IllegalArgumentException.class); + } // test case 6: create an invalid polygon with 0 LinearRings invalidPoly = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "polygon") .startArray("coordinates").endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } // test case 7: create an invalid polygon with 0 LinearRings invalidPoly = Strings.toString(XContentFactory.jsonBuilder().startObject().field("type", "polygon") @@ -697,9 +723,10 @@ public void testParseInvalidPolygon() throws IOException { .endArray() .endObject()); - parser = createParser(JsonXContent.jsonXContent, invalidPoly); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } } public void testParsePolygonWithHole() throws IOException { @@ -764,9 +791,10 @@ public void testParseSelfCrossingPolygon() throws IOException { .endArray() .endObject()); - XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson); - parser.nextToken(); - ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class); + } } @Override @@ -980,11 +1008,12 @@ public void testParseOrientationOption() throws IOException { .endArray() .endObject(); - XContentParser parser = createParser(polygonGeoJson); - parser.nextToken(); - Shape shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertPolygon(shape); + ElasticsearchGeoAssertions.assertPolygon(shape); + } // test 2: valid ccw (right handed system) poly not crossing dateline (with 'ccw' field) polygonGeoJson = XContentFactory.jsonBuilder() @@ -1009,11 +1038,12 @@ public void testParseOrientationOption() throws IOException { .endArray() .endObject(); - parser = createParser(polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertPolygon(shape); + ElasticsearchGeoAssertions.assertPolygon(shape); + } // test 3: valid ccw (right handed system) poly not crossing dateline (with 'counterclockwise' field) polygonGeoJson = XContentFactory.jsonBuilder() @@ -1038,11 +1068,12 @@ public void testParseOrientationOption() throws IOException { .endArray() .endObject(); - parser = createParser(polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertPolygon(shape); + ElasticsearchGeoAssertions.assertPolygon(shape); + } // test 4: valid cw (left handed system) poly crossing dateline (with 'left' field) polygonGeoJson = XContentFactory.jsonBuilder() @@ -1067,11 +1098,12 @@ public void testParseOrientationOption() throws IOException { .endArray() .endObject(); - parser = createParser(polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } // test 5: valid cw multipoly (left handed system) poly crossing dateline (with 'cw' field) polygonGeoJson = XContentFactory.jsonBuilder() @@ -1096,11 +1128,12 @@ public void testParseOrientationOption() throws IOException { .endArray() .endObject(); - parser = createParser(polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } // test 6: valid cw multipoly (left handed system) poly crossing dateline (with 'clockwise' field) polygonGeoJson = XContentFactory.jsonBuilder() @@ -1125,10 +1158,11 @@ public void testParseOrientationOption() throws IOException { .endArray() .endObject(); - parser = createParser(polygonGeoJson); - parser.nextToken(); - shape = ShapeParser.parse(parser).build(); + try (XContentParser parser = createParser(polygonGeoJson)) { + parser.nextToken(); + Shape shape = ShapeParser.parse(parser).build(); - ElasticsearchGeoAssertions.assertMultiPolygon(shape); + ElasticsearchGeoAssertions.assertMultiPolygon(shape); + } } } diff --git a/server/src/test/java/org/elasticsearch/common/geo/GeoUtilTests.java b/server/src/test/java/org/elasticsearch/common/geo/GeoUtilTests.java index efec56e788da1..f23e89ecb2bf7 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/GeoUtilTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/GeoUtilTests.java @@ -59,13 +59,14 @@ private int parsePrecision(CheckedConsumer tokenGe XContentBuilder builder = jsonBuilder().startObject(); tokenGenerator.accept(builder); builder.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken()); // { - assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken()); // field name - assertTrue(parser.nextToken().isValue()); // field value - int precision = GeoUtils.parsePrecision(parser); - assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken()); // } - assertNull(parser.nextToken()); // no more tokens - return precision; + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken()); // { + assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken()); // field name + assertTrue(parser.nextToken().isValue()); // field value + int precision = GeoUtils.parsePrecision(parser); + assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken()); // } + assertNull(parser.nextToken()); // no more tokens + return precision; + } } } diff --git a/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java b/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java index 5ac55832959d7..5f2c721533de9 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java @@ -79,12 +79,13 @@ public void testFromXContent() throws IOException { } XContentBuilder builder = testShape.toXContent(contentBuilder, ToXContent.EMPTY_PARAMS); XContentBuilder shuffled = shuffleXContent(builder); - XContentParser shapeContentParser = createParser(shuffled); - shapeContentParser.nextToken(); - ShapeBuilder parsedShape = ShapeParser.parse(shapeContentParser); - assertNotSame(testShape, parsedShape); - assertEquals(testShape, parsedShape); - assertEquals(testShape.hashCode(), parsedShape.hashCode()); + try (XContentParser shapeContentParser = createParser(shuffled)) { + shapeContentParser.nextToken(); + ShapeBuilder parsedShape = ShapeParser.parse(shapeContentParser); + assertNotSame(testShape, parsedShape); + assertEquals(testShape, parsedShape); + assertEquals(testShape.hashCode(), parsedShape.hashCode()); + } } } diff --git a/server/src/test/java/org/elasticsearch/common/unit/FuzzinessTests.java b/server/src/test/java/org/elasticsearch/common/unit/FuzzinessTests.java index 79b6aa5f60436..0074da43fcfb8 100644 --- a/server/src/test/java/org/elasticsearch/common/unit/FuzzinessTests.java +++ b/server/src/test/java/org/elasticsearch/common/unit/FuzzinessTests.java @@ -45,13 +45,14 @@ public void testParseFromXContent() throws IOException { XContentBuilder json = jsonBuilder().startObject() .field(Fuzziness.X_FIELD_NAME, floatValue) .endObject(); - XContentParser parser = createParser(json); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.VALUE_NUMBER)); - Fuzziness fuzziness = Fuzziness.parse(parser); - assertThat(fuzziness.asFloat(), equalTo(floatValue)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.END_OBJECT)); + try (XContentParser parser = createParser(json)) { + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.VALUE_NUMBER)); + Fuzziness fuzziness = Fuzziness.parse(parser); + assertThat(fuzziness.asFloat(), equalTo(floatValue)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.END_OBJECT)); + } } { Integer intValue = frequently() ? randomIntBetween(0, 2) : randomIntBetween(0, 100); @@ -63,28 +64,29 @@ public void testParseFromXContent() throws IOException { XContentBuilder json = jsonBuilder().startObject() .field(Fuzziness.X_FIELD_NAME, randomBoolean() ? value.toString() : value) .endObject(); - XContentParser parser = createParser(json); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); - assertThat(parser.nextToken(), anyOf(equalTo(XContentParser.Token.VALUE_NUMBER), equalTo(XContentParser.Token.VALUE_STRING))); - Fuzziness fuzziness = Fuzziness.parse(parser); - if (value.intValue() >= 1) { - assertThat(fuzziness.asDistance(), equalTo(Math.min(2, value.intValue()))); - } - assertThat(parser.nextToken(), equalTo(XContentParser.Token.END_OBJECT)); - if (intValue.equals(value)) { - switch (intValue) { - case 1: - assertThat(fuzziness, sameInstance(Fuzziness.ONE)); - break; - case 2: - assertThat(fuzziness, sameInstance(Fuzziness.TWO)); - break; - case 0: - assertThat(fuzziness, sameInstance(Fuzziness.ZERO)); - break; - default: - break; + try (XContentParser parser = createParser(json)) { + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.nextToken(), anyOf(equalTo(XContentParser.Token.VALUE_NUMBER), equalTo(XContentParser.Token.VALUE_STRING))); + Fuzziness fuzziness = Fuzziness.parse(parser); + if (value.intValue() >= 1) { + assertThat(fuzziness.asDistance(), equalTo(Math.min(2, value.intValue()))); + } + assertThat(parser.nextToken(), equalTo(XContentParser.Token.END_OBJECT)); + if (intValue.equals(value)) { + switch (intValue) { + case 1: + assertThat(fuzziness, sameInstance(Fuzziness.ONE)); + break; + case 2: + assertThat(fuzziness, sameInstance(Fuzziness.TWO)); + break; + case 0: + assertThat(fuzziness, sameInstance(Fuzziness.ZERO)); + break; + default: + break; + } } } } @@ -102,15 +104,16 @@ public void testParseFromXContent() throws IOException { .field(Fuzziness.X_FIELD_NAME, auto) .endObject(); } - XContentParser parser = createParser(json); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.VALUE_STRING)); - Fuzziness fuzziness = Fuzziness.parse(parser); - if (isDefaultAutoFuzzinessTested) { - assertThat(fuzziness, sameInstance(Fuzziness.AUTO)); + try (XContentParser parser = createParser(json)) { + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.VALUE_STRING)); + Fuzziness fuzziness = Fuzziness.parse(parser); + if (isDefaultAutoFuzzinessTested) { + assertThat(fuzziness, sameInstance(Fuzziness.AUTO)); + } + assertThat(parser.nextToken(), equalTo(XContentParser.Token.END_OBJECT)); } - assertThat(parser.nextToken(), equalTo(XContentParser.Token.END_OBJECT)); } } @@ -152,15 +155,16 @@ public void testSerializationCustomAuto() throws IOException { .field(Fuzziness.X_FIELD_NAME, auto) .endObject(); - XContentParser parser = createParser(json); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.VALUE_STRING)); - Fuzziness fuzziness = Fuzziness.parse(parser); + try (XContentParser parser = createParser(json)) { + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.VALUE_STRING)); + Fuzziness fuzziness = Fuzziness.parse(parser); - Fuzziness deserializedFuzziness = doSerializeRoundtrip(fuzziness); - assertEquals(fuzziness, deserializedFuzziness); - assertEquals(fuzziness.asString(), deserializedFuzziness.asString()); + Fuzziness deserializedFuzziness = doSerializeRoundtrip(fuzziness); + assertEquals(fuzziness, deserializedFuzziness); + assertEquals(fuzziness.asString(), deserializedFuzziness.asString()); + } } private static Fuzziness doSerializeRoundtrip(Fuzziness in) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java index 86e55c1ab6a91..690e7567e59ff 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java @@ -274,14 +274,15 @@ public void testBinaryField() throws Exception { final byte[] randomBytes = randomBytes(); BytesReference bytes = BytesReference.bytes(builder().startObject().field("binary", randomBytes).endObject()); - XContentParser parser = createParser(xcontentType().xContent(), bytes); - assertSame(parser.nextToken(), Token.START_OBJECT); - assertSame(parser.nextToken(), Token.FIELD_NAME); - assertEquals(parser.currentName(), "binary"); - assertTrue(parser.nextToken().isValue()); - assertArrayEquals(randomBytes, parser.binaryValue()); - assertSame(parser.nextToken(), Token.END_OBJECT); - assertNull(parser.nextToken()); + try (XContentParser parser = createParser(xcontentType().xContent(), bytes)) { + assertSame(parser.nextToken(), Token.START_OBJECT); + assertSame(parser.nextToken(), Token.FIELD_NAME); + assertEquals(parser.currentName(), "binary"); + assertTrue(parser.nextToken().isValue()); + assertArrayEquals(randomBytes, parser.binaryValue()); + assertSame(parser.nextToken(), Token.END_OBJECT); + assertNull(parser.nextToken()); + } } public void testBinaryValue() throws Exception { @@ -290,14 +291,15 @@ public void testBinaryValue() throws Exception { final byte[] randomBytes = randomBytes(); BytesReference bytes = BytesReference.bytes(builder().startObject().field("binary").value(randomBytes).endObject()); - XContentParser parser = createParser(xcontentType().xContent(), bytes); - assertSame(parser.nextToken(), Token.START_OBJECT); - assertSame(parser.nextToken(), Token.FIELD_NAME); - assertEquals(parser.currentName(), "binary"); - assertTrue(parser.nextToken().isValue()); - assertArrayEquals(randomBytes, parser.binaryValue()); - assertSame(parser.nextToken(), Token.END_OBJECT); - assertNull(parser.nextToken()); + try (XContentParser parser = createParser(xcontentType().xContent(), bytes)) { + assertSame(parser.nextToken(), Token.START_OBJECT); + assertSame(parser.nextToken(), Token.FIELD_NAME); + assertEquals(parser.currentName(), "binary"); + assertTrue(parser.nextToken().isValue()); + assertArrayEquals(randomBytes, parser.binaryValue()); + assertSame(parser.nextToken(), Token.END_OBJECT); + assertNull(parser.nextToken()); + } } public void testBinaryValueWithOffsetLength() throws Exception { @@ -315,14 +317,15 @@ public void testBinaryValueWithOffsetLength() throws Exception { } builder.endObject(); - XContentParser parser = createParser(xcontentType().xContent(), BytesReference.bytes(builder)); - assertSame(parser.nextToken(), Token.START_OBJECT); - assertSame(parser.nextToken(), Token.FIELD_NAME); - assertEquals(parser.currentName(), "bin"); - assertTrue(parser.nextToken().isValue()); - assertArrayEquals(Arrays.copyOfRange(randomBytes, offset, offset + length), parser.binaryValue()); - assertSame(parser.nextToken(), Token.END_OBJECT); - assertNull(parser.nextToken()); + try (XContentParser parser = createParser(xcontentType().xContent(), BytesReference.bytes(builder))) { + assertSame(parser.nextToken(), Token.START_OBJECT); + assertSame(parser.nextToken(), Token.FIELD_NAME); + assertEquals(parser.currentName(), "bin"); + assertTrue(parser.nextToken().isValue()); + assertArrayEquals(Arrays.copyOfRange(randomBytes, offset, offset + length), parser.binaryValue()); + assertSame(parser.nextToken(), Token.END_OBJECT); + assertNull(parser.nextToken()); + } } public void testBinaryUTF8() throws Exception { @@ -333,14 +336,15 @@ public void testBinaryUTF8() throws Exception { builder.field("utf8").utf8Value(randomBytesRef.bytes, randomBytesRef.offset, randomBytesRef.length); builder.endObject(); - XContentParser parser = createParser(xcontentType().xContent(), BytesReference.bytes(builder)); - assertSame(parser.nextToken(), Token.START_OBJECT); - assertSame(parser.nextToken(), Token.FIELD_NAME); - assertEquals(parser.currentName(), "utf8"); - assertTrue(parser.nextToken().isValue()); - assertThat(new BytesRef(parser.charBuffer()).utf8ToString(), equalTo(randomBytesRef.utf8ToString())); - assertSame(parser.nextToken(), Token.END_OBJECT); - assertNull(parser.nextToken()); + try (XContentParser parser = createParser(xcontentType().xContent(), BytesReference.bytes(builder))) { + assertSame(parser.nextToken(), Token.START_OBJECT); + assertSame(parser.nextToken(), Token.FIELD_NAME); + assertEquals(parser.currentName(), "utf8"); + assertTrue(parser.nextToken().isValue()); + assertThat(new BytesRef(parser.charBuffer()).utf8ToString(), equalTo(randomBytesRef.utf8ToString())); + assertSame(parser.nextToken(), Token.END_OBJECT); + assertNull(parser.nextToken()); + } } public void testText() throws Exception { @@ -351,14 +355,15 @@ public void testText() throws Exception { final BytesReference random = new BytesArray(randomBytes()); XContentBuilder builder = builder().startObject().field("text", new Text(random)).endObject(); - XContentParser parser = createParser(xcontentType().xContent(), BytesReference.bytes(builder)); - assertSame(parser.nextToken(), Token.START_OBJECT); - assertSame(parser.nextToken(), Token.FIELD_NAME); - assertEquals(parser.currentName(), "text"); - assertTrue(parser.nextToken().isValue()); - assertThat(new BytesRef(parser.charBuffer()).utf8ToString(), equalTo(random.utf8ToString())); - assertSame(parser.nextToken(), Token.END_OBJECT); - assertNull(parser.nextToken()); + try (XContentParser parser = createParser(xcontentType().xContent(), BytesReference.bytes(builder))) { + assertSame(parser.nextToken(), Token.START_OBJECT); + assertSame(parser.nextToken(), Token.FIELD_NAME); + assertEquals(parser.currentName(), "text"); + assertTrue(parser.nextToken().isValue()); + assertThat(new BytesRef(parser.charBuffer()).utf8ToString(), equalTo(random.utf8ToString())); + assertSame(parser.nextToken(), Token.END_OBJECT); + assertNull(parser.nextToken()); + } } public void testReadableInstant() throws Exception { @@ -741,18 +746,19 @@ void doTestRawField(XContent source, boolean useStream) throws Exception { generator.writeEndObject(); } - XContentParser parser = xcontentType().xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, os.toByteArray()); - assertEquals(Token.START_OBJECT, parser.nextToken()); - assertEquals(Token.FIELD_NAME, parser.nextToken()); - assertEquals("bar", parser.currentName()); - assertEquals(Token.START_OBJECT, parser.nextToken()); - assertEquals(Token.FIELD_NAME, parser.nextToken()); - assertEquals("foo", parser.currentName()); - assertEquals(Token.VALUE_NULL, parser.nextToken()); - assertEquals(Token.END_OBJECT, parser.nextToken()); - assertEquals(Token.END_OBJECT, parser.nextToken()); - assertNull(parser.nextToken()); + try (XContentParser parser = xcontentType().xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, os.toByteArray())) { + assertEquals(Token.START_OBJECT, parser.nextToken()); + assertEquals(Token.FIELD_NAME, parser.nextToken()); + assertEquals("bar", parser.currentName()); + assertEquals(Token.START_OBJECT, parser.nextToken()); + assertEquals(Token.FIELD_NAME, parser.nextToken()); + assertEquals("foo", parser.currentName()); + assertEquals(Token.VALUE_NULL, parser.nextToken()); + assertEquals(Token.END_OBJECT, parser.nextToken()); + assertEquals(Token.END_OBJECT, parser.nextToken()); + assertNull(parser.nextToken()); + } } public void testRawValue() throws Exception { @@ -776,14 +782,15 @@ void doTestRawValue(XContent source) throws Exception { generator.writeRawValue(new BytesArray(rawData).streamInput(), source.type()); } - XContentParser parser = xcontentType().xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, os.toByteArray()); - assertEquals(Token.START_OBJECT, parser.nextToken()); - assertEquals(Token.FIELD_NAME, parser.nextToken()); - assertEquals("foo", parser.currentName()); - assertEquals(Token.VALUE_NULL, parser.nextToken()); - assertEquals(Token.END_OBJECT, parser.nextToken()); - assertNull(parser.nextToken()); + try (XContentParser parser = xcontentType().xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, os.toByteArray())) { + assertEquals(Token.START_OBJECT, parser.nextToken()); + assertEquals(Token.FIELD_NAME, parser.nextToken()); + assertEquals("foo", parser.currentName()); + assertEquals(Token.VALUE_NULL, parser.nextToken()); + assertEquals(Token.END_OBJECT, parser.nextToken()); + assertNull(parser.nextToken()); + } os = new ByteArrayOutputStream(); try (XContentGenerator generator = xcontentType().xContent().createGenerator(os)) { @@ -793,18 +800,19 @@ void doTestRawValue(XContent source) throws Exception { generator.writeEndObject(); } - parser = xcontentType().xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, os.toByteArray()); - assertEquals(Token.START_OBJECT, parser.nextToken()); - assertEquals(Token.FIELD_NAME, parser.nextToken()); - assertEquals("test", parser.currentName()); - assertEquals(Token.START_OBJECT, parser.nextToken()); - assertEquals(Token.FIELD_NAME, parser.nextToken()); - assertEquals("foo", parser.currentName()); - assertEquals(Token.VALUE_NULL, parser.nextToken()); - assertEquals(Token.END_OBJECT, parser.nextToken()); - assertEquals(Token.END_OBJECT, parser.nextToken()); - assertNull(parser.nextToken()); + try (XContentParser parser = xcontentType().xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, os.toByteArray())) { + assertEquals(Token.START_OBJECT, parser.nextToken()); + assertEquals(Token.FIELD_NAME, parser.nextToken()); + assertEquals("test", parser.currentName()); + assertEquals(Token.START_OBJECT, parser.nextToken()); + assertEquals(Token.FIELD_NAME, parser.nextToken()); + assertEquals("foo", parser.currentName()); + assertEquals(Token.VALUE_NULL, parser.nextToken()); + assertEquals(Token.END_OBJECT, parser.nextToken()); + assertEquals(Token.END_OBJECT, parser.nextToken()); + assertNull(parser.nextToken()); + } } @@ -822,11 +830,12 @@ protected void doTestBigInteger(JsonGenerator generator, ByteArrayOutputStream o generator.flush(); byte[] serialized = os.toByteArray(); - XContentParser parser = xcontentType().xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, serialized); - Map map = parser.map(); - assertEquals("bar", map.get("foo")); - assertEquals(bigInteger, map.get("bigint")); + try (XContentParser parser = xcontentType().xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, serialized)) { + Map map = parser.map(); + assertEquals("bar", map.get("foo")); + assertEquals(bigInteger, map.get("bigint")); + } } public void testEnsureNameNotNull() { @@ -984,44 +993,46 @@ public void testChecksForDuplicates() throws Exception { .field("key", 1) .field("key", 2) .endObject(); - - JsonParseException pex = expectThrows(JsonParseException.class, () -> createParser(builder).map()); - assertThat(pex.getMessage(), startsWith("Duplicate field 'key'")); + try (XContentParser xParser = createParser(builder)) { + JsonParseException pex = expectThrows(JsonParseException.class, () -> xParser.map()); + assertThat(pex.getMessage(), startsWith("Duplicate field 'key'")); + } } public void testNamedObject() throws IOException { Object test1 = new Object(); Object test2 = new Object(); NamedXContentRegistry registry = new NamedXContentRegistry(Arrays.asList( - new NamedXContentRegistry.Entry(Object.class, new ParseField("test1"), p -> test1), - new NamedXContentRegistry.Entry(Object.class, new ParseField("test2", "deprecated"), p -> test2), - new NamedXContentRegistry.Entry(Object.class, new ParseField("str"), p -> p.text()))); + new NamedXContentRegistry.Entry(Object.class, new ParseField("test1"), p -> test1), + new NamedXContentRegistry.Entry(Object.class, new ParseField("test2", "deprecated"), p -> test2), + new NamedXContentRegistry.Entry(Object.class, new ParseField("str"), p -> p.text()))); XContentBuilder b = XContentBuilder.builder(xcontentType().xContent()); b.value("test"); - XContentParser p = xcontentType().xContent().createParser(registry, LoggingDeprecationHandler.INSTANCE, - BytesReference.bytes(b).streamInput()); - assertEquals(test1, p.namedObject(Object.class, "test1", null)); - assertEquals(test2, p.namedObject(Object.class, "test2", null)); - assertEquals(test2, p.namedObject(Object.class, "deprecated", null)); - assertWarnings("Deprecated field [deprecated] used, expected [test2] instead"); - { + try (XContentParser p = xcontentType().xContent().createParser(registry, LoggingDeprecationHandler.INSTANCE, + BytesReference.bytes(b).streamInput())) { + assertEquals(test1, p.namedObject(Object.class, "test1", null)); + assertEquals(test2, p.namedObject(Object.class, "test2", null)); + assertEquals(test2, p.namedObject(Object.class, "deprecated", null)); + assertWarnings("Deprecated field [deprecated] used, expected [test2] instead"); p.nextToken(); assertEquals("test", p.namedObject(Object.class, "str", null)); - NamedObjectNotFoundException e = expectThrows(NamedObjectNotFoundException.class, + { + NamedObjectNotFoundException e = expectThrows(NamedObjectNotFoundException.class, () -> p.namedObject(Object.class, "unknown", null)); - assertThat(e.getMessage(), endsWith("unable to parse Object with name [unknown]: parser not found")); - } - { - Exception e = expectThrows(NamedObjectNotFoundException.class, () -> p.namedObject(String.class, "doesn't matter", null)); - assertEquals("unknown named object category [java.lang.String]", e.getMessage()); + assertThat(e.getMessage(), endsWith("unable to parse Object with name [unknown]: parser not found")); + } + { + Exception e = expectThrows(NamedObjectNotFoundException.class, () -> p.namedObject(String.class, "doesn't matter", null)); + assertEquals("unknown named object category [java.lang.String]", e.getMessage()); + } } - { - XContentParser emptyRegistryParser = xcontentType().xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, new byte[] {}); + try (XContentParser emptyRegistryParser = xcontentType().xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, new byte[] {})) { Exception e = expectThrows(NamedObjectNotFoundException.class, - () -> emptyRegistryParser.namedObject(String.class, "doesn't matter", null)); + () -> emptyRegistryParser.namedObject(String.class, "doesn't matter", null)); assertEquals("named objects are not supported for this parser", e.getMessage()); } + } private static void expectUnclosedException(ThrowingRunnable runnable) { diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/builder/XContentBuilderTests.java b/server/src/test/java/org/elasticsearch/common/xcontent/builder/XContentBuilderTests.java index cb666418b6cac..07338d9286b70 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/builder/XContentBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/builder/XContentBuilderTests.java @@ -216,43 +216,44 @@ public void testCopyCurrentStructure() throws Exception { } builder.field("fakefield", terms).endObject().endObject().endObject(); - - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - XContentBuilder filterBuilder = null; XContentParser.Token token; - String currentFieldName = null; - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - currentFieldName = parser.currentName(); - } else if (token.isValue()) { - if ("test".equals(currentFieldName)) { - assertThat(parser.text(), equalTo("test field")); - } - } else if (token == XContentParser.Token.START_OBJECT) { - if ("filter".equals(currentFieldName)) { - filterBuilder = XContentFactory.contentBuilder(parser.contentType()); - filterBuilder.copyCurrentStructure(parser); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + + String currentFieldName = null; + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else if (token.isValue()) { + if ("test".equals(currentFieldName)) { + assertThat(parser.text(), equalTo("test field")); + } + } else if (token == XContentParser.Token.START_OBJECT) { + if ("filter".equals(currentFieldName)) { + filterBuilder = XContentFactory.contentBuilder(parser.contentType()); + filterBuilder.copyCurrentStructure(parser); + } } } } - assertNotNull(filterBuilder); - parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(filterBuilder)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); - assertThat(parser.currentName(), equalTo("terms")); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); - assertThat(parser.currentName(), equalTo("fakefield")); - assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_ARRAY)); - int i = 0; - while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - assertThat(parser.text(), equalTo(terms.get(i++))); - } + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(filterBuilder))) { + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("terms")); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("fakefield")); + assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_ARRAY)); + int i = 0; + while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { + assertThat(parser.text(), equalTo(terms.get(i++))); + } - assertThat(i, equalTo(terms.size())); + assertThat(i, equalTo(terms.size())); + } } public void testHandlingOfPath() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/cbor/CborXContentParserTests.java b/server/src/test/java/org/elasticsearch/common/xcontent/cbor/CborXContentParserTests.java index 146b83c8c17a9..0e682e8be66c1 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/cbor/CborXContentParserTests.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/cbor/CborXContentParserTests.java @@ -33,9 +33,10 @@ public void testEmptyValue() throws IOException { for (int i = 0; i < 2; i++) { // Running this part twice triggers the issue. // See https://github.com/elastic/elasticsearch/issues/8629 - XContentParser parser = createParser(CborXContent.cborXContent, ref); - while (parser.nextToken() != null) { - parser.charBuffer(); + try (XContentParser parser = createParser(CborXContent.cborXContent, ref)) { + while (parser.nextToken() != null) { + parser.charBuffer(); + } } } } diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/cbor/JsonVsCborTests.java b/server/src/test/java/org/elasticsearch/common/xcontent/cbor/JsonVsCborTests.java index e165425400eb5..b10cce71f718a 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/cbor/JsonVsCborTests.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/cbor/JsonVsCborTests.java @@ -62,8 +62,10 @@ public void testCompareParsingTokens() throws IOException { xsonGen.close(); jsonGen.close(); - - verifySameTokens(createParser(JsonXContent.jsonXContent, jsonOs.bytes()), createParser(CborXContent.cborXContent, xsonOs.bytes())); + try (XContentParser json0sParser = createParser(JsonXContent.jsonXContent, jsonOs.bytes()); + XContentParser xson0sParser = createParser(CborXContent.cborXContent, xsonOs.bytes())) { + verifySameTokens(json0sParser, xson0sParser); + } } private void verifySameTokens(XContentParser parser1, XContentParser parser2) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/smile/JsonVsSmileTests.java b/server/src/test/java/org/elasticsearch/common/xcontent/smile/JsonVsSmileTests.java index 47913a5481e33..7f909df694f8e 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/smile/JsonVsSmileTests.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/smile/JsonVsSmileTests.java @@ -63,8 +63,10 @@ public void testCompareParsingTokens() throws IOException { xsonGen.close(); jsonGen.close(); - verifySameTokens(createParser(JsonXContent.jsonXContent, jsonOs.bytes()), - createParser(SmileXContent.smileXContent, xsonOs.bytes())); + try (XContentParser jsonParser = createParser(JsonXContent.jsonXContent, jsonOs.bytes()); + XContentParser smileParser = createParser(SmileXContent.smileXContent, xsonOs.bytes())) { + verifySameTokens(jsonParser, smileParser); + } } private void verifySameTokens(XContentParser parser1, XContentParser parser2) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/support/filtering/AbstractXContentFilteringTestCase.java b/server/src/test/java/org/elasticsearch/common/xcontent/support/filtering/AbstractXContentFilteringTestCase.java index 1d12defe6988d..4aa19b78a5ca0 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/support/filtering/AbstractXContentFilteringTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/support/filtering/AbstractXContentFilteringTestCase.java @@ -75,15 +75,15 @@ static void assertXContentBuilderAsString(final XContentBuilder expected, final } static void assertXContentBuilderAsBytes(final XContentBuilder expected, final XContentBuilder actual) { - try { - XContent xContent = XContentFactory.xContent(actual.contentType()); + XContent xContent = XContentFactory.xContent(actual.contentType()); + try ( XContentParser jsonParser = xContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, BytesReference.bytes(expected).streamInput()); XContentParser testParser = xContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, BytesReference.bytes(actual).streamInput()); - + ) { while (true) { XContentParser.Token token1 = jsonParser.nextToken(); XContentParser.Token token2 = testParser.nextToken(); diff --git a/server/src/test/java/org/elasticsearch/index/IndexTests.java b/server/src/test/java/org/elasticsearch/index/IndexTests.java index f1360071745d0..9b0ca1978075a 100644 --- a/server/src/test/java/org/elasticsearch/index/IndexTests.java +++ b/server/src/test/java/org/elasticsearch/index/IndexTests.java @@ -56,9 +56,10 @@ public void testXContent() throws IOException { final Index original = new Index(name, uuid); final XContentBuilder builder = JsonXContent.contentBuilder(); original.toXContent(builder, ToXContent.EMPTY_PARAMS); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - parser.nextToken(); // the beginning of the parser - assertThat(Index.fromXContent(parser), equalTo(original)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + parser.nextToken(); // the beginning of the parser + assertThat(Index.fromXContent(parser), equalTo(original)); + } } public void testEquals() { diff --git a/server/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java index a417cba13b9a4..362adf4a4c996 100644 --- a/server/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java @@ -28,6 +28,7 @@ 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.search.internal.SearchContext; import org.elasticsearch.test.AbstractQueryTestCase; @@ -169,8 +170,10 @@ public void testIllegalArguments() { public void testEmptyBooleanQuery() throws Exception { XContentBuilder contentBuilder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); contentBuilder.startObject().startObject("bool").endObject().endObject(); - Query parsedQuery = parseQuery(createParser(contentBuilder)).toQuery(createShardContext()); - assertThat(parsedQuery, Matchers.instanceOf(MatchAllDocsQuery.class)); + try (XContentParser xParser = createParser(contentBuilder)) { + Query parsedQuery = parseQuery(xParser).toQuery(createShardContext()); + assertThat(parsedQuery, Matchers.instanceOf(MatchAllDocsQuery.class)); + } } public void testDefaultMinShouldMatch() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java index a2068a666f44c..95a91e1668c3e 100644 --- a/server/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java @@ -124,11 +124,12 @@ public void testFromAndToXContent() throws Exception { innerHit.toXContent(builder, ToXContent.EMPTY_PARAMS); //fields is printed out as an object but parsed into a List where order matters, we disable shuffling XContentBuilder shuffled = shuffleXContent(builder, "fields"); - XContentParser parser = createParser(shuffled); - InnerHitBuilder secondInnerHits = InnerHitBuilder.fromXContent(parser); - assertThat(innerHit, not(sameInstance(secondInnerHits))); - assertThat(innerHit, equalTo(secondInnerHits)); - assertThat(innerHit.hashCode(), equalTo(secondInnerHits.hashCode())); + try (XContentParser parser = createParser(shuffled)) { + InnerHitBuilder secondInnerHits = InnerHitBuilder.fromXContent(parser); + assertThat(innerHit, not(sameInstance(secondInnerHits))); + assertThat(innerHit, equalTo(secondInnerHits)); + assertThat(innerHit.hashCode(), equalTo(secondInnerHits.hashCode())); + } } } diff --git a/server/src/test/java/org/elasticsearch/index/search/geo/GeoPointParsingTests.java b/server/src/test/java/org/elasticsearch/index/search/geo/GeoPointParsingTests.java index 4b580aa6a2467..b116c61d27c28 100644 --- a/server/src/test/java/org/elasticsearch/index/search/geo/GeoPointParsingTests.java +++ b/server/src/test/java/org/elasticsearch/index/search/geo/GeoPointParsingTests.java @@ -107,16 +107,17 @@ public void testInvalidPointEmbeddedObject() throws IOException { content.endObject(); content.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); - - XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser2.nextToken(); - e = expectThrows(ElasticsearchParseException.class, () -> - GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); - assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + } + try (XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser2.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> + GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); + assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + } } public void testInvalidPointLatHashMix() throws IOException { @@ -125,16 +126,17 @@ public void testInvalidPointLatHashMix() throws IOException { content.field("lat", 0).field("geohash", stringEncode(0d, 0d)); content.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); - - XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser2.nextToken(); - e = expectThrows(ElasticsearchParseException.class, () -> - GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); - assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + } + try (XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser2.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> + GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); + assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + } } public void testInvalidPointLonHashMix() throws IOException { @@ -143,17 +145,18 @@ public void testInvalidPointLonHashMix() throws IOException { content.field("lon", 0).field("geohash", stringEncode(0d, 0d)); content.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser.nextToken(); - - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser.nextToken(); - XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser2.nextToken(); - e = expectThrows(ElasticsearchParseException.class, () -> - GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); - assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + } + try (XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser2.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> + GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); + assertThat(e.getMessage(), is("field must be either lat/lon or geohash")); + } } public void testInvalidField() throws IOException { @@ -162,17 +165,18 @@ public void testInvalidField() throws IOException { content.field("lon", 0).field("lat", 0).field("test", 0); content.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); - + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + } - XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser2.nextToken(); - e = expectThrows(ElasticsearchParseException.class, () -> - GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); - assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + try (XContentParser parser2 = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser2.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> + GeoUtils.parseGeoPoint(toObject(parser2), randomBoolean())); + assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + } } public void testInvalidGeoHash() throws IOException { @@ -181,11 +185,12 @@ public void testInvalidGeoHash() throws IOException { content.field("geohash", "!!!!"); content.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content)); - parser.nextToken(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(content))) { + parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("unsupported symbol [!] in geohash [!!!!]")); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("unsupported symbol [!] in geohash [!!!!]")); + } } private XContentParser objectLatLon(double lat, double lon) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/index/search/geo/GeoUtilsTests.java b/server/src/test/java/org/elasticsearch/index/search/geo/GeoUtilsTests.java index d390490dd225c..9fec336e2a33f 100644 --- a/server/src/test/java/org/elasticsearch/index/search/geo/GeoUtilsTests.java +++ b/server/src/test/java/org/elasticsearch/index/search/geo/GeoUtilsTests.java @@ -384,29 +384,33 @@ public void testParseGeoPoint() throws IOException { double lat = randomDouble() * 180 - 90 + randomIntBetween(-1000, 1000) * 180; double lon = randomDouble() * 360 - 180 + randomIntBetween(-1000, 1000) * 360; XContentBuilder json = jsonBuilder().startObject().field("lat", lat).field("lon", lon).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - GeoPoint point = GeoUtils.parseGeoPoint(parser); - assertThat(point, equalTo(new GeoPoint(lat, lon))); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + GeoPoint point = GeoUtils.parseGeoPoint(parser); + assertThat(point, equalTo(new GeoPoint(lat, lon))); + } json = jsonBuilder().startObject().field("lat", String.valueOf(lat)).field("lon", String.valueOf(lon)).endObject(); - parser = createParser(json); - parser.nextToken(); - point = GeoUtils.parseGeoPoint(parser); - assertThat(point, equalTo(new GeoPoint(lat, lon))); - json = jsonBuilder().startObject().startArray("foo").value(lon).value(lat).endArray().endObject(); - parser = createParser(json); - while (parser.currentToken() != Token.START_ARRAY) { + try (XContentParser parser = createParser(json)) { parser.nextToken(); + GeoPoint point = GeoUtils.parseGeoPoint(parser); + assertThat(point, equalTo(new GeoPoint(lat, lon))); + } + json = jsonBuilder().startObject().startArray("foo").value(lon).value(lat).endArray().endObject(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.START_ARRAY) { + parser.nextToken(); + } + GeoPoint point = GeoUtils.parseGeoPoint(parser); + assertThat(point, equalTo(new GeoPoint(lat, lon))); } - point = GeoUtils.parseGeoPoint(parser); - assertThat(point, equalTo(new GeoPoint(lat, lon))); json = jsonBuilder().startObject().field("foo", lat + "," + lon).endObject(); - parser = createParser(json); - while (parser.currentToken() != Token.VALUE_STRING) { - parser.nextToken(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.VALUE_STRING) { + parser.nextToken(); + } + GeoPoint point = GeoUtils.parseGeoPoint(parser); + assertThat(point, equalTo(new GeoPoint(lat, lon))); } - point = GeoUtils.parseGeoPoint(parser); - assertThat(point, equalTo(new GeoPoint(lat, lon))); } } @@ -415,12 +419,13 @@ public void testParseGeoPointStringZValueError() throws IOException { double lon = randomDouble() * 360 - 180 + randomIntBetween(-1000, 1000) * 360; double alt = randomDouble() * 1000; XContentBuilder json = jsonBuilder().startObject().field("foo", lat + "," + lon + "," + alt).endObject(); - XContentParser parser = createParser(json); - while (parser.currentToken() != Token.VALUE_STRING) { - parser.nextToken(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.VALUE_STRING) { + parser.nextToken(); + } + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser, new GeoPoint(), false)); + assertThat(e.getMessage(), containsString("but [ignore_z_value] parameter is [false]")); } - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser, new GeoPoint(), false)); - assertThat(e.getMessage(), containsString("but [ignore_z_value] parameter is [false]")); } public void testParseGeoPointGeohash() throws IOException { @@ -431,74 +436,82 @@ public void testParseGeoPointGeohash() throws IOException { geohashBuilder.append(BASE_32[randomInt(BASE_32.length - 1)]); } XContentBuilder json = jsonBuilder().startObject().field("geohash", geohashBuilder.toString()).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - GeoPoint point = GeoUtils.parseGeoPoint(parser); - assertThat(point.lat(), allOf(lessThanOrEqualTo(90.0), greaterThanOrEqualTo(-90.0))); - assertThat(point.lon(), allOf(lessThanOrEqualTo(180.0), greaterThanOrEqualTo(-180.0))); - json = jsonBuilder().startObject().field("geohash", geohashBuilder.toString()).endObject(); - parser = createParser(json); - while (parser.currentToken() != Token.VALUE_STRING) { + try (XContentParser parser = createParser(json)) { parser.nextToken(); + GeoPoint point = GeoUtils.parseGeoPoint(parser); + assertThat(point.lat(), allOf(lessThanOrEqualTo(90.0), greaterThanOrEqualTo(-90.0))); + assertThat(point.lon(), allOf(lessThanOrEqualTo(180.0), greaterThanOrEqualTo(-180.0))); + } + json = jsonBuilder().startObject().field("geohash", geohashBuilder.toString()).endObject(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.VALUE_STRING) { + parser.nextToken(); + } + GeoPoint point = GeoUtils.parseGeoPoint(parser); + assertThat(point.lat(), allOf(lessThanOrEqualTo(90.0), greaterThanOrEqualTo(-90.0))); + assertThat(point.lon(), allOf(lessThanOrEqualTo(180.0), greaterThanOrEqualTo(-180.0))); } - point = GeoUtils.parseGeoPoint(parser); - assertThat(point.lat(), allOf(lessThanOrEqualTo(90.0), greaterThanOrEqualTo(-90.0))); - assertThat(point.lon(), allOf(lessThanOrEqualTo(180.0), greaterThanOrEqualTo(-180.0))); } } public void testParseGeoPointGeohashWrongType() throws IOException { XContentBuilder json = jsonBuilder().startObject().field("geohash", 1.0).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), containsString("geohash must be a string")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), containsString("geohash must be a string")); + } } public void testParseGeoPointLatNoLon() throws IOException { double lat = 0.0; XContentBuilder json = jsonBuilder().startObject().field("lat", lat).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field [lon] missing")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field [lon] missing")); + } } public void testParseGeoPointLonNoLat() throws IOException { double lon = 0.0; XContentBuilder json = jsonBuilder().startObject().field("lon", lon).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field [lat] missing")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field [lat] missing")); + } } public void testParseGeoPointLonWrongType() throws IOException { double lat = 0.0; XContentBuilder json = jsonBuilder().startObject().field("lat", lat).field("lon", false).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("longitude must be a number")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("longitude must be a number")); + } } public void testParseGeoPointLatWrongType() throws IOException { double lon = 0.0; XContentBuilder json = jsonBuilder().startObject().field("lat", false).field("lon", lon).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("latitude must be a number")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("latitude must be a number")); + } } public void testParseGeoPointExtraField() throws IOException { double lat = 0.0; double lon = 0.0; XContentBuilder json = jsonBuilder().startObject().field("lat", lat).field("lon", lon).field("foo", true).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("field must be either [lat], [lon] or [geohash]")); + } } public void testParseGeoPointLonLatGeoHash() throws IOException { @@ -506,10 +519,11 @@ public void testParseGeoPointLonLatGeoHash() throws IOException { double lon = 0.0; String geohash = "abcd"; XContentBuilder json = jsonBuilder().startObject().field("lat", lat).field("lon", lon).field("geohash", geohash).endObject(); - XContentParser parser = createParser(json); - parser.nextToken(); - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), containsString("field must be either lat/lon or geohash")); + try (XContentParser parser = createParser(json)) { + parser.nextToken(); + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), containsString("field must be either lat/lon or geohash")); + } } public void testParseGeoPointArrayTooManyValues() throws IOException { @@ -517,12 +531,13 @@ public void testParseGeoPointArrayTooManyValues() throws IOException { double lon = 0.0; double elev = 0.0; XContentBuilder json = jsonBuilder().startObject().startArray("foo").value(lon).value(lat).value(elev).endArray().endObject(); - XContentParser parser = createParser(json); - while (parser.currentToken() != Token.START_ARRAY) { - parser.nextToken(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.START_ARRAY) { + parser.nextToken(); + } + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("Exception parsing coordinates: found Z value [0.0] but [ignore_z_value] parameter is [false]")); } - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("Exception parsing coordinates: found Z value [0.0] but [ignore_z_value] parameter is [false]")); } public void testParseGeoPointArray3D() throws IOException { @@ -530,35 +545,38 @@ public void testParseGeoPointArray3D() throws IOException { double lon = -180.0; double elev = 0.0; XContentBuilder json = jsonBuilder().startObject().startArray("foo").value(lon).value(lat).value(elev).endArray().endObject(); - XContentParser parser = createParser(json); - while (parser.currentToken() != Token.START_ARRAY) { - parser.nextToken(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.START_ARRAY) { + parser.nextToken(); + } + GeoPoint point = GeoUtils.parseGeoPoint(parser, new GeoPoint(), true); + assertThat(point.lat(), equalTo(lat)); + assertThat(point.lon(), equalTo(lon)); } - GeoPoint point = GeoUtils.parseGeoPoint(parser, new GeoPoint(), true); - assertThat(point.lat(), equalTo(lat)); - assertThat(point.lon(), equalTo(lon)); } public void testParseGeoPointArrayWrongType() throws IOException { double lat = 0.0; boolean lon = false; XContentBuilder json = jsonBuilder().startObject().startArray("foo").value(lon).value(lat).endArray().endObject(); - XContentParser parser = createParser(json); - while (parser.currentToken() != Token.START_ARRAY) { - parser.nextToken(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.START_ARRAY) { + parser.nextToken(); + } + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("numeric value expected")); } - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("numeric value expected")); } public void testParseGeoPointInvalidType() throws IOException { XContentBuilder json = jsonBuilder().startObject().field("foo", 5).endObject(); - XContentParser parser = createParser(json); - while (parser.currentToken() != Token.VALUE_NUMBER) { - parser.nextToken(); + try (XContentParser parser = createParser(json)) { + while (parser.currentToken() != Token.VALUE_NUMBER) { + parser.nextToken(); + } + Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); + assertThat(e.getMessage(), is("geo_point expected")); } - Exception e = expectThrows(ElasticsearchParseException.class, () -> GeoUtils.parseGeoPoint(parser)); - assertThat(e.getMessage(), is("geo_point expected")); } public void testPrefixTreeCellSizes() { @@ -619,9 +637,10 @@ public void testParseGeoPointGeohashPositions() throws IOException { } private GeoPoint parseGeohash(String geohash, GeoUtils.EffectivePoint effectivePoint) throws IOException { - XContentParser parser = createParser(jsonBuilder().startObject().field("geohash", geohash).endObject()); - parser.nextToken(); - return GeoUtils.parseGeoPoint(parser, new GeoPoint(), randomBoolean(), effectivePoint); + try (XContentParser parser = createParser(jsonBuilder().startObject().field("geohash", geohash).endObject())) { + parser.nextToken(); + return GeoUtils.parseGeoPoint(parser, new GeoPoint(), randomBoolean(), effectivePoint); + } } private static void assertNormalizedPoint(GeoPoint input, GeoPoint expected) { diff --git a/server/src/test/java/org/elasticsearch/ingest/IngestMetadataTests.java b/server/src/test/java/org/elasticsearch/ingest/IngestMetadataTests.java index 518b775d7f802..6684544a74749 100644 --- a/server/src/test/java/org/elasticsearch/ingest/IngestMetadataTests.java +++ b/server/src/test/java/org/elasticsearch/ingest/IngestMetadataTests.java @@ -57,15 +57,16 @@ public void testFromXContent() throws IOException { ingestMetadata.toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); XContentBuilder shuffled = shuffleXContent(builder); - final XContentParser parser = createParser(shuffled); - MetaData.Custom custom = IngestMetadata.fromXContent(parser); - assertTrue(custom instanceof IngestMetadata); - IngestMetadata m = (IngestMetadata) custom; - assertEquals(2, m.getPipelines().size()); - assertEquals("1", m.getPipelines().get("1").getId()); - assertEquals("2", m.getPipelines().get("2").getId()); - assertEquals(pipeline.getConfigAsMap(), m.getPipelines().get("1").getConfigAsMap()); - assertEquals(pipeline2.getConfigAsMap(), m.getPipelines().get("2").getConfigAsMap()); + try (XContentParser parser = createParser(shuffled)) { + MetaData.Custom custom = IngestMetadata.fromXContent(parser); + assertTrue(custom instanceof IngestMetadata); + IngestMetadata m = (IngestMetadata) custom; + assertEquals(2, m.getPipelines().size()); + assertEquals("1", m.getPipelines().get("1").getId()); + assertEquals("2", m.getPipelines().get("2").getId()); + assertEquals(pipeline.getConfigAsMap(), m.getPipelines().get("1").getConfigAsMap()); + assertEquals(pipeline2.getConfigAsMap(), m.getPipelines().get("2").getConfigAsMap()); + } } public void testDiff() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java b/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java index 5b1f74d6cdfa5..2a180cc12dd19 100644 --- a/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java +++ b/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java @@ -174,8 +174,10 @@ public void testSerializationContext() throws Exception { XContentType xContentType = randomFrom(XContentType.values()); BytesReference shuffled = toShuffledXContent(testInstance, xContentType, params, false); - XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled); - PersistentTasksCustomMetaData newInstance = doParseInstance(parser); + PersistentTasksCustomMetaData newInstance; + try (XContentParser parser = createParser(XContentFactory.xContent(xContentType), shuffled)) { + newInstance = doParseInstance(parser); + } assertNotSame(newInstance, testInstance); assertEquals(testInstance.tasks().size(), newInstance.tasks().size()); diff --git a/server/src/test/java/org/elasticsearch/repositories/RepositoryDataTests.java b/server/src/test/java/org/elasticsearch/repositories/RepositoryDataTests.java index d0cf5d374897d..1d37490e2ff5f 100644 --- a/server/src/test/java/org/elasticsearch/repositories/RepositoryDataTests.java +++ b/server/src/test/java/org/elasticsearch/repositories/RepositoryDataTests.java @@ -62,11 +62,12 @@ public void testXContent() throws IOException { RepositoryData repositoryData = generateRandomRepoData(); XContentBuilder builder = JsonXContent.contentBuilder(); repositoryData.snapshotsToXContent(builder, ToXContent.EMPTY_PARAMS); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - long gen = (long) randomIntBetween(0, 500); - RepositoryData fromXContent = RepositoryData.snapshotsFromXContent(parser, gen); - assertEquals(repositoryData, fromXContent); - assertEquals(gen, fromXContent.getGenId()); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + long gen = (long) randomIntBetween(0, 500); + RepositoryData fromXContent = RepositoryData.snapshotsFromXContent(parser, gen); + assertEquals(repositoryData, fromXContent); + assertEquals(gen, fromXContent.getGenId()); + } } public void testAddSnapshots() { @@ -166,7 +167,10 @@ public void testIndexThatReferencesAnUnknownSnapshot() throws IOException { XContentBuilder builder = XContentBuilder.builder(xContent); repositoryData.snapshotsToXContent(builder, ToXContent.EMPTY_PARAMS); - RepositoryData parsedRepositoryData = RepositoryData.snapshotsFromXContent(createParser(builder), repositoryData.getGenId()); + RepositoryData parsedRepositoryData; + try (XContentParser xParser = createParser(builder)) { + parsedRepositoryData = RepositoryData.snapshotsFromXContent(xParser, repositoryData.getGenId()); + } assertEquals(repositoryData, parsedRepositoryData); Map snapshotIds = new HashMap<>(); @@ -195,10 +199,12 @@ public void testIndexThatReferencesAnUnknownSnapshot() throws IOException { final XContentBuilder corruptedBuilder = XContentBuilder.builder(xContent); corruptedRepositoryData.snapshotsToXContent(corruptedBuilder, ToXContent.EMPTY_PARAMS); - ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> - RepositoryData.snapshotsFromXContent(createParser(corruptedBuilder), corruptedRepositoryData.getGenId())); - assertThat(e.getMessage(), equalTo("Detected a corrupted repository, index " + corruptedIndexId + " references an unknown " + - "snapshot uuid [_does_not_exist]")); + try (XContentParser xParser = createParser(corruptedBuilder)) { + ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> + RepositoryData.snapshotsFromXContent(xParser, corruptedRepositoryData.getGenId())); + assertThat(e.getMessage(), equalTo("Detected a corrupted repository, index " + corruptedIndexId + " references an unknown " + + "snapshot uuid [_does_not_exist]")); + } } public void testIndexThatReferenceANullSnapshot() throws IOException { @@ -230,9 +236,12 @@ public void testIndexThatReferenceANullSnapshot() throws IOException { } builder.endObject(); - ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> - RepositoryData.snapshotsFromXContent(createParser(builder), randomNonNegativeLong())); - assertThat(e.getMessage(), equalTo("Detected a corrupted repository, index [docs/_id] references an unknown snapshot uuid [null]")); + try (XContentParser xParser = createParser(builder)) { + ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> + RepositoryData.snapshotsFromXContent(xParser, randomNonNegativeLong())); + assertThat(e.getMessage(), equalTo("Detected a corrupted repository, " + + "index [docs/_id] references an unknown snapshot uuid [null]")); + } } public static RepositoryData generateRandomRepoData() { diff --git a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java index 66f0bd796eaef..406e9b1d36c07 100644 --- a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java +++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestAnalyzeActionTests.java @@ -37,28 +37,29 @@ public class RestAnalyzeActionTests extends ESTestCase { public void testParseXContentForAnalyzeRequest() throws Exception { - XContentParser content = createParser(XContentFactory.jsonBuilder() + try (XContentParser content = createParser(XContentFactory.jsonBuilder() .startObject() .field("text", "THIS IS A TEST") .field("tokenizer", "keyword") .array("filter", "lowercase") - .endObject()); + .endObject())) { - AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); + AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); - RestAnalyzeAction.buildFromContent(content, analyzeRequest); + RestAnalyzeAction.buildFromContent(content, analyzeRequest); - assertThat(analyzeRequest.text().length, equalTo(1)); - assertThat(analyzeRequest.text(), equalTo(new String[]{"THIS IS A TEST"})); - assertThat(analyzeRequest.tokenizer().name, equalTo("keyword")); - assertThat(analyzeRequest.tokenFilters().size(), equalTo(1)); - for (AnalyzeRequest.NameOrDefinition filter : analyzeRequest.tokenFilters()) { - assertThat(filter.name, equalTo("lowercase")); + assertThat(analyzeRequest.text().length, equalTo(1)); + assertThat(analyzeRequest.text(), equalTo(new String[]{"THIS IS A TEST"})); + assertThat(analyzeRequest.tokenizer().name, equalTo("keyword")); + assertThat(analyzeRequest.tokenFilters().size(), equalTo(1)); + for (AnalyzeRequest.NameOrDefinition filter : analyzeRequest.tokenFilters()) { + assertThat(filter.name, equalTo("lowercase")); + } } } public void testParseXContentForAnalyzeRequestWithCustomFilters() throws Exception { - XContentParser content = createParser(XContentFactory.jsonBuilder() + try (XContentParser content = createParser(XContentFactory.jsonBuilder() .startObject() .field("text", "THIS IS A TEST") .field("tokenizer", "keyword") @@ -76,21 +77,22 @@ public void testParseXContentForAnalyzeRequestWithCustomFilters() throws Excepti .endObject() .endArray() .field("normalizer", "normalizer") - .endObject()); + .endObject())) { - AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); + AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); - RestAnalyzeAction.buildFromContent(content, analyzeRequest); - - assertThat(analyzeRequest.text().length, equalTo(1)); - assertThat(analyzeRequest.text(), equalTo(new String[]{"THIS IS A TEST"})); - assertThat(analyzeRequest.tokenizer().name, equalTo("keyword")); - assertThat(analyzeRequest.tokenFilters().size(), equalTo(2)); - assertThat(analyzeRequest.tokenFilters().get(0).name, equalTo("lowercase")); - assertThat(analyzeRequest.tokenFilters().get(1).definition, notNullValue()); - assertThat(analyzeRequest.charFilters().size(), equalTo(1)); - assertThat(analyzeRequest.charFilters().get(0).definition, notNullValue()); - assertThat(analyzeRequest.normalizer(), equalTo("normalizer")); + RestAnalyzeAction.buildFromContent(content, analyzeRequest); + + assertThat(analyzeRequest.text().length, equalTo(1)); + assertThat(analyzeRequest.text(), equalTo(new String[]{"THIS IS A TEST"})); + assertThat(analyzeRequest.tokenizer().name, equalTo("keyword")); + assertThat(analyzeRequest.tokenFilters().size(), equalTo(2)); + assertThat(analyzeRequest.tokenFilters().get(0).name, equalTo("lowercase")); + assertThat(analyzeRequest.tokenFilters().get(1).definition, notNullValue()); + assertThat(analyzeRequest.charFilters().size(), equalTo(1)); + assertThat(analyzeRequest.charFilters().get(0).definition, notNullValue()); + assertThat(analyzeRequest.normalizer(), equalTo("normalizer")); + } } public void testParseXContentForAnalyzeRequestWithInvalidJsonThrowsException() throws Exception { @@ -103,84 +105,83 @@ public void testParseXContentForAnalyzeRequestWithInvalidJsonThrowsException() t public void testParseXContentForAnalyzeRequestWithUnknownParamThrowsException() throws Exception { AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); - XContentParser invalidContent = createParser(XContentFactory.jsonBuilder() + try (XContentParser invalidContent = createParser(XContentFactory.jsonBuilder() .startObject() .field("text", "THIS IS A TEST") .field("unknown", "keyword") - .endObject()); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + .endObject())) { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> RestAnalyzeAction.buildFromContent(invalidContent, analyzeRequest)); - assertThat(e.getMessage(), startsWith("Unknown parameter [unknown]")); + assertThat(e.getMessage(), startsWith("Unknown parameter [unknown]")); + } } public void testParseXContentForAnalyzeRequestWithInvalidStringExplainParamThrowsException() throws Exception { AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); - XContentParser invalidExplain = createParser(XContentFactory.jsonBuilder() + try (XContentParser invalidExplain = createParser(XContentFactory.jsonBuilder() .startObject() .field("explain", "fals") - .endObject()); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, - () -> RestAnalyzeAction.buildFromContent(invalidExplain, analyzeRequest)); - assertThat(e.getMessage(), startsWith("explain must be either 'true' or 'false'")); + .endObject())) { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> RestAnalyzeAction.buildFromContent(invalidExplain, analyzeRequest)); + assertThat(e.getMessage(), startsWith("explain must be either 'true' or 'false'")); + } } public void testParseXContentForAnalyzeRequestWithInvalidNormalizerThrowsException() throws Exception { AnalyzeRequest analyzeRequest = new AnalyzeRequest("for test"); - XContentParser invalidExplain = createParser(XContentFactory.jsonBuilder() + try (XContentParser invalidExplain = createParser(XContentFactory.jsonBuilder() .startObject() .field("normalizer", true) - .endObject()); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, - () -> RestAnalyzeAction.buildFromContent(invalidExplain, analyzeRequest)); - assertThat(e.getMessage(), startsWith("normalizer should be normalizer's name")); + .endObject())) { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> RestAnalyzeAction.buildFromContent(invalidExplain, analyzeRequest)); + assertThat(e.getMessage(), startsWith("normalizer should be normalizer's name")); + } } public void testDeprecatedParamIn2xException() throws Exception { - { - XContentParser parser = createParser(XContentFactory.jsonBuilder() - .startObject() - .field("text", "THIS IS A TEST") - .field("tokenizer", "keyword") - .array("filters", "lowercase") - .endObject()); + try (XContentParser parser = createParser(XContentFactory.jsonBuilder() + .startObject() + .field("text", "THIS IS A TEST") + .field("tokenizer", "keyword") + .array("filters", "lowercase") + .endObject())) { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> RestAnalyzeAction.buildFromContent(parser, - new AnalyzeRequest("for test"))); + new AnalyzeRequest("for test"))); assertThat(e.getMessage(), startsWith("Unknown parameter [filters]")); } - { - XContentParser parser = createParser(XContentFactory.jsonBuilder() - .startObject() - .field("text", "THIS IS A TEST") - .field("tokenizer", "keyword") - .array("token_filters", "lowercase") - .endObject()); + try (XContentParser parser = createParser(XContentFactory.jsonBuilder() + .startObject() + .field("text", "THIS IS A TEST") + .field("tokenizer", "keyword") + .array("token_filters", "lowercase") + .endObject())) { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> RestAnalyzeAction.buildFromContent(parser, - new AnalyzeRequest("for test"))); + new AnalyzeRequest("for test"))); assertThat(e.getMessage(), startsWith("Unknown parameter [token_filters]")); } - { - XContentParser parser = createParser(XContentFactory.jsonBuilder() - .startObject() - .field("text", "THIS IS A TEST") - .field("tokenizer", "keyword") - .array("char_filters", "lowercase") - .endObject()); + try (XContentParser parser = createParser(XContentFactory.jsonBuilder() + .startObject() + .field("text", "THIS IS A TEST") + .field("tokenizer", "keyword") + .array("char_filters", "lowercase") + .endObject())) { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> RestAnalyzeAction.buildFromContent(parser, - new AnalyzeRequest("for test"))); + new AnalyzeRequest("for test"))); assertThat(e.getMessage(), startsWith("Unknown parameter [char_filters]")); } - { - XContentParser parser = createParser(XContentFactory.jsonBuilder() - .startObject() - .field("text", "THIS IS A TEST") - .field("tokenizer", "keyword") - .array("token_filter", "lowercase") - .endObject()); + try (XContentParser parser = createParser(XContentFactory.jsonBuilder() + .startObject() + .field("text", "THIS IS A TEST") + .field("tokenizer", "keyword") + .array("token_filter", "lowercase") + .endObject())) { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> RestAnalyzeAction.buildFromContent(parser, - new AnalyzeRequest("for test"))); + new AnalyzeRequest("for test"))); assertThat(e.getMessage(), startsWith("Unknown parameter [token_filter]")); } } diff --git a/server/src/test/java/org/elasticsearch/script/ScriptTests.java b/server/src/test/java/org/elasticsearch/script/ScriptTests.java index 6e578ed910d40..8b66bb32c486e 100644 --- a/server/src/test/java/org/elasticsearch/script/ScriptTests.java +++ b/server/src/test/java/org/elasticsearch/script/ScriptTests.java @@ -89,9 +89,11 @@ public void testParse() throws IOException { Script expectedScript = createScript(); try (XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values()))) { expectedScript.toXContent(builder, ToXContent.EMPTY_PARAMS); - Settings settings = Settings.fromXContent(createParser(builder)); - Script actualScript = Script.parse(settings); - assertThat(actualScript, equalTo(expectedScript)); + try (XContentParser xParser = createParser(builder)) { + Settings settings = Settings.fromXContent(xParser); + Script actualScript = Script.parse(settings); + assertThat(actualScript, equalTo(expectedScript)); + } } } } diff --git a/server/src/test/java/org/elasticsearch/search/NestedIdentityTests.java b/server/src/test/java/org/elasticsearch/search/NestedIdentityTests.java index b0eb9e907618f..b1c46f3bcedf4 100644 --- a/server/src/test/java/org/elasticsearch/search/NestedIdentityTests.java +++ b/server/src/test/java/org/elasticsearch/search/NestedIdentityTests.java @@ -58,10 +58,11 @@ public void testFromXContent() throws IOException { builder.prettyPrint(); } builder = nestedIdentity.innerToXContent(builder, ToXContent.EMPTY_PARAMS); - XContentParser parser = createParser(builder); - NestedIdentity parsedNestedIdentity = NestedIdentity.fromXContent(parser); - assertEquals(nestedIdentity, parsedNestedIdentity); - assertNull(parser.nextToken()); + try (XContentParser parser = createParser(builder)) { + NestedIdentity parsedNestedIdentity = NestedIdentity.fromXContent(parser); + assertEquals(nestedIdentity, parsedNestedIdentity); + assertNull(parser.nextToken()); + } } public void testToXContent() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/AggregationCollectorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/AggregationCollectorTests.java index 9b5d64b46bc33..9919e9dcdbbd1 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/AggregationCollectorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/AggregationCollectorTests.java @@ -56,13 +56,14 @@ public void testNeedsScores() throws Exception { } private boolean needsScores(IndexService index, String agg) throws IOException { - XContentParser aggParser = createParser(JsonXContent.jsonXContent, agg); - aggParser.nextToken(); - SearchContext context = createSearchContext(index); - final AggregatorFactories factories = AggregatorFactories.parseAggregators(aggParser).build(context, null); - final Aggregator[] aggregators = factories.createTopLevelAggregators(); - assertEquals(1, aggregators.length); - return aggregators[0].needsScores(); + try (XContentParser aggParser = createParser(JsonXContent.jsonXContent, agg)) { + aggParser.nextToken(); + SearchContext context = createSearchContext(index); + final AggregatorFactories factories = AggregatorFactories.parseAggregators(aggParser).build(context, null); + final Aggregator[] aggregators = factories.createTopLevelAggregators(); + assertEquals(1, aggregators.length); + return aggregators[0].needsScores(); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java b/server/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java index 828b419909238..c7bbcfc147780 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java @@ -106,13 +106,14 @@ public void testFromXContent() throws IOException { } factoriesBuilder.toXContent(builder, ToXContent.EMPTY_PARAMS); XContentBuilder shuffled = shuffleXContent(builder); - XContentParser parser = createParser(shuffled); - String contentString = factoriesBuilder.toString(); - logger.info("Content string: {}", contentString); - PipelineAggregationBuilder newAgg = parse(parser); - assertNotSame(newAgg, testAgg); - assertEquals(testAgg, newAgg); - assertEquals(testAgg.hashCode(), newAgg.hashCode()); + try (XContentParser parser = createParser(shuffled)) { + String contentString = factoriesBuilder.toString(); + logger.info("Content string: {}", contentString); + PipelineAggregationBuilder newAgg = parse(parser); + assertNotSame(newAgg, testAgg); + assertEquals(testAgg, newAgg); + assertEquals(testAgg.hashCode(), newAgg.hashCode()); + } } protected PipelineAggregationBuilder parse(XContentParser parser) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersTests.java index 4577986da270c..327a717f05c52 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersTests.java @@ -94,34 +94,37 @@ public void testOtherBucket() throws IOException { builder.startObject(); builder.startArray("filters").endArray(); builder.endObject(); - XContentParser parser = createParser(shuffleXContent(builder)); - parser.nextToken(); - FiltersAggregationBuilder filters = FiltersAggregationBuilder.parse("agg_name", parser); - // The other bucket is disabled by default - assertFalse(filters.otherBucket()); - - builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); - builder.startObject(); - builder.startArray("filters").endArray(); - builder.field("other_bucket_key", "some_key"); - builder.endObject(); - parser = createParser(shuffleXContent(builder)); - parser.nextToken(); - filters = FiltersAggregationBuilder.parse("agg_name", parser); - // but setting a key enables it automatically - assertTrue(filters.otherBucket()); - - builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); - builder.startObject(); - builder.startArray("filters").endArray(); - builder.field("other_bucket", false); - builder.field("other_bucket_key", "some_key"); - builder.endObject(); - parser = createParser(shuffleXContent(builder)); - parser.nextToken(); - filters = FiltersAggregationBuilder.parse("agg_name", parser); - // unless the other bucket is explicitly disabled - assertFalse(filters.otherBucket()); + try (XContentParser parser = createParser(shuffleXContent(builder))) { + parser.nextToken(); + FiltersAggregationBuilder filters = FiltersAggregationBuilder.parse("agg_name", parser); + // The other bucket is disabled by default + assertFalse(filters.otherBucket()); + + builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); + builder.startObject(); + builder.startArray("filters").endArray(); + builder.field("other_bucket_key", "some_key"); + builder.endObject(); + } + try (XContentParser parser = createParser(shuffleXContent(builder))) { + parser.nextToken(); + FiltersAggregationBuilder filters = FiltersAggregationBuilder.parse("agg_name", parser); + // but setting a key enables it automatically + assertTrue(filters.otherBucket()); + + builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); + builder.startObject(); + builder.startArray("filters").endArray(); + builder.field("other_bucket", false); + builder.field("other_bucket_key", "some_key"); + builder.endObject(); + } + try (XContentParser parser = createParser(shuffleXContent(builder))) { + parser.nextToken(); + FiltersAggregationBuilder filters = FiltersAggregationBuilder.parse("agg_name", parser); + // unless the other bucket is explicitly disabled + assertFalse(filters.otherBucket()); + } } public void testRewrite() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/significant/SignificanceHeuristicTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/significant/SignificanceHeuristicTests.java index 414954a2d905b..5009594160ef7 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/significant/SignificanceHeuristicTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/significant/SignificanceHeuristicTests.java @@ -264,9 +264,8 @@ public void testBuilderAndParser() throws Exception { protected void checkParseException(ParseFieldRegistry significanceHeuristicParserRegistry, String faultyHeuristicDefinition, String expectedError) throws IOException { - try { - XContentParser stParser = createParser(JsonXContent.jsonXContent, - "{\"field\":\"text\", " + faultyHeuristicDefinition + ",\"min_doc_count\":200}"); + try (XContentParser stParser = createParser(JsonXContent.jsonXContent, + "{\"field\":\"text\", " + faultyHeuristicDefinition + ",\"min_doc_count\":200}")) { stParser.nextToken(); SignificantTermsAggregationBuilder.getParser(significanceHeuristicParserRegistry).parse("testagg", stParser); fail(); @@ -301,9 +300,10 @@ private static SignificanceHeuristic parseSignificanceHeuristic( protected SignificanceHeuristic parseFromString(ParseFieldRegistry significanceHeuristicParserRegistry, String heuristicString) throws IOException { - XContentParser stParser = createParser(JsonXContent.jsonXContent, - "{\"field\":\"text\", " + heuristicString + ", \"min_doc_count\":200}"); - return parseSignificanceHeuristic(significanceHeuristicParserRegistry, stParser); + try (XContentParser stParser = createParser(JsonXContent.jsonXContent, + "{\"field\":\"text\", " + heuristicString + ", \"min_doc_count\":200}")) { + return parseSignificanceHeuristic(significanceHeuristicParserRegistry, stParser); + } } void testBackgroundAssertions(SignificanceHeuristic heuristicIsSuperset, SignificanceHeuristic heuristicNotSuperset) { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/support/IncludeExcludeTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/support/IncludeExcludeTests.java index 6e477021a541f..dc2624dc39e40 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/support/IncludeExcludeTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/support/IncludeExcludeTests.java @@ -214,21 +214,22 @@ private IncludeExclude serialize(IncludeExclude incExc, ParseField field) throws incExc.toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); - XContentParser parser = createParser(builder); - XContentParser.Token token = parser.nextToken(); - assertEquals(token, XContentParser.Token.START_OBJECT); - token = parser.nextToken(); - assertEquals(token, XContentParser.Token.FIELD_NAME); - assertEquals(field.getPreferredName(), parser.currentName()); - token = parser.nextToken(); - - if (field.getPreferredName().equalsIgnoreCase("include")) { - return IncludeExclude.parseInclude(parser); - } else if (field.getPreferredName().equalsIgnoreCase("exclude")) { - return IncludeExclude.parseExclude(parser); - } else { - throw new IllegalArgumentException( + try (XContentParser parser = createParser(builder)) { + XContentParser.Token token = parser.nextToken(); + assertEquals(token, XContentParser.Token.START_OBJECT); + token = parser.nextToken(); + assertEquals(token, XContentParser.Token.FIELD_NAME); + assertEquals(field.getPreferredName(), parser.currentName()); + token = parser.nextToken(); + + if (field.getPreferredName().equalsIgnoreCase("include")) { + return IncludeExclude.parseInclude(parser); + } else if (field.getPreferredName().equalsIgnoreCase("exclude")) { + return IncludeExclude.parseExclude(parser); + } else { + throw new IllegalArgumentException( "Unexpected field name serialized in test: " + field.getPreferredName()); + } } } @@ -260,28 +261,29 @@ private IncludeExclude serializeMixedRegex(IncludeExclude incExc) throws IOExcep incExc.toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); - XContentParser parser = createParser(builder); - XContentParser.Token token = parser.nextToken(); - assertEquals(token, XContentParser.Token.START_OBJECT); - - IncludeExclude inc = null; - IncludeExclude exc = null; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - assertEquals(XContentParser.Token.FIELD_NAME, token); - if (IncludeExclude.INCLUDE_FIELD.match(parser.currentName(), parser.getDeprecationHandler())) { - token = parser.nextToken(); - inc = IncludeExclude.parseInclude(parser); - } else if (IncludeExclude.EXCLUDE_FIELD.match(parser.currentName(), parser.getDeprecationHandler())) { - token = parser.nextToken(); - exc = IncludeExclude.parseExclude(parser); - } else { - throw new IllegalArgumentException("Unexpected field name serialized in test: " + parser.currentName()); + try (XContentParser parser = createParser(builder)) { + XContentParser.Token token = parser.nextToken(); + assertEquals(token, XContentParser.Token.START_OBJECT); + + IncludeExclude inc = null; + IncludeExclude exc = null; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + assertEquals(XContentParser.Token.FIELD_NAME, token); + if (IncludeExclude.INCLUDE_FIELD.match(parser.currentName(), parser.getDeprecationHandler())) { + token = parser.nextToken(); + inc = IncludeExclude.parseInclude(parser); + } else if (IncludeExclude.EXCLUDE_FIELD.match(parser.currentName(), parser.getDeprecationHandler())) { + token = parser.nextToken(); + exc = IncludeExclude.parseExclude(parser); + } else { + throw new IllegalArgumentException("Unexpected field name serialized in test: " + parser.currentName()); + } } + assertNotNull(inc); + assertNotNull(exc); + // Include and Exclude clauses are parsed independently and then merged + return IncludeExclude.merge(inc, exc); } - assertNotNull(inc); - assertNotNull(exc); - // Include and Exclude clauses are parsed independently and then merged - return IncludeExclude.merge(inc, exc); } } diff --git a/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java b/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java index 2550c0a4a444c..12c3e487ff124 100644 --- a/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java @@ -64,7 +64,9 @@ public void testFromXContent() throws IOException { builder.prettyPrint(); } testSearchSourceBuilder.toXContent(builder, ToXContent.EMPTY_PARAMS); - assertParseSearchSource(testSearchSourceBuilder, createParser(builder)); + try (XContentParser xParser = createParser(builder)) { + assertParseSearchSource(testSearchSourceBuilder, xParser); + } } public void testFromXContentInvalid() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java index 95da15e838c31..37359d9f20d71 100644 --- a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java @@ -139,17 +139,18 @@ public void testFromXContent() throws IOException { shuffled = shuffleXContent(builder, "fields"); } - XContentParser parser = createParser(shuffled); - parser.nextToken(); - HighlightBuilder secondHighlightBuilder; - try { - secondHighlightBuilder = HighlightBuilder.fromXContent(parser); - } catch (RuntimeException e) { - throw new RuntimeException("Error parsing " + highlightBuilder, e); + try (XContentParser parser = createParser(shuffled)) { + parser.nextToken(); + HighlightBuilder secondHighlightBuilder; + try { + secondHighlightBuilder = HighlightBuilder.fromXContent(parser); + } catch (RuntimeException e) { + throw new RuntimeException("Error parsing " + highlightBuilder, e); + } + assertNotSame(highlightBuilder, secondHighlightBuilder); + assertEquals(highlightBuilder, secondHighlightBuilder); + assertEquals(highlightBuilder.hashCode(), secondHighlightBuilder.hashCode()); } - assertNotSame(highlightBuilder, secondHighlightBuilder); - assertEquals(highlightBuilder, secondHighlightBuilder); - assertEquals(highlightBuilder.hashCode(), secondHighlightBuilder.hashCode()); } } @@ -179,8 +180,9 @@ public void testUnknownArrayNameExpection() throws IOException { } private T expectParseThrows(Class exceptionClass, String highlightElement) throws IOException { - XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement); - return expectThrows(exceptionClass, () -> HighlightBuilder.fromXContent(parser)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement)) { + return expectThrows(exceptionClass, () -> HighlightBuilder.fromXContent(parser)); + } } /** @@ -389,30 +391,32 @@ public void testParsingTagsSchema() throws IOException { String highlightElement = "{\n" + " \"tags_schema\" : \"styled\"\n" + "}\n"; - XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement)) { - HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); - assertArrayEquals("setting tags_schema 'styled' should alter pre_tags", HighlightBuilder.DEFAULT_STYLED_PRE_TAG, + HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); + assertArrayEquals("setting tags_schema 'styled' should alter pre_tags", HighlightBuilder.DEFAULT_STYLED_PRE_TAG, highlightBuilder.preTags()); - assertArrayEquals("setting tags_schema 'styled' should alter post_tags", HighlightBuilder.DEFAULT_STYLED_POST_TAGS, + assertArrayEquals("setting tags_schema 'styled' should alter post_tags", HighlightBuilder.DEFAULT_STYLED_POST_TAGS, highlightBuilder.postTags()); - highlightElement = "{\n" + + highlightElement = "{\n" + " \"tags_schema\" : \"default\"\n" + "}\n"; - parser = createParser(JsonXContent.jsonXContent, highlightElement); + } + try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement)) { - highlightBuilder = HighlightBuilder.fromXContent(parser); - assertArrayEquals("setting tags_schema 'default' should alter pre_tags", HighlightBuilder.DEFAULT_PRE_TAGS, + HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); + assertArrayEquals("setting tags_schema 'default' should alter pre_tags", HighlightBuilder.DEFAULT_PRE_TAGS, highlightBuilder.preTags()); - assertArrayEquals("setting tags_schema 'default' should alter post_tags", HighlightBuilder.DEFAULT_POST_TAGS, + assertArrayEquals("setting tags_schema 'default' should alter post_tags", HighlightBuilder.DEFAULT_POST_TAGS, highlightBuilder.postTags()); - XContentParseException e = expectParseThrows(XContentParseException.class, "{\n" + + XContentParseException e = expectParseThrows(XContentParseException.class, "{\n" + " \"tags_schema\" : \"somthing_else\"\n" + "}\n"); - assertThat(e.getMessage(), containsString("[highlight] failed to parse field [tags_schema]")); - assertEquals("Unknown tag schema [somthing_else]", e.getCause().getMessage()); + assertThat(e.getMessage(), containsString("[highlight] failed to parse field [tags_schema]")); + assertEquals("Unknown tag schema [somthing_else]", e.getCause().getMessage()); + } } /** @@ -420,22 +424,22 @@ public void testParsingTagsSchema() throws IOException { */ public void testParsingEmptyStructure() throws IOException { String highlightElement = "{ }"; - XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement); - - HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); - assertEquals("expected plain HighlightBuilder", new HighlightBuilder(), highlightBuilder); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement)) { + HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); + assertEquals("expected plain HighlightBuilder", new HighlightBuilder(), highlightBuilder); + } highlightElement = "{ \"fields\" : { } }"; - parser = createParser(JsonXContent.jsonXContent, highlightElement); - - highlightBuilder = HighlightBuilder.fromXContent(parser); - assertEquals("defining no field should return plain HighlightBuilder", new HighlightBuilder(), highlightBuilder); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement)) { + HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); + assertEquals("defining no field should return plain HighlightBuilder", new HighlightBuilder(), highlightBuilder); + } highlightElement = "{ \"fields\" : { \"foo\" : { } } }"; - parser = createParser(JsonXContent.jsonXContent, highlightElement); - - highlightBuilder = HighlightBuilder.fromXContent(parser); - assertEquals("expected HighlightBuilder with field", new HighlightBuilder().field(new Field("foo")), highlightBuilder); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightElement)) { + HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(parser); + assertEquals("expected HighlightBuilder with field", new HighlightBuilder().field(new Field("foo")), highlightBuilder); + } } public void testPreTagsWithoutPostTags() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightFieldTests.java b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightFieldTests.java index 7b27cf78ec65a..7044a7b103098 100644 --- a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightFieldTests.java +++ b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightFieldTests.java @@ -62,16 +62,17 @@ public void testFromXContent() throws IOException { builder.startObject(); // we need to wrap xContent output in proper object to create a parser for it builder = highlightField.toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); - XContentParser parser = createParser(builder); - parser.nextToken(); // skip to the opening object token, fromXContent advances from here and starts with the field name - parser.nextToken(); - HighlightField parsedField = HighlightField.fromXContent(parser); - assertEquals(highlightField, parsedField); - if (highlightField.fragments() != null) { - assertEquals(XContentParser.Token.END_ARRAY, parser.currentToken()); + try (XContentParser parser = createParser(builder)) { + parser.nextToken(); // skip to the opening object token, fromXContent advances from here and starts with the field name + parser.nextToken(); + HighlightField parsedField = HighlightField.fromXContent(parser); + assertEquals(highlightField, parsedField); + if (highlightField.fragments() != null) { + assertEquals(XContentParser.Token.END_ARRAY, parser.currentToken()); + } + assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken()); + assertNull(parser.nextToken()); } - assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken()); - assertNull(parser.nextToken()); } public void testToXContent() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java b/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java index efd3e5ef2ca06..700b3949facf4 100644 --- a/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java @@ -121,12 +121,13 @@ public void testFromXContent() throws IOException { XContentBuilder shuffled = shuffleXContent(builder); - XContentParser parser = createParser(shuffled); - parser.nextToken(); - RescorerBuilder secondRescoreBuilder = RescorerBuilder.parseFromXContent(parser); - assertNotSame(rescoreBuilder, secondRescoreBuilder); - assertEquals(rescoreBuilder, secondRescoreBuilder); - assertEquals(rescoreBuilder.hashCode(), secondRescoreBuilder.hashCode()); + try (XContentParser parser = createParser(shuffled)) { + parser.nextToken(); + RescorerBuilder secondRescoreBuilder = RescorerBuilder.parseFromXContent(parser); + assertNotSame(rescoreBuilder, secondRescoreBuilder); + assertEquals(rescoreBuilder, secondRescoreBuilder); + assertEquals(rescoreBuilder.hashCode(), secondRescoreBuilder.hashCode()); + } } } @@ -214,67 +215,61 @@ public MappedFieldType fieldMapper(String name) { public void testUnknownFieldsExpection() throws IOException { String rescoreElement = "{\n" + - " \"window_size\" : 20,\n" + - " \"bad_rescorer_name\" : { }\n" + - "}\n"; - { - XContentParser parser = createParser(rescoreElement); + " \"window_size\" : 20,\n" + + " \"bad_rescorer_name\" : { }\n" + + "}\n"; + try (XContentParser parser = createParser(rescoreElement)) { Exception e = expectThrows(NamedObjectNotFoundException.class, () -> RescorerBuilder.parseFromXContent(parser)); assertEquals("[3:27] unable to parse RescorerBuilder with name [bad_rescorer_name]: parser not found", e.getMessage()); } - rescoreElement = "{\n" + - " \"bad_fieldName\" : 20\n" + - "}\n"; - { - XContentParser parser = createParser(rescoreElement); + " \"bad_fieldName\" : 20\n" + + "}\n"; + try (XContentParser parser = createParser(rescoreElement)) { Exception e = expectThrows(ParsingException.class, () -> RescorerBuilder.parseFromXContent(parser)); assertEquals("rescore doesn't support [bad_fieldName]", e.getMessage()); } rescoreElement = "{\n" + - " \"window_size\" : 20,\n" + - " \"query\" : [ ]\n" + - "}\n"; - { - XContentParser parser = createParser(rescoreElement); + " \"window_size\" : 20,\n" + + " \"query\" : [ ]\n" + + "}\n"; + try (XContentParser parser = createParser(rescoreElement)) { Exception e = expectThrows(ParsingException.class, () -> RescorerBuilder.parseFromXContent(parser)); assertEquals("unexpected token [START_ARRAY] after [query]", e.getMessage()); } rescoreElement = "{ }"; - { - XContentParser parser = createParser(rescoreElement); + try (XContentParser parser = createParser(rescoreElement)) { Exception e = expectThrows(ParsingException.class, () -> RescorerBuilder.parseFromXContent(parser)); assertEquals("missing rescore type", e.getMessage()); } rescoreElement = "{\n" + - " \"window_size\" : 20,\n" + - " \"query\" : { \"bad_fieldname\" : 1.0 } \n" + - "}\n"; - { - XContentParser parser = createParser(rescoreElement); + " \"window_size\" : 20,\n" + + " \"query\" : { \"bad_fieldname\" : 1.0 } \n" + + "}\n"; + try (XContentParser parser = createParser(rescoreElement)) { XContentParseException e = expectThrows(XContentParseException.class, () -> RescorerBuilder.parseFromXContent(parser)); assertEquals("[3:17] [query] unknown field [bad_fieldname], parser not found", e.getMessage()); } rescoreElement = "{\n" + - " \"window_size\" : 20,\n" + - " \"query\" : { \"rescore_query\" : { \"unknown_queryname\" : { } } } \n" + - "}\n"; - { - XContentParser parser = createParser(rescoreElement); + " \"window_size\" : 20,\n" + + " \"query\" : { \"rescore_query\" : { \"unknown_queryname\" : { } } } \n" + + "}\n"; + try (XContentParser parser = createParser(rescoreElement)) { Exception e = expectThrows(XContentParseException.class, () -> RescorerBuilder.parseFromXContent(parser)); assertThat(e.getMessage(), containsString("[query] failed to parse field [rescore_query]")); } rescoreElement = "{\n" + - " \"window_size\" : 20,\n" + - " \"query\" : { \"rescore_query\" : { \"match_all\" : { } } } \n" - + "}\n"; - XContentParser parser = createParser(rescoreElement); - RescorerBuilder.parseFromXContent(parser); + " \"window_size\" : 20,\n" + + " \"query\" : { \"rescore_query\" : { \"match_all\" : { } } } \n" + + "}\n"; + try (XContentParser parser = createParser(rescoreElement)) { + RescorerBuilder.parseFromXContent(parser); + } } /** diff --git a/server/src/test/java/org/elasticsearch/search/searchafter/SearchAfterBuilderTests.java b/server/src/test/java/org/elasticsearch/search/searchafter/SearchAfterBuilderTests.java index 53bd9da2ff1de..f7457d965744a 100644 --- a/server/src/test/java/org/elasticsearch/search/searchafter/SearchAfterBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/searchafter/SearchAfterBuilderTests.java @@ -136,11 +136,12 @@ private SearchAfterBuilder randomJsonSearchFromBuilder() throws IOException { } jsonBuilder.endArray(); jsonBuilder.endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(jsonBuilder)); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - return SearchAfterBuilder.fromXContent(parser); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(jsonBuilder))) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + return SearchAfterBuilder.fromXContent(parser); + } } private static SearchAfterBuilder serializedCopy(SearchAfterBuilder original) throws IOException { @@ -174,14 +175,15 @@ public void testFromXContent() throws Exception { builder.startObject(); searchAfterBuilder.innerToXContent(builder); builder.endObject(); - XContentParser parser = createParser(shuffleXContent(builder)); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - SearchAfterBuilder secondSearchAfterBuilder = SearchAfterBuilder.fromXContent(parser); - assertNotSame(searchAfterBuilder, secondSearchAfterBuilder); - assertEquals(searchAfterBuilder, secondSearchAfterBuilder); - assertEquals(searchAfterBuilder.hashCode(), secondSearchAfterBuilder.hashCode()); + try (XContentParser parser = createParser(shuffleXContent(builder))) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + SearchAfterBuilder secondSearchAfterBuilder = SearchAfterBuilder.fromXContent(parser); + assertNotSame(searchAfterBuilder, secondSearchAfterBuilder); + assertEquals(searchAfterBuilder, secondSearchAfterBuilder); + assertEquals(searchAfterBuilder.hashCode(), secondSearchAfterBuilder.hashCode()); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/slice/SliceBuilderTests.java b/server/src/test/java/org/elasticsearch/search/slice/SliceBuilderTests.java index b93ebc1adde72..30ed0cb5ab5b5 100644 --- a/server/src/test/java/org/elasticsearch/search/slice/SliceBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/slice/SliceBuilderTests.java @@ -306,11 +306,12 @@ public void testFromXContent() throws Exception { builder.startObject(); sliceBuilder.innerToXContent(builder); builder.endObject(); - XContentParser parser = createParser(shuffleXContent(builder)); - SliceBuilder secondSliceBuilder = SliceBuilder.fromXContent(parser); - assertNotSame(sliceBuilder, secondSliceBuilder); - assertEquals(sliceBuilder, secondSliceBuilder); - assertEquals(sliceBuilder.hashCode(), secondSliceBuilder.hashCode()); + try (XContentParser parser = createParser(shuffleXContent(builder))) { + SliceBuilder secondSliceBuilder = SliceBuilder.fromXContent(parser); + assertNotSame(sliceBuilder, secondSliceBuilder); + assertEquals(sliceBuilder, secondSliceBuilder); + assertEquals(sliceBuilder.hashCode(), secondSliceBuilder.hashCode()); + } } public void testInvalidArguments() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java index d05ddf4ee640e..2285af3ec46c0 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java @@ -121,21 +121,22 @@ public void testFromXContent() throws IOException { } testItem.toXContent(builder, ToXContent.EMPTY_PARAMS); XContentBuilder shuffled = shuffleXContent(builder); - XContentParser itemParser = createParser(shuffled); - itemParser.nextToken(); - - /* - * filter out name of sort, or field name to sort on for element fieldSort - */ - itemParser.nextToken(); - String elementName = itemParser.currentName(); - itemParser.nextToken(); - - T parsedItem = fromXContent(itemParser, elementName); - assertNotSame(testItem, parsedItem); - assertEquals(testItem, parsedItem); - assertEquals(testItem.hashCode(), parsedItem.hashCode()); - assertWarnings(testItem); + try (XContentParser itemParser = createParser(shuffled)) { + itemParser.nextToken(); + + /* + * filter out name of sort, or field name to sort on for element fieldSort + */ + itemParser.nextToken(); + String elementName = itemParser.currentName(); + itemParser.nextToken(); + + T parsedItem = fromXContent(itemParser, elementName); + assertNotSame(testItem, parsedItem); + assertEquals(testItem, parsedItem); + assertEquals(testItem.hashCode(), parsedItem.hashCode()); + assertWarnings(testItem); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java index 6aceed996ccdc..268f4aeb26d65 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java @@ -304,14 +304,15 @@ public void testBuildNested() throws IOException { public void testUnknownOptionFails() throws IOException { String json = "{ \"post_date\" : {\"reverse\" : true} },\n"; - XContentParser parser = createParser(JsonXContent.jsonXContent, json); - // need to skip until parser is located on second START_OBJECT - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - - XContentParseException e = expectThrows(XContentParseException.class, () -> FieldSortBuilder.fromXContent(parser, "")); - assertEquals("[1:18] [field_sort] unknown field [reverse], parser not found", e.getMessage()); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, json)) { + // need to skip until parser is located on second START_OBJECT + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + + XContentParseException e = expectThrows(XContentParseException.class, () -> FieldSortBuilder.fromXContent(parser, "")); + assertEquals("[1:18] [field_sort] unknown field [reverse], parser not found", e.getMessage()); + } } @Override diff --git a/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java index b70a87ea9860f..7ffedbf43ec2c 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java @@ -232,12 +232,13 @@ public void testSortModeSumIsRejectedInJSON() throws IOException { " \"distance_type\" : \"arc\",\n" + " \"mode\" : \"SUM\"\n" + "}"; - XContentParser itemParser = createParser(JsonXContent.jsonXContent, json); - itemParser.nextToken(); + try (XContentParser itemParser = createParser(JsonXContent.jsonXContent, json)) { + itemParser.nextToken(); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> GeoDistanceSortBuilder.fromXContent(itemParser, "")); - assertEquals("sort_mode [sum] isn't supported for sorting by geo distance", e.getMessage()); + assertEquals("sort_mode [sum] isn't supported for sorting by geo distance", e.getMessage()); + } } public void testGeoDistanceSortCanBeParsedFromGeoHash() throws IOException { @@ -258,16 +259,17 @@ public void testGeoDistanceSortCanBeParsedFromGeoHash() throws IOException { " },\n" + " \"validation_method\" : \"STRICT\"\n" + " }"; - XContentParser itemParser = createParser(JsonXContent.jsonXContent, json); - itemParser.nextToken(); + try (XContentParser itemParser = createParser(JsonXContent.jsonXContent, json)) { + itemParser.nextToken(); - GeoDistanceSortBuilder result = GeoDistanceSortBuilder.fromXContent(itemParser, json); - assertEquals("[-19.700583312660456, -2.8225036337971687, " + GeoDistanceSortBuilder result = GeoDistanceSortBuilder.fromXContent(itemParser, json); + assertEquals("[-19.700583312660456, -2.8225036337971687, " + "31.537466906011105, -74.63590376079082, " + "43.71844606474042, -5.548660643398762, " + "-37.20467280596495, 38.71751043945551, " + "-69.44606635719538, 84.25200328230858, " + "-39.03717711567879, 44.74099852144718]", Arrays.toString(result.points())); + } } public void testGeoDistanceSortParserManyPointsNoException() throws Exception { @@ -380,9 +382,10 @@ public void testGeoDistanceSortDeprecatedSortModeException() throws Exception { } private GeoDistanceSortBuilder parse(XContentBuilder sortBuilder) throws Exception { - XContentParser parser = createParser(sortBuilder); - parser.nextToken(); - return GeoDistanceSortBuilder.fromXContent(parser, null); + try (XContentParser parser = createParser(sortBuilder)) { + parser.nextToken(); + return GeoDistanceSortBuilder.fromXContent(parser, null); + } } @Override diff --git a/server/src/test/java/org/elasticsearch/search/sort/NestedSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/NestedSortBuilderTests.java index 0908d83896f92..b0613b320b86a 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/NestedSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/NestedSortBuilderTests.java @@ -73,12 +73,13 @@ public void testFromXContent() throws IOException { XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); testItem.toXContent(builder, ToXContent.EMPTY_PARAMS); XContentBuilder shuffled = shuffleXContent(builder); - XContentParser parser = createParser(shuffled); - parser.nextToken(); - NestedSortBuilder parsedItem = NestedSortBuilder.fromXContent(parser); - assertNotSame(testItem, parsedItem); - assertEquals(testItem, parsedItem); - assertEquals(testItem.hashCode(), parsedItem.hashCode()); + try (XContentParser parser = createParser(shuffled)) { + parser.nextToken(); + NestedSortBuilder parsedItem = NestedSortBuilder.fromXContent(parser); + assertNotSame(testItem, parsedItem); + assertEquals(testItem, parsedItem); + assertEquals(testItem.hashCode(), parsedItem.hashCode()); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java index 9a030cc3aabcb..0f19b709a4fed 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java @@ -177,20 +177,21 @@ public void testParseJson() throws IOException { "\"mode\" : \"max\",\n" + "\"order\" : \"asc\"\n" + "} }\n"; - XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - - ScriptSortBuilder builder = ScriptSortBuilder.fromXContent(parser, null); - assertEquals("doc['field_name'].value * factor", builder.script().getIdOrCode()); - assertEquals(Script.DEFAULT_SCRIPT_LANG, builder.script().getLang()); - assertEquals(1.1, builder.script().getParams().get("factor")); - assertEquals(ScriptType.INLINE, builder.script().getType()); - assertEquals(ScriptSortType.NUMBER, builder.type()); - assertEquals(SortOrder.ASC, builder.order()); - assertEquals(SortMode.MAX, builder.sortMode()); - assertNull(builder.getNestedSort()); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort)) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + + ScriptSortBuilder builder = ScriptSortBuilder.fromXContent(parser, null); + assertEquals("doc['field_name'].value * factor", builder.script().getIdOrCode()); + assertEquals(Script.DEFAULT_SCRIPT_LANG, builder.script().getLang()); + assertEquals(1.1, builder.script().getParams().get("factor")); + assertEquals(ScriptType.INLINE, builder.script().getType()); + assertEquals(ScriptSortType.NUMBER, builder.type()); + assertEquals(SortOrder.ASC, builder.order()); + assertEquals(SortMode.MAX, builder.sortMode()); + assertNull(builder.getNestedSort()); + } } public void testParseJson_simple() throws IOException { @@ -201,54 +202,58 @@ public void testParseJson_simple() throws IOException { "\"mode\" : \"max\",\n" + "\"order\" : \"asc\"\n" + "} }\n"; - XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); - - ScriptSortBuilder builder = ScriptSortBuilder.fromXContent(parser, null); - assertEquals("doc['field_name'].value", builder.script().getIdOrCode()); - assertEquals(Script.DEFAULT_SCRIPT_LANG, builder.script().getLang()); - assertEquals(builder.script().getParams(), Collections.emptyMap()); - assertEquals(ScriptType.INLINE, builder.script().getType()); - assertEquals(ScriptSortType.NUMBER, builder.type()); - assertEquals(SortOrder.ASC, builder.order()); - assertEquals(SortMode.MAX, builder.sortMode()); - assertNull(builder.getNestedSort()); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort)) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); + + ScriptSortBuilder builder = ScriptSortBuilder.fromXContent(parser, null); + assertEquals("doc['field_name'].value", builder.script().getIdOrCode()); + assertEquals(Script.DEFAULT_SCRIPT_LANG, builder.script().getLang()); + assertEquals(builder.script().getParams(), Collections.emptyMap()); + assertEquals(ScriptType.INLINE, builder.script().getType()); + assertEquals(ScriptSortType.NUMBER, builder.type()); + assertEquals(SortOrder.ASC, builder.order()); + assertEquals(SortMode.MAX, builder.sortMode()); + assertNull(builder.getNestedSort()); + } } public void testParseBadFieldNameExceptions() throws IOException { String scriptSort = "{\"_script\" : {" + "\"bad_field\" : \"number\"" + "} }"; - XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort)) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); - XContentParseException e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); - assertEquals("[1:15] [_script] unknown field [bad_field], parser not found", e.getMessage()); + XContentParseException e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); + assertEquals("[1:15] [_script] unknown field [bad_field], parser not found", e.getMessage()); + } } public void testParseBadFieldNameExceptionsOnStartObject() throws IOException { String scriptSort = "{\"_script\" : {" + "\"bad_field\" : { \"order\" : \"asc\" } } }"; - XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort)) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); - XContentParseException e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); - assertEquals("[1:15] [_script] unknown field [bad_field], parser not found", e.getMessage()); + XContentParseException e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); + assertEquals("[1:15] [_script] unknown field [bad_field], parser not found", e.getMessage()); + } } public void testParseUnexpectedToken() throws IOException { String scriptSort = "{\"_script\" : {" + "\"script\" : [ \"order\" : \"asc\" ] } }"; - XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort); - parser.nextToken(); - parser.nextToken(); - parser.nextToken(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, scriptSort)) { + parser.nextToken(); + parser.nextToken(); + parser.nextToken(); - Exception e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); - assertThat(e.getMessage(), containsString("[_script] script doesn't support values of type: START_ARRAY")); + Exception e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); + assertThat(e.getMessage(), containsString("[_script] script doesn't support values of type: START_ARRAY")); + } } /** diff --git a/server/src/test/java/org/elasticsearch/search/sort/SortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/SortBuilderTests.java index f267dec2a8623..5f5ea5e869450 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/SortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/SortBuilderTests.java @@ -252,12 +252,13 @@ protected NamedXContentRegistry xContentRegistry() { } private List> parseSort(String jsonString) throws IOException { - XContentParser itemParser = createParser(JsonXContent.jsonXContent, jsonString); + try (XContentParser itemParser = createParser(JsonXContent.jsonXContent, jsonString)) { - assertEquals(XContentParser.Token.START_OBJECT, itemParser.nextToken()); - assertEquals(XContentParser.Token.FIELD_NAME, itemParser.nextToken()); - assertEquals("sort", itemParser.currentName()); - itemParser.nextToken(); - return SortBuilder.fromXContent(itemParser); + assertEquals(XContentParser.Token.START_OBJECT, itemParser.nextToken()); + assertEquals(XContentParser.Token.FIELD_NAME, itemParser.nextToken()); + assertEquals("sort", itemParser.currentName()); + itemParser.nextToken(); + return SortBuilder.fromXContent(itemParser); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/suggest/AbstractSuggestionBuilderTestCase.java b/server/src/test/java/org/elasticsearch/search/suggest/AbstractSuggestionBuilderTestCase.java index eb31f19ad4e83..00a287f02528c 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/AbstractSuggestionBuilderTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/AbstractSuggestionBuilderTestCase.java @@ -140,14 +140,15 @@ public void testFromXContent() throws IOException { xContentBuilder.endObject(); XContentBuilder shuffled = shuffleXContent(xContentBuilder, shuffleProtectedFields()); - XContentParser parser = createParser(shuffled); - // we need to skip the start object and the name, those will be parsed by outer SuggestBuilder - parser.nextToken(); + try (XContentParser parser = createParser(shuffled)) { + // we need to skip the start object and the name, those will be parsed by outer SuggestBuilder + parser.nextToken(); - SuggestionBuilder secondSuggestionBuilder = SuggestionBuilder.fromXContent(parser); - assertNotSame(suggestionBuilder, secondSuggestionBuilder); - assertEquals(suggestionBuilder, secondSuggestionBuilder); - assertEquals(suggestionBuilder.hashCode(), secondSuggestionBuilder.hashCode()); + SuggestionBuilder secondSuggestionBuilder = SuggestionBuilder.fromXContent(parser); + assertNotSame(suggestionBuilder, secondSuggestionBuilder); + assertEquals(suggestionBuilder, secondSuggestionBuilder); + assertEquals(suggestionBuilder.hashCode(), secondSuggestionBuilder.hashCode()); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java b/server/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java index 16de2a3506740..2b99c62185b7c 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java @@ -74,11 +74,12 @@ public void testFromXContent() throws IOException { xContentBuilder.prettyPrint(); } suggestBuilder.toXContent(xContentBuilder, ToXContent.EMPTY_PARAMS); - XContentParser parser = createParser(xContentBuilder); - SuggestBuilder secondSuggestBuilder = SuggestBuilder.fromXContent(parser); - assertNotSame(suggestBuilder, secondSuggestBuilder); - assertEquals(suggestBuilder, secondSuggestBuilder); - assertEquals(suggestBuilder.hashCode(), secondSuggestBuilder.hashCode()); + try (XContentParser parser = createParser(xContentBuilder)) { + SuggestBuilder secondSuggestBuilder = SuggestBuilder.fromXContent(parser); + assertNotSame(suggestBuilder, secondSuggestBuilder); + assertEquals(suggestBuilder, secondSuggestBuilder); + assertEquals(suggestBuilder.hashCode(), secondSuggestBuilder.hashCode()); + } } } diff --git a/server/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java b/server/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java index 6ebced51e1ea1..3a7451e78fb4f 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java @@ -368,44 +368,48 @@ public void testIndexingWithMultipleContexts() throws Exception { public void testQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().value("context1"); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(1)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(1)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(1)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(1)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + } } public void testBooleanQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().value(true); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(1)); - assertThat(internalQueryContexts.get(0).context, equalTo("true")); - assertThat(internalQueryContexts.get(0).boost, equalTo(1)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(1)); + assertThat(internalQueryContexts.get(0).context, equalTo("true")); + assertThat(internalQueryContexts.get(0).boost, equalTo(1)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + } } public void testNumberQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().value(10); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(1)); - assertThat(internalQueryContexts.get(0).context, equalTo("10")); - assertThat(internalQueryContexts.get(0).boost, equalTo(1)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(1)); + assertThat(internalQueryContexts.get(0).context, equalTo("10")); + assertThat(internalQueryContexts.get(0).boost, equalTo(1)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + } } public void testNULLQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().nullValue(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); - assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be an object, string, number or boolean")); + XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); + assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be an object, string, number or boolean")); + } } public void testQueryContextParsingArray() throws Exception { @@ -413,16 +417,17 @@ public void testQueryContextParsingArray() throws Exception { .value("context1") .value("context2") .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(2)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(1)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(1).context, equalTo("context2")); - assertThat(internalQueryContexts.get(1).boost, equalTo(1)); - assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(2)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(1)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(1).context, equalTo("context2")); + assertThat(internalQueryContexts.get(1).boost, equalTo(1)); + assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + } } public void testQueryContextParsingMixedTypeValuesArray() throws Exception { @@ -432,22 +437,23 @@ public void testQueryContextParsingMixedTypeValuesArray() throws Exception { .value(true) .value(10) .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(4)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(1)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(1).context, equalTo("context2")); - assertThat(internalQueryContexts.get(1).boost, equalTo(1)); - assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(2).context, equalTo("true")); - assertThat(internalQueryContexts.get(2).boost, equalTo(1)); - assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(3).context, equalTo("10")); - assertThat(internalQueryContexts.get(3).boost, equalTo(1)); - assertThat(internalQueryContexts.get(3).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(4)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(1)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(1).context, equalTo("context2")); + assertThat(internalQueryContexts.get(1).boost, equalTo(1)); + assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(2).context, equalTo("true")); + assertThat(internalQueryContexts.get(2).boost, equalTo(1)); + assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(3).context, equalTo("10")); + assertThat(internalQueryContexts.get(3).boost, equalTo(1)); + assertThat(internalQueryContexts.get(3).isPrefix, equalTo(false)); + } } public void testQueryContextParsingMixedTypeValuesArrayHavingNULL() throws Exception { @@ -458,11 +464,12 @@ public void testQueryContextParsingMixedTypeValuesArrayHavingNULL() throws Excep .value(10) .nullValue() .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); - assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be an object, string, number or boolean")); + XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); + assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be an object, string, number or boolean")); + } } public void testQueryContextParsingObject() throws Exception { @@ -471,13 +478,14 @@ public void testQueryContextParsingObject() throws Exception { .field("boost", 10) .field("prefix", true) .endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(1)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(10)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(1)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(10)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + } } public void testQueryContextParsingObjectHavingBoolean() throws Exception { @@ -486,13 +494,14 @@ public void testQueryContextParsingObjectHavingBoolean() throws Exception { .field("boost", 10) .field("prefix", true) .endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(1)); - assertThat(internalQueryContexts.get(0).context, equalTo("false")); - assertThat(internalQueryContexts.get(0).boost, equalTo(10)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(1)); + assertThat(internalQueryContexts.get(0).context, equalTo("false")); + assertThat(internalQueryContexts.get(0).boost, equalTo(10)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + } } public void testQueryContextParsingObjectHavingNumber() throws Exception { @@ -501,13 +510,14 @@ public void testQueryContextParsingObjectHavingNumber() throws Exception { .field("boost", 10) .field("prefix", true) .endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(1)); - assertThat(internalQueryContexts.get(0).context, equalTo("333")); - assertThat(internalQueryContexts.get(0).boost, equalTo(10)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(1)); + assertThat(internalQueryContexts.get(0).context, equalTo("333")); + assertThat(internalQueryContexts.get(0).boost, equalTo(10)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + } } public void testQueryContextParsingObjectHavingNULL() throws Exception { @@ -516,11 +526,12 @@ public void testQueryContextParsingObjectHavingNULL() throws Exception { .field("boost", 10) .field("prefix", true) .endObject(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - Exception e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); - assertThat(e.getMessage(), containsString("category context must be a string, number or boolean")); + Exception e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); + assertThat(e.getMessage(), containsString("category context must be a string, number or boolean")); + } } public void testQueryContextParsingObjectArray() throws Exception { @@ -536,16 +547,17 @@ public void testQueryContextParsingObjectArray() throws Exception { .field("prefix", false) .endObject() .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(2)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(2)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); - assertThat(internalQueryContexts.get(1).context, equalTo("context2")); - assertThat(internalQueryContexts.get(1).boost, equalTo(3)); - assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(2)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(2)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + assertThat(internalQueryContexts.get(1).context, equalTo("context2")); + assertThat(internalQueryContexts.get(1).boost, equalTo(3)); + assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + } } public void testQueryContextParsingMixedTypeObjectArray() throws Exception { @@ -571,22 +583,23 @@ public void testQueryContextParsingMixedTypeObjectArray() throws Exception { .field("prefix", false) .endObject() .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(4)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(2)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); - assertThat(internalQueryContexts.get(1).context, equalTo("context2")); - assertThat(internalQueryContexts.get(1).boost, equalTo(3)); - assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(2).context, equalTo("true")); - assertThat(internalQueryContexts.get(2).boost, equalTo(3)); - assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(3).context, equalTo("333")); - assertThat(internalQueryContexts.get(3).boost, equalTo(3)); - assertThat(internalQueryContexts.get(3).isPrefix, equalTo(false)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(4)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(2)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + assertThat(internalQueryContexts.get(1).context, equalTo("context2")); + assertThat(internalQueryContexts.get(1).boost, equalTo(3)); + assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(2).context, equalTo("true")); + assertThat(internalQueryContexts.get(2).boost, equalTo(3)); + assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(3).context, equalTo("333")); + assertThat(internalQueryContexts.get(3).boost, equalTo(3)); + assertThat(internalQueryContexts.get(3).isPrefix, equalTo(false)); + } } public void testQueryContextParsingMixedTypeObjectArrayHavingNULL() throws Exception { @@ -617,11 +630,12 @@ public void testQueryContextParsingMixedTypeObjectArrayHavingNULL() throws Excep .field("prefix", false) .endObject() .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); - assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be a string, number or boolean")); + XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); + assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be a string, number or boolean")); + } } @@ -640,22 +654,23 @@ public void testQueryContextParsingMixed() throws Exception { .field("prefix", true) .endObject() .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - List internalQueryContexts = mapping.parseQueryContext(parser); - assertThat(internalQueryContexts.size(), equalTo(4)); - assertThat(internalQueryContexts.get(0).context, equalTo("context1")); - assertThat(internalQueryContexts.get(0).boost, equalTo(2)); - assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); - assertThat(internalQueryContexts.get(1).context, equalTo("context2")); - assertThat(internalQueryContexts.get(1).boost, equalTo(1)); - assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(2).context, equalTo("false")); - assertThat(internalQueryContexts.get(2).boost, equalTo(1)); - assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); - assertThat(internalQueryContexts.get(3).context, equalTo("333")); - assertThat(internalQueryContexts.get(3).boost, equalTo(2)); - assertThat(internalQueryContexts.get(3).isPrefix, equalTo(true)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + List internalQueryContexts = mapping.parseQueryContext(parser); + assertThat(internalQueryContexts.size(), equalTo(4)); + assertThat(internalQueryContexts.get(0).context, equalTo("context1")); + assertThat(internalQueryContexts.get(0).boost, equalTo(2)); + assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); + assertThat(internalQueryContexts.get(1).context, equalTo("context2")); + assertThat(internalQueryContexts.get(1).boost, equalTo(1)); + assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(2).context, equalTo("false")); + assertThat(internalQueryContexts.get(2).boost, equalTo(1)); + assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); + assertThat(internalQueryContexts.get(3).context, equalTo("333")); + assertThat(internalQueryContexts.get(3).boost, equalTo(2)); + assertThat(internalQueryContexts.get(3).isPrefix, equalTo(true)); + } } public void testQueryContextParsingMixedHavingNULL() throws Exception { @@ -674,11 +689,12 @@ public void testQueryContextParsingMixedHavingNULL() throws Exception { .endObject() .nullValue() .endArray(); - XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder)); - CategoryContextMapping mapping = ContextBuilder.category("cat").build(); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + CategoryContextMapping mapping = ContextBuilder.category("cat").build(); - XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); - assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be an object, string, number or boolean")); + XContentParseException e = expectThrows(XContentParseException.class, () -> mapping.parseQueryContext(parser)); + assertThat(ExceptionsHelper.detailedMessage(e), containsString("category context must be an object, string, number or boolean")); + } } public void testUnknownQueryContextParsing() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java b/server/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java index ebfac5f58ef77..925526323a540 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java @@ -124,12 +124,13 @@ public void testFromXContent() throws IOException { builder.prettyPrint(); } generator.toXContent(builder, ToXContent.EMPTY_PARAMS); - XContentParser parser = createParser(shuffleXContent(builder)); - parser.nextToken(); - DirectCandidateGeneratorBuilder secondGenerator = DirectCandidateGeneratorBuilder.PARSER.apply(parser, null); - assertNotSame(generator, secondGenerator); - assertEquals(generator, secondGenerator); - assertEquals(generator.hashCode(), secondGenerator.hashCode()); + try (XContentParser parser = createParser(shuffleXContent(builder))) { + parser.nextToken(); + DirectCandidateGeneratorBuilder secondGenerator = DirectCandidateGeneratorBuilder.PARSER.apply(parser, null); + assertNotSame(generator, secondGenerator); + assertEquals(generator, secondGenerator); + assertEquals(generator.hashCode(), secondGenerator.hashCode()); + } } } @@ -187,9 +188,10 @@ public void testIllegalXContent() throws IOException { private void assertIllegalXContent(String directGenerator, Class exceptionClass, String exceptionMsg) throws IOException { - XContentParser parser = createParser(JsonXContent.jsonXContent, directGenerator); - Exception e = expectThrows(exceptionClass, () -> DirectCandidateGeneratorBuilder.PARSER.apply(parser, null)); - assertThat(e.getMessage(), containsString(exceptionMsg)); + try (XContentParser parser = createParser(JsonXContent.jsonXContent, directGenerator)) { + Exception e = expectThrows(exceptionClass, () -> DirectCandidateGeneratorBuilder.PARSER.apply(parser, null)); + assertThat(e.getMessage(), containsString(exceptionMsg)); + } } /** diff --git a/server/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java b/server/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java index e75d01739ccb8..5923cd3332e5e 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java @@ -95,12 +95,13 @@ public void testFromXContent() throws IOException { contentBuilder.startObject(); testModel.innerToXContent(contentBuilder, ToXContent.EMPTY_PARAMS); contentBuilder.endObject(); - XContentParser parser = createParser(shuffleXContent(contentBuilder)); - parser.nextToken(); // go to start token, real parsing would do that in the outer element parser - SmoothingModel parsedModel = fromXContent(parser); - assertNotSame(testModel, parsedModel); - assertEquals(testModel, parsedModel); - assertEquals(testModel.hashCode(), parsedModel.hashCode()); + try (XContentParser parser = createParser(shuffleXContent(contentBuilder))) { + parser.nextToken(); // go to start token, real parsing would do that in the outer element parser + SmoothingModel parsedModel = fromXContent(parser); + assertNotSame(testModel, parsedModel); + assertEquals(testModel, parsedModel); + assertEquals(testModel.hashCode(), parsedModel.hashCode()); + } } /** From 8b698f0bce8c73cb6d8510ce6a3f857cb0fb2f02 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Mon, 25 Jun 2018 10:12:31 +0200 Subject: [PATCH 04/23] turn GetFieldMappingsResponse to ToXContentObject (#31544) --- .../admin/indices/mapping/get/GetFieldMappingsResponse.java | 5 ++++- .../rest/action/admin/indices/RestGetFieldMappingAction.java | 2 -- .../indices/mapping/SimpleGetFieldMappingsIT.java | 4 ---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java index 81b9812d61c5f..44a66f497c846 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; @@ -47,7 +48,7 @@ import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken; /** Response object for {@link GetFieldMappingsRequest} API */ -public class GetFieldMappingsResponse extends ActionResponse implements ToXContentFragment { +public class GetFieldMappingsResponse extends ActionResponse implements ToXContentObject { private static final ParseField MAPPINGS = new ParseField("mappings"); @@ -111,6 +112,7 @@ public FieldMappingMetaData fieldMappings(String index, String type, String fiel @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); for (Map.Entry>> indexEntry : mappings.entrySet()) { builder.startObject(indexEntry.getKey()); builder.startObject(MAPPINGS.getPreferredName()); @@ -126,6 +128,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.endObject(); builder.endObject(); } + builder.endObject(); return builder; } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java index ea68d9cc3c04f..c43f14dcddf26 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java @@ -81,9 +81,7 @@ public RestResponse buildResponse(GetFieldMappingsResponse response, XContentBui if (mappingsByIndex.isEmpty() && fields.length > 0) { status = NOT_FOUND; } - builder.startObject(); response.toXContent(builder, request); - builder.endObject(); return new BytesRestResponse(status, builder); } }); diff --git a/server/src/test/java/org/elasticsearch/indices/mapping/SimpleGetFieldMappingsIT.java b/server/src/test/java/org/elasticsearch/indices/mapping/SimpleGetFieldMappingsIT.java index f5cac445b220d..2ba943ba0dc4b 100644 --- a/server/src/test/java/org/elasticsearch/indices/mapping/SimpleGetFieldMappingsIT.java +++ b/server/src/test/java/org/elasticsearch/indices/mapping/SimpleGetFieldMappingsIT.java @@ -149,9 +149,7 @@ public void testSimpleGetFieldMappingsWithPretty() throws Exception { params.put("pretty", "true"); GetFieldMappingsResponse response = client().admin().indices().prepareGetFieldMappings("index").setTypes("type").setFields("field1", "obj.subfield").get(); XContentBuilder responseBuilder = XContentFactory.jsonBuilder().prettyPrint(); - responseBuilder.startObject(); response.toXContent(responseBuilder, new ToXContent.MapParams(params)); - responseBuilder.endObject(); String responseStrings = Strings.toString(responseBuilder); @@ -163,9 +161,7 @@ public void testSimpleGetFieldMappingsWithPretty() throws Exception { response = client().admin().indices().prepareGetFieldMappings("index").setTypes("type").setFields("field1", "obj.subfield").get(); responseBuilder = XContentFactory.jsonBuilder().prettyPrint().lfAtEnd(); - responseBuilder.startObject(); response.toXContent(responseBuilder, new ToXContent.MapParams(params)); - responseBuilder.endObject(); responseStrings = Strings.toString(responseBuilder); prettyJsonBuilder = XContentFactory.jsonBuilder().prettyPrint(); From 8e4768890abbd2fb6fbc49d6188909ed7ca6961b Mon Sep 17 00:00:00 2001 From: Jonathan Little Date: Mon, 25 Jun 2018 04:01:33 -0700 Subject: [PATCH 05/23] Migrate scripted metric aggregation scripts to ScriptContext design (#30111) * Migrate scripted metric aggregation scripts to ScriptContext design #29328 * Rename new script context container class and add clarifying comments to remaining references to params._agg(s) * Misc cleanup: make mock metric agg script inner classes static * Move _score to an accessor rather than an arg for scripted metric agg scripts This causes the score to be evaluated only when it's used. * Documentation changes for params._agg -> agg * Migration doc addition for scripted metric aggs _agg object change * Rename "agg" Scripted Metric Aggregation script context variable to "state" * Rename a private base class from ...Agg to ...State that I missed in my last commit * Clean up imports after merge --- .../scripted-metric-aggregation.asciidoc | 18 +- .../scripted-metric-aggregation.asciidoc | 64 +++---- .../migrate_7_0/aggregations.asciidoc | 10 +- .../ScriptedMetricAggContextsTests.java | 126 ++++++++++++++ .../elasticsearch/script/ScriptModule.java | 6 +- .../script/ScriptedMetricAggContexts.java | 161 ++++++++++++++++++ .../scripted/InternalScriptedMetric.java | 19 ++- .../ScriptedMetricAggregationBuilder.java | 23 +-- .../scripted/ScriptedMetricAggregator.java | 36 ++-- .../ScriptedMetricAggregatorFactory.java | 38 +++-- .../metrics/ScriptedMetricIT.java | 82 ++++++++- .../ScriptedMetricAggregatorTests.java | 3 +- .../script/MockScriptEngine.java | 144 +++++++++++++++- 13 files changed, 619 insertions(+), 111 deletions(-) create mode 100644 modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptedMetricAggContextsTests.java create mode 100644 server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java diff --git a/docs/java-api/aggregations/metrics/scripted-metric-aggregation.asciidoc b/docs/java-api/aggregations/metrics/scripted-metric-aggregation.asciidoc index b23a683b05610..5b68fa7be451f 100644 --- a/docs/java-api/aggregations/metrics/scripted-metric-aggregation.asciidoc +++ b/docs/java-api/aggregations/metrics/scripted-metric-aggregation.asciidoc @@ -13,8 +13,8 @@ Here is an example on how to create the aggregation request: -------------------------------------------------- ScriptedMetricAggregationBuilder aggregation = AggregationBuilders .scriptedMetric("agg") - .initScript(new Script("params._agg.heights = []")) - .mapScript(new Script("params._agg.heights.add(doc.gender.value == 'male' ? doc.height.value : -1.0 * doc.height.value)")); + .initScript(new Script("state.heights = []")) + .mapScript(new Script("state.heights.add(doc.gender.value == 'male' ? doc.height.value : -1.0 * doc.height.value)")); -------------------------------------------------- You can also specify a `combine` script which will be executed on each shard: @@ -23,9 +23,9 @@ You can also specify a `combine` script which will be executed on each shard: -------------------------------------------------- ScriptedMetricAggregationBuilder aggregation = AggregationBuilders .scriptedMetric("agg") - .initScript(new Script("params._agg.heights = []")) - .mapScript(new Script("params._agg.heights.add(doc.gender.value == 'male' ? doc.height.value : -1.0 * doc.height.value)")) - .combineScript(new Script("double heights_sum = 0.0; for (t in params._agg.heights) { heights_sum += t } return heights_sum")); + .initScript(new Script("state.heights = []")) + .mapScript(new Script("state.heights.add(doc.gender.value == 'male' ? doc.height.value : -1.0 * doc.height.value)")) + .combineScript(new Script("double heights_sum = 0.0; for (t in state.heights) { heights_sum += t } return heights_sum")); -------------------------------------------------- You can also specify a `reduce` script which will be executed on the node which gets the request: @@ -34,10 +34,10 @@ You can also specify a `reduce` script which will be executed on the node which -------------------------------------------------- ScriptedMetricAggregationBuilder aggregation = AggregationBuilders .scriptedMetric("agg") - .initScript(new Script("params._agg.heights = []")) - .mapScript(new Script("params._agg.heights.add(doc.gender.value == 'male' ? doc.height.value : -1.0 * doc.height.value)")) - .combineScript(new Script("double heights_sum = 0.0; for (t in params._agg.heights) { heights_sum += t } return heights_sum")) - .reduceScript(new Script("double heights_sum = 0.0; for (a in params._aggs) { heights_sum += a } return heights_sum")); + .initScript(new Script("state.heights = []")) + .mapScript(new Script("state.heights.add(doc.gender.value == 'male' ? doc.height.value : -1.0 * doc.height.value)")) + .combineScript(new Script("double heights_sum = 0.0; for (t in state.heights) { heights_sum += t } return heights_sum")) + .reduceScript(new Script("double heights_sum = 0.0; for (a in states) { heights_sum += a } return heights_sum")); -------------------------------------------------- diff --git a/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc b/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc index 1a4d6d4774c49..c4857699f9805 100644 --- a/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc +++ b/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc @@ -15,10 +15,10 @@ POST ledger/_search?size=0 "aggs": { "profit": { "scripted_metric": { - "init_script" : "params._agg.transactions = []", - "map_script" : "params._agg.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)", <1> - "combine_script" : "double profit = 0; for (t in params._agg.transactions) { profit += t } return profit", - "reduce_script" : "double profit = 0; for (a in params._aggs) { profit += a } return profit" + "init_script" : "state.transactions = []", + "map_script" : "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)", <1> + "combine_script" : "double profit = 0; for (t in state.transactions) { profit += t } return profit", + "reduce_script" : "double profit = 0; for (a in states) { profit += a } return profit" } } } @@ -67,8 +67,7 @@ POST ledger/_search?size=0 "id": "my_combine_script" }, "params": { - "field": "amount", <1> - "_agg": {} <2> + "field": "amount" <1> }, "reduce_script" : { "id": "my_reduce_script" @@ -82,8 +81,7 @@ POST ledger/_search?size=0 // TEST[setup:ledger,stored_scripted_metric_script] <1> script parameters for `init`, `map` and `combine` scripts must be specified -in a global `params` object so that it can be share between the scripts. -<2> if you specify script parameters then you must specify `"_agg": {}`. +in a global `params` object so that it can be shared between the scripts. //// Verify this response as well but in a hidden block. @@ -108,7 +106,7 @@ For more details on specifying scripts see <, List> scriptContexts() { + Map, List> contexts = new HashMap<>(); + contexts.put(ScriptedMetricAggContexts.InitScript.CONTEXT, Whitelist.BASE_WHITELISTS); + contexts.put(ScriptedMetricAggContexts.MapScript.CONTEXT, Whitelist.BASE_WHITELISTS); + contexts.put(ScriptedMetricAggContexts.CombineScript.CONTEXT, Whitelist.BASE_WHITELISTS); + contexts.put(ScriptedMetricAggContexts.ReduceScript.CONTEXT, Whitelist.BASE_WHITELISTS); + return contexts; + } + + public void testInitBasic() { + ScriptedMetricAggContexts.InitScript.Factory factory = scriptEngine.compile("test", + "state.testField = params.initialVal", ScriptedMetricAggContexts.InitScript.CONTEXT, Collections.emptyMap()); + + Map params = new HashMap<>(); + Map state = new HashMap<>(); + + params.put("initialVal", 10); + + ScriptedMetricAggContexts.InitScript script = factory.newInstance(params, state); + script.execute(); + + assert(state.containsKey("testField")); + assertEquals(10, state.get("testField")); + } + + public void testMapBasic() { + ScriptedMetricAggContexts.MapScript.Factory factory = scriptEngine.compile("test", + "state.testField = 2*_score", ScriptedMetricAggContexts.MapScript.CONTEXT, Collections.emptyMap()); + + Map params = new HashMap<>(); + Map state = new HashMap<>(); + + Scorer scorer = new Scorer(null) { + @Override + public int docID() { return 0; } + + @Override + public float score() { return 0.5f; } + + @Override + public DocIdSetIterator iterator() { return null; } + }; + + ScriptedMetricAggContexts.MapScript.LeafFactory leafFactory = factory.newFactory(params, state, null); + ScriptedMetricAggContexts.MapScript script = leafFactory.newInstance(null); + + script.setScorer(scorer); + script.execute(); + + assert(state.containsKey("testField")); + assertEquals(1.0, state.get("testField")); + } + + public void testCombineBasic() { + ScriptedMetricAggContexts.CombineScript.Factory factory = scriptEngine.compile("test", + "state.testField = params.initialVal; return state.testField + params.inc", ScriptedMetricAggContexts.CombineScript.CONTEXT, + Collections.emptyMap()); + + Map params = new HashMap<>(); + Map state = new HashMap<>(); + + params.put("initialVal", 10); + params.put("inc", 2); + + ScriptedMetricAggContexts.CombineScript script = factory.newInstance(params, state); + Object res = script.execute(); + + assert(state.containsKey("testField")); + assertEquals(10, state.get("testField")); + assertEquals(12, res); + } + + public void testReduceBasic() { + ScriptedMetricAggContexts.ReduceScript.Factory factory = scriptEngine.compile("test", + "states[0].testField + states[1].testField", ScriptedMetricAggContexts.ReduceScript.CONTEXT, Collections.emptyMap()); + + Map params = new HashMap<>(); + List states = new ArrayList<>(); + + Map state1 = new HashMap<>(), state2 = new HashMap<>(); + state1.put("testField", 1); + state2.put("testField", 2); + + states.add(state1); + states.add(state2); + + ScriptedMetricAggContexts.ReduceScript script = factory.newInstance(params, states); + Object res = script.execute(); + assertEquals(3, res); + } +} diff --git a/server/src/main/java/org/elasticsearch/script/ScriptModule.java b/server/src/main/java/org/elasticsearch/script/ScriptModule.java index 7074d3ad9fe44..f0e075eac7d93 100644 --- a/server/src/main/java/org/elasticsearch/script/ScriptModule.java +++ b/server/src/main/java/org/elasticsearch/script/ScriptModule.java @@ -53,7 +53,11 @@ public class ScriptModule { SimilarityScript.CONTEXT, SimilarityWeightScript.CONTEXT, TemplateScript.CONTEXT, - MovingFunctionScript.CONTEXT + MovingFunctionScript.CONTEXT, + ScriptedMetricAggContexts.InitScript.CONTEXT, + ScriptedMetricAggContexts.MapScript.CONTEXT, + ScriptedMetricAggContexts.CombineScript.CONTEXT, + ScriptedMetricAggContexts.ReduceScript.CONTEXT ).collect(Collectors.toMap(c -> c.name, Function.identity())); } diff --git a/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java b/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java new file mode 100644 index 0000000000000..774dc95d39977 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java @@ -0,0 +1,161 @@ +/* + * 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.script; + +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.Scorer; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.index.fielddata.ScriptDocValues; +import org.elasticsearch.search.lookup.LeafSearchLookup; +import org.elasticsearch.search.lookup.SearchLookup; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class ScriptedMetricAggContexts { + private abstract static class ParamsAndStateBase { + private final Map params; + private final Object state; + + ParamsAndStateBase(Map params, Object state) { + this.params = params; + this.state = state; + } + + public Map getParams() { + return params; + } + + public Object getState() { + return state; + } + } + + public abstract static class InitScript extends ParamsAndStateBase { + public InitScript(Map params, Object state) { + super(params, state); + } + + public abstract void execute(); + + public interface Factory { + InitScript newInstance(Map params, Object state); + } + + public static String[] PARAMETERS = {}; + public static ScriptContext CONTEXT = new ScriptContext<>("aggs_init", Factory.class); + } + + public abstract static class MapScript extends ParamsAndStateBase { + private final LeafSearchLookup leafLookup; + private Scorer scorer; + + public MapScript(Map params, Object state, SearchLookup lookup, LeafReaderContext leafContext) { + super(params, state); + + this.leafLookup = leafContext == null ? null : lookup.getLeafSearchLookup(leafContext); + } + + // Return the doc as a map (instead of LeafDocLookup) in order to abide by type whitelisting rules for + // Painless scripts. + public Map> getDoc() { + return leafLookup == null ? null : leafLookup.doc(); + } + + public void setDocument(int docId) { + if (leafLookup != null) { + leafLookup.setDocument(docId); + } + } + + public void setScorer(Scorer scorer) { + this.scorer = scorer; + } + + // get_score() is named this way so that it's picked up by Painless as '_score' + public double get_score() { + if (scorer == null) { + return 0.0; + } + + try { + return scorer.score(); + } catch (IOException e) { + throw new ElasticsearchException("Couldn't look up score", e); + } + } + + public abstract void execute(); + + public interface LeafFactory { + MapScript newInstance(LeafReaderContext ctx); + } + + public interface Factory { + LeafFactory newFactory(Map params, Object state, SearchLookup lookup); + } + + public static String[] PARAMETERS = new String[] {}; + public static ScriptContext CONTEXT = new ScriptContext<>("aggs_map", Factory.class); + } + + public abstract static class CombineScript extends ParamsAndStateBase { + public CombineScript(Map params, Object state) { + super(params, state); + } + + public abstract Object execute(); + + public interface Factory { + CombineScript newInstance(Map params, Object state); + } + + public static String[] PARAMETERS = {}; + public static ScriptContext CONTEXT = new ScriptContext<>("aggs_combine", Factory.class); + } + + public abstract static class ReduceScript { + private final Map params; + private final List states; + + public ReduceScript(Map params, List states) { + this.params = params; + this.states = states; + } + + public Map getParams() { + return params; + } + + public List getStates() { + return states; + } + + public abstract Object execute(); + + public interface Factory { + ReduceScript newInstance(Map params, List states); + } + + public static String[] PARAMETERS = {}; + public static ScriptContext CONTEXT = new ScriptContext<>("aggs_reduce", Factory.class); + } +} diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java index e350ecbed5814..f4281c063ff2c 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java @@ -23,7 +23,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.ScriptedMetricAggContexts; import org.elasticsearch.script.Script; import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; @@ -90,16 +90,19 @@ public InternalAggregation doReduce(List aggregations, Redu InternalScriptedMetric firstAggregation = ((InternalScriptedMetric) aggregations.get(0)); List aggregation; if (firstAggregation.reduceScript != null && reduceContext.isFinalReduce()) { - Map vars = new HashMap<>(); - vars.put("_aggs", aggregationObjects); + Map params = new HashMap<>(); if (firstAggregation.reduceScript.getParams() != null) { - vars.putAll(firstAggregation.reduceScript.getParams()); + params.putAll(firstAggregation.reduceScript.getParams()); } - ExecutableScript.Factory factory = reduceContext.scriptService().compile( - firstAggregation.reduceScript, ExecutableScript.AGGS_CONTEXT); - ExecutableScript script = factory.newInstance(vars); - Object scriptResult = script.run(); + // Add _aggs to params map for backwards compatibility (redundant with a context variable on the ReduceScript created below). + params.put("_aggs", aggregationObjects); + + ScriptedMetricAggContexts.ReduceScript.Factory factory = reduceContext.scriptService().compile( + firstAggregation.reduceScript, ScriptedMetricAggContexts.ReduceScript.CONTEXT); + ScriptedMetricAggContexts.ReduceScript script = factory.newInstance(params, aggregationObjects); + + Object scriptResult = script.execute(); CollectionUtils.ensureNoSelfReferences(scriptResult, "reduce script"); aggregation = Collections.singletonList(scriptResult); diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java index 225398e51b7c0..8b6d834184d73 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregationBuilder.java @@ -26,9 +26,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryShardContext; -import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.ScriptedMetricAggContexts; import org.elasticsearch.script.Script; -import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.aggregations.AbstractAggregationBuilder; import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregatorFactories.Builder; @@ -202,30 +201,32 @@ protected ScriptedMetricAggregatorFactory doBuild(SearchContext context, Aggrega // Extract params from scripts and pass them along to ScriptedMetricAggregatorFactory, since it won't have // access to them for the scripts it's given precompiled. - ExecutableScript.Factory executableInitScript; + ScriptedMetricAggContexts.InitScript.Factory compiledInitScript; Map initScriptParams; if (initScript != null) { - executableInitScript = queryShardContext.getScriptService().compile(initScript, ExecutableScript.AGGS_CONTEXT); + compiledInitScript = queryShardContext.getScriptService().compile(initScript, ScriptedMetricAggContexts.InitScript.CONTEXT); initScriptParams = initScript.getParams(); } else { - executableInitScript = p -> null; + compiledInitScript = (p, a) -> null; initScriptParams = Collections.emptyMap(); } - SearchScript.Factory searchMapScript = queryShardContext.getScriptService().compile(mapScript, SearchScript.AGGS_CONTEXT); + ScriptedMetricAggContexts.MapScript.Factory compiledMapScript = queryShardContext.getScriptService().compile(mapScript, + ScriptedMetricAggContexts.MapScript.CONTEXT); Map mapScriptParams = mapScript.getParams(); - ExecutableScript.Factory executableCombineScript; + ScriptedMetricAggContexts.CombineScript.Factory compiledCombineScript; Map combineScriptParams; if (combineScript != null) { - executableCombineScript = queryShardContext.getScriptService().compile(combineScript, ExecutableScript.AGGS_CONTEXT); + compiledCombineScript = queryShardContext.getScriptService().compile(combineScript, + ScriptedMetricAggContexts.CombineScript.CONTEXT); combineScriptParams = combineScript.getParams(); } else { - executableCombineScript = p -> null; + compiledCombineScript = (p, a) -> null; combineScriptParams = Collections.emptyMap(); } - return new ScriptedMetricAggregatorFactory(name, searchMapScript, mapScriptParams, executableInitScript, initScriptParams, - executableCombineScript, combineScriptParams, reduceScript, + return new ScriptedMetricAggregatorFactory(name, compiledMapScript, mapScriptParams, compiledInitScript, + initScriptParams, compiledCombineScript, combineScriptParams, reduceScript, params, queryShardContext.lookup(), context, parent, subfactoriesBuilder, metaData); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java index d6e861a9a6792..ffdff44b783b6 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java @@ -20,10 +20,10 @@ package org.elasticsearch.search.aggregations.metrics.scripted; import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.Scorer; import org.elasticsearch.common.util.CollectionUtils; -import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.ScriptedMetricAggContexts; import org.elasticsearch.script.Script; -import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.LeafBucketCollector; @@ -38,17 +38,17 @@ public class ScriptedMetricAggregator extends MetricsAggregator { - private final SearchScript.LeafFactory mapScript; - private final ExecutableScript combineScript; + private final ScriptedMetricAggContexts.MapScript.LeafFactory mapScript; + private final ScriptedMetricAggContexts.CombineScript combineScript; private final Script reduceScript; - private Map params; + private Object aggState; - protected ScriptedMetricAggregator(String name, SearchScript.LeafFactory mapScript, ExecutableScript combineScript, - Script reduceScript, - Map params, SearchContext context, Aggregator parent, List pipelineAggregators, Map metaData) - throws IOException { + protected ScriptedMetricAggregator(String name, ScriptedMetricAggContexts.MapScript.LeafFactory mapScript, ScriptedMetricAggContexts.CombineScript combineScript, + Script reduceScript, Object aggState, SearchContext context, Aggregator parent, + List pipelineAggregators, Map metaData) + throws IOException { super(name, context, parent, pipelineAggregators, metaData); - this.params = params; + this.aggState = aggState; this.mapScript = mapScript; this.combineScript = combineScript; this.reduceScript = reduceScript; @@ -62,14 +62,20 @@ public boolean needsScores() { @Override public LeafBucketCollector getLeafCollector(LeafReaderContext ctx, final LeafBucketCollector sub) throws IOException { - final SearchScript leafMapScript = mapScript.newInstance(ctx); + final ScriptedMetricAggContexts.MapScript leafMapScript = mapScript.newInstance(ctx); return new LeafBucketCollectorBase(sub, leafMapScript) { + @Override + public void setScorer(Scorer scorer) throws IOException { + leafMapScript.setScorer(scorer); + } + @Override public void collect(int doc, long bucket) throws IOException { assert bucket == 0 : bucket; + leafMapScript.setDocument(doc); - leafMapScript.run(); - CollectionUtils.ensureNoSelfReferences(params, "Scripted metric aggs map script"); + leafMapScript.execute(); + CollectionUtils.ensureNoSelfReferences(aggState, "Scripted metric aggs map script"); } }; } @@ -78,10 +84,10 @@ public void collect(int doc, long bucket) throws IOException { public InternalAggregation buildAggregation(long owningBucketOrdinal) { Object aggregation; if (combineScript != null) { - aggregation = combineScript.run(); + aggregation = combineScript.execute(); CollectionUtils.ensureNoSelfReferences(aggregation, "Scripted metric aggs combine script"); } else { - aggregation = params.get("_agg"); + aggregation = aggState; } return new InternalScriptedMetric(name, aggregation, reduceScript, pipelineAggregators(), metaData()); diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java index 0deda32e79d77..9bd904a07013d 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorFactory.java @@ -19,10 +19,9 @@ package org.elasticsearch.search.aggregations.metrics.scripted; +import org.elasticsearch.script.ScriptedMetricAggContexts; import org.elasticsearch.common.util.CollectionUtils; -import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; -import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.SearchParseException; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; @@ -39,20 +38,21 @@ public class ScriptedMetricAggregatorFactory extends AggregatorFactory { - private final SearchScript.Factory mapScript; + private final ScriptedMetricAggContexts.MapScript.Factory mapScript; private final Map mapScriptParams; - private final ExecutableScript.Factory combineScript; + private final ScriptedMetricAggContexts.CombineScript.Factory combineScript; private final Map combineScriptParams; private final Script reduceScript; private final Map aggParams; private final SearchLookup lookup; - private final ExecutableScript.Factory initScript; + private final ScriptedMetricAggContexts.InitScript.Factory initScript; private final Map initScriptParams; - public ScriptedMetricAggregatorFactory(String name, SearchScript.Factory mapScript, Map mapScriptParams, - ExecutableScript.Factory initScript, Map initScriptParams, - ExecutableScript.Factory combineScript, Map combineScriptParams, - Script reduceScript, Map aggParams, + public ScriptedMetricAggregatorFactory(String name, + ScriptedMetricAggContexts.MapScript.Factory mapScript, Map mapScriptParams, + ScriptedMetricAggContexts.InitScript.Factory initScript, Map initScriptParams, + ScriptedMetricAggContexts.CombineScript.Factory combineScript, + Map combineScriptParams, Script reduceScript, Map aggParams, SearchLookup lookup, SearchContext context, AggregatorFactory parent, AggregatorFactories.Builder subFactories, Map metaData) throws IOException { super(name, context, parent, subFactories, metaData); @@ -79,21 +79,29 @@ public Aggregator createInternal(Aggregator parent, boolean collectsFromSingleBu } else { aggParams = new HashMap<>(); } + + // Add _agg to params map for backwards compatibility (redundant with context variables on the scripts created below). + // When this is removed, aggState (as passed to ScriptedMetricAggregator) can be changed to Map, since + // it won't be possible to completely replace it with another type as is possible when it's an entry in params. if (aggParams.containsKey("_agg") == false) { aggParams.put("_agg", new HashMap()); } + Object aggState = aggParams.get("_agg"); - final ExecutableScript initScript = this.initScript.newInstance(mergeParams(aggParams, initScriptParams)); - final SearchScript.LeafFactory mapScript = this.mapScript.newFactory(mergeParams(aggParams, mapScriptParams), lookup); - final ExecutableScript combineScript = this.combineScript.newInstance(mergeParams(aggParams, combineScriptParams)); + final ScriptedMetricAggContexts.InitScript initScript = this.initScript.newInstance( + mergeParams(aggParams, initScriptParams), aggState); + final ScriptedMetricAggContexts.MapScript.LeafFactory mapScript = this.mapScript.newFactory( + mergeParams(aggParams, mapScriptParams), aggState, lookup); + final ScriptedMetricAggContexts.CombineScript combineScript = this.combineScript.newInstance( + mergeParams(aggParams, combineScriptParams), aggState); final Script reduceScript = deepCopyScript(this.reduceScript, context); if (initScript != null) { - initScript.run(); - CollectionUtils.ensureNoSelfReferences(aggParams.get("_agg"), "Scripted metric aggs init script"); + initScript.execute(); + CollectionUtils.ensureNoSelfReferences(aggState, "Scripted metric aggs init script"); } return new ScriptedMetricAggregator(name, mapScript, - combineScript, reduceScript, aggParams, context, parent, + combineScript, reduceScript, aggState, context, parent, pipelineAggregators, metaData); } diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/ScriptedMetricIT.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/ScriptedMetricIT.java index 816c0464d95d9..13e1489795996 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/ScriptedMetricIT.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/ScriptedMetricIT.java @@ -193,14 +193,55 @@ protected Map, Object>> pluginScripts() { return newAggregation; }); + scripts.put("state.items = new ArrayList()", vars -> + aggContextScript(vars, state -> ((HashMap) state).put("items", new ArrayList()))); + + scripts.put("state.items.add(1)", vars -> + aggContextScript(vars, state -> { + HashMap stateMap = (HashMap) state; + List items = (List) stateMap.get("items"); + items.add(1); + })); + + scripts.put("sum context state values", vars -> { + int sum = 0; + HashMap state = (HashMap) vars.get("state"); + List items = (List) state.get("items"); + + for (Object x : items) { + sum += (Integer)x; + } + + return sum; + }); + + scripts.put("sum context states", vars -> { + Integer sum = 0; + + List states = (List) vars.get("states"); + for (Object state : states) { + sum += ((Number) state).intValue(); + } + + return sum; + }); + return scripts; } - @SuppressWarnings("unchecked") static Object aggScript(Map vars, Consumer fn) { - T agg = (T) vars.get("_agg"); - fn.accept(agg); - return agg; + return aggScript(vars, fn, "_agg"); + } + + static Object aggContextScript(Map vars, Consumer fn) { + return aggScript(vars, fn, "state"); + } + + @SuppressWarnings("unchecked") + private static Object aggScript(Map vars, Consumer fn, String stateVarName) { + T aggState = (T) vars.get(stateVarName); + fn.accept(aggState); + return aggState; } } @@ -1015,4 +1056,37 @@ public void testConflictingAggAndScriptParams() { SearchPhaseExecutionException ex = expectThrows(SearchPhaseExecutionException.class, builder::get); assertThat(ex.getCause().getMessage(), containsString("Parameter name \"param1\" used in both aggregation and script parameters")); } + + public void testAggFromContext() { + Script initScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "state.items = new ArrayList()", Collections.emptyMap()); + Script mapScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "state.items.add(1)", Collections.emptyMap()); + Script combineScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "sum context state values", Collections.emptyMap()); + Script reduceScript = + new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "sum context states", + Collections.emptyMap()); + + SearchResponse response = client() + .prepareSearch("idx") + .setQuery(matchAllQuery()) + .addAggregation( + scriptedMetric("scripted") + .initScript(initScript) + .mapScript(mapScript) + .combineScript(combineScript) + .reduceScript(reduceScript)) + .get(); + + Aggregation aggregation = response.getAggregations().get("scripted"); + assertThat(aggregation, notNullValue()); + assertThat(aggregation, instanceOf(ScriptedMetric.class)); + + ScriptedMetric scriptedMetricAggregation = (ScriptedMetric) aggregation; + assertThat(scriptedMetricAggregation.getName(), equalTo("scripted")); + assertThat(scriptedMetricAggregation.aggregation(), notNullValue()); + + assertThat(scriptedMetricAggregation.aggregation(), instanceOf(Integer.class)); + Integer aggResult = (Integer) scriptedMetricAggregation.aggregation(); + long totalAgg = aggResult.longValue(); + assertThat(totalAgg, equalTo(numDocs)); + } } diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorTests.java index 7a7c66d21aada..b2a949ceeee1a 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregatorTests.java @@ -31,7 +31,6 @@ import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.script.MockScriptEngine; -import org.elasticsearch.script.ScoreAccessor; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptModule; @@ -107,7 +106,7 @@ public static void initMockScripts() { }); SCRIPTS.put("mapScriptScore", params -> { Map agg = (Map) params.get("_agg"); - ((List) agg.get("collector")).add(((ScoreAccessor) params.get("_score")).doubleValue()); + ((List) agg.get("collector")).add(((Number) params.get("_score")).doubleValue()); return agg; }); SCRIPTS.put("combineScriptScore", params -> { diff --git a/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java b/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java index b86cb9ff29352..e608bd13d2559 100644 --- a/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java +++ b/test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Function; @@ -115,6 +116,18 @@ public String execute() { } else if (context.instanceClazz.equals(ScoreScript.class)) { ScoreScript.Factory factory = new MockScoreScript(script); return context.factoryClazz.cast(factory); + } else if (context.instanceClazz.equals(ScriptedMetricAggContexts.InitScript.class)) { + ScriptedMetricAggContexts.InitScript.Factory factory = mockCompiled::createMetricAggInitScript; + return context.factoryClazz.cast(factory); + } else if (context.instanceClazz.equals(ScriptedMetricAggContexts.MapScript.class)) { + ScriptedMetricAggContexts.MapScript.Factory factory = mockCompiled::createMetricAggMapScript; + return context.factoryClazz.cast(factory); + } else if (context.instanceClazz.equals(ScriptedMetricAggContexts.CombineScript.class)) { + ScriptedMetricAggContexts.CombineScript.Factory factory = mockCompiled::createMetricAggCombineScript; + return context.factoryClazz.cast(factory); + } else if (context.instanceClazz.equals(ScriptedMetricAggContexts.ReduceScript.class)) { + ScriptedMetricAggContexts.ReduceScript.Factory factory = mockCompiled::createMetricAggReduceScript; + return context.factoryClazz.cast(factory); } throw new IllegalArgumentException("mock script engine does not know how to handle context [" + context.name + "]"); } @@ -179,6 +192,23 @@ public SimilarityWeightScript createSimilarityWeightScript() { public MovingFunctionScript createMovingFunctionScript() { return new MockMovingFunctionScript(); } + + public ScriptedMetricAggContexts.InitScript createMetricAggInitScript(Map params, Object state) { + return new MockMetricAggInitScript(params, state, script != null ? script : ctx -> 42d); + } + + public ScriptedMetricAggContexts.MapScript.LeafFactory createMetricAggMapScript(Map params, Object state, + SearchLookup lookup) { + return new MockMetricAggMapScript(params, state, lookup, script != null ? script : ctx -> 42d); + } + + public ScriptedMetricAggContexts.CombineScript createMetricAggCombineScript(Map params, Object state) { + return new MockMetricAggCombineScript(params, state, script != null ? script : ctx -> 42d); + } + + public ScriptedMetricAggContexts.ReduceScript createMetricAggReduceScript(Map params, List states) { + return new MockMetricAggReduceScript(params, states, script != null ? script : ctx -> 42d); + } } public class MockExecutableScript implements ExecutableScript { @@ -333,6 +363,108 @@ public double execute(Query query, Field field, Term term) throws IOException { } } + public static class MockMetricAggInitScript extends ScriptedMetricAggContexts.InitScript { + private final Function, Object> script; + + MockMetricAggInitScript(Map params, Object state, + Function, Object> script) { + super(params, state); + this.script = script; + } + + public void execute() { + Map map = new HashMap<>(); + + if (getParams() != null) { + map.putAll(getParams()); // TODO: remove this once scripts know to look for params under params key + map.put("params", getParams()); + } + + map.put("state", getState()); + script.apply(map); + } + } + + public static class MockMetricAggMapScript implements ScriptedMetricAggContexts.MapScript.LeafFactory { + private final Map params; + private final Object state; + private final SearchLookup lookup; + private final Function, Object> script; + + MockMetricAggMapScript(Map params, Object state, SearchLookup lookup, + Function, Object> script) { + this.params = params; + this.state = state; + this.lookup = lookup; + this.script = script; + } + + @Override + public ScriptedMetricAggContexts.MapScript newInstance(LeafReaderContext context) { + return new ScriptedMetricAggContexts.MapScript(params, state, lookup, context) { + @Override + public void execute() { + Map map = new HashMap<>(); + + if (getParams() != null) { + map.putAll(getParams()); // TODO: remove this once scripts know to look for params under params key + map.put("params", getParams()); + } + + map.put("state", getState()); + map.put("doc", getDoc()); + map.put("_score", get_score()); + + script.apply(map); + } + }; + } + } + + public static class MockMetricAggCombineScript extends ScriptedMetricAggContexts.CombineScript { + private final Function, Object> script; + + MockMetricAggCombineScript(Map params, Object state, + Function, Object> script) { + super(params, state); + this.script = script; + } + + public Object execute() { + Map map = new HashMap<>(); + + if (getParams() != null) { + map.putAll(getParams()); // TODO: remove this once scripts know to look for params under params key + map.put("params", getParams()); + } + + map.put("state", getState()); + return script.apply(map); + } + } + + public static class MockMetricAggReduceScript extends ScriptedMetricAggContexts.ReduceScript { + private final Function, Object> script; + + MockMetricAggReduceScript(Map params, List states, + Function, Object> script) { + super(params, states); + this.script = script; + } + + public Object execute() { + Map map = new HashMap<>(); + + if (getParams() != null) { + map.putAll(getParams()); // TODO: remove this once scripts know to look for params under params key + map.put("params", getParams()); + } + + map.put("states", getStates()); + return script.apply(map); + } + } + public static Script mockInlineScript(final String script) { return new Script(ScriptType.INLINE, "mock", script, emptyMap()); } @@ -343,15 +475,15 @@ public double execute(Map params, double[] values) { return MovingFunctions.unweightedAvg(values); } } - + public class MockScoreScript implements ScoreScript.Factory { - + private final Function, Object> scripts; - + MockScoreScript(Function, Object> scripts) { this.scripts = scripts; } - + @Override public ScoreScript.LeafFactory newFactory(Map params, SearchLookup lookup) { return new ScoreScript.LeafFactory() { @@ -359,7 +491,7 @@ public ScoreScript.LeafFactory newFactory(Map params, SearchLook public boolean needs_score() { return true; } - + @Override public ScoreScript newInstance(LeafReaderContext ctx) throws IOException { Scorer[] scorerHolder = new Scorer[1]; @@ -373,7 +505,7 @@ public double execute() { } return ((Number) scripts.apply(vars)).doubleValue(); } - + @Override public void setScorer(Scorer scorer) { scorerHolder[0] = scorer; From 86ab3a2d1a3bc5f4478d25cd28906915c2ec03fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 25 Jun 2018 15:59:03 +0200 Subject: [PATCH 06/23] Reduce number of raw types warnings (#31523) A first attempt to reduce the number of raw type warnings, most of the time by using the unbounded wildcard. --- .../search/NoopSearchRequestBuilder.java | 4 +- .../ingest/common/AppendProcessorTests.java | 6 +-- .../java/org/elasticsearch/action/Action.java | 2 +- .../action/bulk/BulkItemRequest.java | 6 +-- .../action/bulk/BulkProcessor.java | 10 ++--- .../action/bulk/BulkRequest.java | 22 +++++------ .../action/bulk/TransportBulkAction.java | 28 +++++++------- .../TransportBroadcastReplicationAction.java | 1 + .../common/component/AbstractComponent.java | 2 +- .../component/AbstractLifecycleComponent.java | 2 +- .../builders/GeometryCollectionBuilder.java | 11 +++--- .../geo/builders/MultiPolygonBuilder.java | 11 +++--- .../common/inject/AbstractProcessor.java | 2 +- .../elasticsearch/common/inject/Binder.java | 2 +- .../common/inject/BindingProcessor.java | 4 +- .../common/inject/spi/ElementVisitor.java | 2 +- .../settings/AbstractScopedSettings.java | 4 +- .../common/util/BigObjectArray.java | 2 +- .../plain/AtomicDoubleFieldData.java | 4 +- .../index/mapper/BinaryFieldMapper.java | 3 +- .../index/mapper/BooleanFieldMapper.java | 3 +- .../index/query/BaseTermQueryBuilder.java | 2 +- .../ingest/PipelineExecutionService.java | 4 +- .../elasticsearch/plugins/ActionPlugin.java | 4 +- .../highlight/AbstractHighlighterBuilder.java | 2 +- .../completion/context/ContextBuilder.java | 2 +- .../completion/context/ContextMapping.java | 2 +- .../completion/context/ContextMappings.java | 28 +++++++------- .../CollapsingTopDocsCollectorTests.java | 28 +++++++------- .../org/elasticsearch/action/ActionTests.java | 2 +- .../action/bulk/BulkRequestTests.java | 4 +- .../bulk/TransportBulkActionIngestTests.java | 4 +- .../BroadcastReplicationTests.java | 13 ++++--- .../AbstractTermVectorsTestCase.java | 4 +- .../client/AbstractClientHeadersTestCase.java | 6 +-- .../common/geo/BaseGeoParsingTestCase.java | 6 +-- .../AbstractShapeBuilderTestCase.java | 4 +- .../common/xcontent/BaseXContentTestCase.java | 10 ++--- .../AbstractFieldDataImplTestCase.java | 15 ++++---- .../fielddata/AbstractFieldDataTestCase.java | 2 +- .../AbstractStringFieldDataTestCase.java | 4 +- .../AggregationTestScriptsPlugin.java | 13 +++---- .../aggregations/AggregationsTests.java | 18 ++++----- .../aggregations/metrics/CardinalityIT.java | 8 ++-- .../suggest/CompletionSuggestSearchIT.java | 8 ++-- .../ContextCompletionSuggestSearchIT.java | 37 ++++++++++--------- .../CompletionSuggesterBuilderTests.java | 2 +- .../hamcrest/ElasticsearchGeoAssertions.java | 30 +++++++-------- .../bootstrap/BootstrapForTesting.java | 3 +- .../AbstractSimpleTransportTestCase.java | 8 ++-- .../xpack/core/XPackClientPlugin.java | 4 +- .../elasticsearch/xpack/core/XPackPlugin.java | 6 +-- .../core/watcher/actions/ActionFactory.java | 3 +- .../core/watcher/actions/ActionWrapper.java | 16 ++++---- .../aggregation/AggregationTestUtils.java | 4 +- .../integration/BasicDistributedJobsIT.java | 2 +- .../BatchedDocumentsIteratorTests.java | 2 +- .../AutodetectCommunicatorTests.java | 4 +- .../AutodetectProcessManagerTests.java | 6 +-- .../security/authz/AuthorizationService.java | 2 +- .../security/authz/AuthorizationUtils.java | 4 +- .../security/audit/index/AuditTrailTests.java | 4 +- .../authc/AuthenticationServiceTests.java | 19 ++++++---- .../authz/AuthorizationServiceTests.java | 4 +- .../xpack/watcher/input/InputRegistry.java | 6 +-- .../watcher/actions/ActionWrapperTests.java | 5 ++- .../throttler/ActionThrottleTests.java | 14 +++---- 67 files changed, 261 insertions(+), 248 deletions(-) diff --git a/client/client-benchmark-noop-api-plugin/src/main/java/org/elasticsearch/plugin/noop/action/search/NoopSearchRequestBuilder.java b/client/client-benchmark-noop-api-plugin/src/main/java/org/elasticsearch/plugin/noop/action/search/NoopSearchRequestBuilder.java index e73edb143e0d0..e66ef6208a6cf 100644 --- a/client/client-benchmark-noop-api-plugin/src/main/java/org/elasticsearch/plugin/noop/action/search/NoopSearchRequestBuilder.java +++ b/client/client-benchmark-noop-api-plugin/src/main/java/org/elasticsearch/plugin/noop/action/search/NoopSearchRequestBuilder.java @@ -329,7 +329,7 @@ public NoopSearchRequestBuilder addSort(String field, SortOrder order) { * * @see org.elasticsearch.search.sort.SortBuilders */ - public NoopSearchRequestBuilder addSort(SortBuilder sort) { + public NoopSearchRequestBuilder addSort(SortBuilder sort) { sourceBuilder().sort(sort); return this; } @@ -415,7 +415,7 @@ public NoopSearchRequestBuilder setRescorer(RescorerBuilder rescorer) { * @param window rescore window * @return this for chaining */ - public NoopSearchRequestBuilder setRescorer(RescorerBuilder rescorer, int window) { + public NoopSearchRequestBuilder setRescorer(RescorerBuilder rescorer, int window) { sourceBuilder().clearRescorers(); return addRescorer(rescorer.windowSize(window)); } diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorTests.java index 2042bb745bc1b..7a48c9ace326d 100644 --- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorTests.java +++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorTests.java @@ -91,7 +91,7 @@ public void testAppendValuesToNonExistingList() throws Exception { appendProcessor = createAppendProcessor(field, values); } appendProcessor.execute(ingestDocument); - List list = ingestDocument.getFieldValue(field, List.class); + List list = ingestDocument.getFieldValue(field, List.class); assertThat(list, not(sameInstance(values))); assertThat(list, equalTo(values)); } @@ -115,7 +115,7 @@ public void testConvertScalarToList() throws Exception { appendProcessor = createAppendProcessor(field, values); } appendProcessor.execute(ingestDocument); - List fieldValue = ingestDocument.getFieldValue(field, List.class); + List fieldValue = ingestDocument.getFieldValue(field, List.class); assertThat(fieldValue.size(), equalTo(values.size() + 1)); assertThat(fieldValue.get(0), equalTo(initialValue)); for (int i = 1; i < values.size() + 1; i++) { @@ -144,7 +144,7 @@ public void testAppendMetadataExceptVersion() throws Exception { IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random()); Object initialValue = ingestDocument.getSourceAndMetadata().get(randomMetaData.getFieldName()); appendProcessor.execute(ingestDocument); - List list = ingestDocument.getFieldValue(randomMetaData.getFieldName(), List.class); + List list = ingestDocument.getFieldValue(randomMetaData.getFieldName(), List.class); if (initialValue == null) { assertThat(list, equalTo(values)); } else { diff --git a/server/src/main/java/org/elasticsearch/action/Action.java b/server/src/main/java/org/elasticsearch/action/Action.java index 2fc49d69ed1cc..771762ad15c30 100644 --- a/server/src/main/java/org/elasticsearch/action/Action.java +++ b/server/src/main/java/org/elasticsearch/action/Action.java @@ -57,7 +57,7 @@ public TransportRequestOptions transportOptions(Settings settings) { @Override public boolean equals(Object o) { - return o instanceof Action && name.equals(((Action) o).name()); + return o instanceof Action && name.equals(((Action) o).name()); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/bulk/BulkItemRequest.java b/server/src/main/java/org/elasticsearch/action/bulk/BulkItemRequest.java index 3180f57d20409..434f87de121ed 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/BulkItemRequest.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/BulkItemRequest.java @@ -31,7 +31,7 @@ public class BulkItemRequest implements Streamable { private int id; - private DocWriteRequest request; + private DocWriteRequest request; private volatile BulkItemResponse primaryResponse; BulkItemRequest() { @@ -39,7 +39,7 @@ public class BulkItemRequest implements Streamable { } // NOTE: public for testing only - public BulkItemRequest(int id, DocWriteRequest request) { + public BulkItemRequest(int id, DocWriteRequest request) { this.id = id; this.request = request; } @@ -48,7 +48,7 @@ public int id() { return id; } - public DocWriteRequest request() { + public DocWriteRequest request() { return request; } diff --git a/server/src/main/java/org/elasticsearch/action/bulk/BulkProcessor.java b/server/src/main/java/org/elasticsearch/action/bulk/BulkProcessor.java index 9febbd63962ee..f8f9d154b14d6 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/BulkProcessor.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/BulkProcessor.java @@ -248,24 +248,24 @@ public synchronized boolean awaitClose(long timeout, TimeUnit unit) throws Inter * (for example, if no id is provided, one will be generated, or usage of the create flag). */ public BulkProcessor add(IndexRequest request) { - return add((DocWriteRequest) request); + return add((DocWriteRequest) request); } /** * Adds an {@link DeleteRequest} to the list of actions to execute. */ public BulkProcessor add(DeleteRequest request) { - return add((DocWriteRequest) request); + return add((DocWriteRequest) request); } /** * Adds either a delete or an index request. */ - public BulkProcessor add(DocWriteRequest request) { + public BulkProcessor add(DocWriteRequest request) { return add(request, null); } - public BulkProcessor add(DocWriteRequest request, @Nullable Object payload) { + public BulkProcessor add(DocWriteRequest request, @Nullable Object payload) { internalAdd(request, payload); return this; } @@ -280,7 +280,7 @@ protected void ensureOpen() { } } - private synchronized void internalAdd(DocWriteRequest request, @Nullable Object payload) { + private synchronized void internalAdd(DocWriteRequest request, @Nullable Object payload) { ensureOpen(); bulkRequest.add(request, payload); executeIfNeeded(); diff --git a/server/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java b/server/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java index ca5d997dc3882..989172b711a13 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java @@ -83,7 +83,7 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques * {@link WriteRequest}s to this but java doesn't support syntax to declare that everything in the array has both types so we declare * the one with the least casts. */ - final List requests = new ArrayList<>(); + final List> requests = new ArrayList<>(); private final Set indices = new HashSet<>(); List payloads = null; @@ -99,14 +99,14 @@ public BulkRequest() { /** * Adds a list of requests to be executed. Either index or delete requests. */ - public BulkRequest add(DocWriteRequest... requests) { - for (DocWriteRequest request : requests) { + public BulkRequest add(DocWriteRequest... requests) { + for (DocWriteRequest request : requests) { add(request, null); } return this; } - public BulkRequest add(DocWriteRequest request) { + public BulkRequest add(DocWriteRequest request) { return add(request, null); } @@ -116,7 +116,7 @@ public BulkRequest add(DocWriteRequest request) { * @param payload Optional payload * @return the current bulk request */ - public BulkRequest add(DocWriteRequest request, @Nullable Object payload) { + public BulkRequest add(DocWriteRequest request, @Nullable Object payload) { if (request instanceof IndexRequest) { add((IndexRequest) request, payload); } else if (request instanceof DeleteRequest) { @@ -133,8 +133,8 @@ public BulkRequest add(DocWriteRequest request, @Nullable Object payload) { /** * Adds a list of requests to be executed. Either index or delete requests. */ - public BulkRequest add(Iterable requests) { - for (DocWriteRequest request : requests) { + public BulkRequest add(Iterable> requests) { + for (DocWriteRequest request : requests) { add(request); } return this; @@ -223,7 +223,7 @@ private void addPayload(Object payload) { /** * The list of requests in this bulk request. */ - public List requests() { + public List> requests() { return this.requests; } @@ -527,7 +527,7 @@ private int findNextMarker(byte marker, int from, BytesReference data, int lengt * @return Whether this bulk request contains index request with an ingest pipeline enabled. */ public boolean hasIndexRequestsWithPipelines() { - for (DocWriteRequest actionRequest : requests) { + for (DocWriteRequest actionRequest : requests) { if (actionRequest instanceof IndexRequest) { IndexRequest indexRequest = (IndexRequest) actionRequest; if (Strings.hasText(indexRequest.getPipeline())) { @@ -545,7 +545,7 @@ public ActionRequestValidationException validate() { if (requests.isEmpty()) { validationException = addValidationError("no requests added", validationException); } - for (DocWriteRequest request : requests) { + for (DocWriteRequest request : requests) { // We first check if refresh has been set if (((WriteRequest) request).getRefreshPolicy() != RefreshPolicy.NONE) { validationException = addValidationError( @@ -580,7 +580,7 @@ public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); waitForActiveShards.writeTo(out); out.writeVInt(requests.size()); - for (DocWriteRequest request : requests) { + for (DocWriteRequest request : requests) { DocWriteRequest.writeDocumentRequest(out, request); } refreshPolicy.writeTo(out); diff --git a/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java b/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java index 247970dafcee3..a6ed8de653007 100644 --- a/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java +++ b/server/src/main/java/org/elasticsearch/action/bulk/TransportBulkAction.java @@ -143,8 +143,8 @@ protected void doExecute(Task task, BulkRequest bulkRequest, ActionListener indices = bulkRequest.requests.stream() // delete requests should not attempt to create the index (if the index does not // exists), unless an external versioning is used - .filter(request -> request.opType() != DocWriteRequest.OpType.DELETE - || request.versionType() == VersionType.EXTERNAL + .filter(request -> request.opType() != DocWriteRequest.OpType.DELETE + || request.versionType() == VersionType.EXTERNAL || request.versionType() == VersionType.EXTERNAL_GTE) .map(DocWriteRequest::index) .collect(Collectors.toSet()); @@ -184,7 +184,7 @@ public void onFailure(Exception e) { if (!(ExceptionsHelper.unwrapCause(e) instanceof ResourceAlreadyExistsException)) { // fail all requests involving this index, if create didn't work for (int i = 0; i < bulkRequest.requests.size(); i++) { - DocWriteRequest request = bulkRequest.requests.get(i); + DocWriteRequest request = bulkRequest.requests.get(i); if (request != null && setResponseFailureIfIndexMatches(responses, i, request, index, e)) { bulkRequest.requests.set(i, null); } @@ -221,7 +221,7 @@ void createIndex(String index, TimeValue timeout, ActionListener responses, int idx, DocWriteRequest request, String index, Exception e) { + private boolean setResponseFailureIfIndexMatches(AtomicArray responses, int idx, DocWriteRequest request, String index, Exception e) { if (index.equals(request.index())) { responses.set(idx, new BulkItemResponse(idx, request.opType(), new BulkItemResponse.Failure(request.index(), request.type(), request.id(), e))); return true; @@ -271,7 +271,7 @@ protected void doRun() throws Exception { final ConcreteIndices concreteIndices = new ConcreteIndices(clusterState, indexNameExpressionResolver); MetaData metaData = clusterState.metaData(); for (int i = 0; i < bulkRequest.requests.size(); i++) { - DocWriteRequest docWriteRequest = bulkRequest.requests.get(i); + DocWriteRequest docWriteRequest = bulkRequest.requests.get(i); //the request can only be null because we set it to null in the previous step, so it gets ignored if (docWriteRequest == null) { continue; @@ -315,7 +315,7 @@ protected void doRun() throws Exception { // first, go over all the requests and create a ShardId -> Operations mapping Map> requestsByShard = new HashMap<>(); for (int i = 0; i < bulkRequest.requests.size(); i++) { - DocWriteRequest request = bulkRequest.requests.get(i); + DocWriteRequest request = bulkRequest.requests.get(i); if (request == null) { continue; } @@ -362,7 +362,7 @@ public void onFailure(Exception e) { // create failures for all relevant requests for (BulkItemRequest request : requests) { final String indexName = concreteIndices.getConcreteIndex(request.index()).getName(); - DocWriteRequest docWriteRequest = request.request(); + DocWriteRequest docWriteRequest = request.request(); responses.set(request.id(), new BulkItemResponse(request.id(), docWriteRequest.opType(), new BulkItemResponse.Failure(indexName, docWriteRequest.type(), docWriteRequest.id(), e))); } @@ -418,7 +418,7 @@ public void onTimeout(TimeValue timeout) { }); } - private boolean addFailureIfIndexIsUnavailable(DocWriteRequest request, int idx, final ConcreteIndices concreteIndices, + private boolean addFailureIfIndexIsUnavailable(DocWriteRequest request, int idx, final ConcreteIndices concreteIndices, final MetaData metaData) { IndexNotFoundException cannotCreate = indicesThatCannotBeCreated.get(request.index()); if (cannotCreate != null) { @@ -442,7 +442,7 @@ private boolean addFailureIfIndexIsUnavailable(DocWriteRequest request, int idx, return false; } - private void addFailure(DocWriteRequest request, int idx, Exception unavailableException) { + private void addFailure(DocWriteRequest request, int idx, Exception unavailableException) { BulkItemResponse.Failure failure = new BulkItemResponse.Failure(request.index(), request.type(), request.id(), unavailableException); BulkItemResponse bulkItemResponse = new BulkItemResponse(idx, request.opType(), failure); @@ -471,7 +471,7 @@ Index getConcreteIndex(String indexOrAlias) { return indices.get(indexOrAlias); } - Index resolveIfAbsent(DocWriteRequest request) { + Index resolveIfAbsent(DocWriteRequest request) { Index concreteIndex = indices.get(request.index()); if (concreteIndex == null) { concreteIndex = indexNameExpressionResolver.concreteSingleIndex(state, request); @@ -512,7 +512,7 @@ void processBulkIndexIngestRequest(Task task, BulkRequest original, ActionListen }); } - static final class BulkRequestModifier implements Iterator { + static final class BulkRequestModifier implements Iterator> { final BulkRequest bulkRequest; final SparseFixedBitSet failedSlots; @@ -528,7 +528,7 @@ static final class BulkRequestModifier implements Iterator { } @Override - public DocWriteRequest next() { + public DocWriteRequest next() { return bulkRequest.requests().get(++currentSlot); } @@ -547,10 +547,10 @@ BulkRequest getBulkRequest() { modifiedBulkRequest.timeout(bulkRequest.timeout()); int slot = 0; - List requests = bulkRequest.requests(); + List> requests = bulkRequest.requests(); originalSlots = new int[requests.size()]; // oversize, but that's ok for (int i = 0; i < requests.size(); i++) { - DocWriteRequest request = requests.get(i); + DocWriteRequest request = requests.get(i); if (failedSlots.get(i) == false) { modifiedBulkRequest.add(request); originalSlots[slot++] = i; diff --git a/server/src/main/java/org/elasticsearch/action/support/replication/TransportBroadcastReplicationAction.java b/server/src/main/java/org/elasticsearch/action/support/replication/TransportBroadcastReplicationAction.java index aa3784efdd04f..1adfdbca8786b 100644 --- a/server/src/main/java/org/elasticsearch/action/support/replication/TransportBroadcastReplicationAction.java +++ b/server/src/main/java/org/elasticsearch/action/support/replication/TransportBroadcastReplicationAction.java @@ -20,6 +20,7 @@ package org.elasticsearch.action.support.replication; import com.carrotsearch.hppc.cursors.IntObjectCursor; + import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; diff --git a/server/src/main/java/org/elasticsearch/common/component/AbstractComponent.java b/server/src/main/java/org/elasticsearch/common/component/AbstractComponent.java index 8cb51f2b06b0e..62d6e7e311d5d 100644 --- a/server/src/main/java/org/elasticsearch/common/component/AbstractComponent.java +++ b/server/src/main/java/org/elasticsearch/common/component/AbstractComponent.java @@ -39,7 +39,7 @@ public AbstractComponent(Settings settings) { this.settings = settings; } - public AbstractComponent(Settings settings, Class customClass) { + public AbstractComponent(Settings settings, Class customClass) { this.logger = LogManager.getLogger(customClass); this.deprecationLogger = new DeprecationLogger(logger); this.settings = settings; diff --git a/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java b/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java index 2ed43ccaa24e6..de14e0cd53db6 100644 --- a/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java +++ b/server/src/main/java/org/elasticsearch/common/component/AbstractLifecycleComponent.java @@ -35,7 +35,7 @@ protected AbstractLifecycleComponent(Settings settings) { super(settings); } - protected AbstractLifecycleComponent(Settings settings, Class customClass) { + protected AbstractLifecycleComponent(Settings settings, Class customClass) { super(settings, customClass); } diff --git a/server/src/main/java/org/elasticsearch/common/geo/builders/GeometryCollectionBuilder.java b/server/src/main/java/org/elasticsearch/common/geo/builders/GeometryCollectionBuilder.java index b9c23842a5a8c..d2ff86ea63ced 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/builders/GeometryCollectionBuilder.java +++ b/server/src/main/java/org/elasticsearch/common/geo/builders/GeometryCollectionBuilder.java @@ -19,23 +19,22 @@ package org.elasticsearch.common.geo.builders; -import org.elasticsearch.common.geo.GeoShapeType; -import org.elasticsearch.common.geo.parsers.ShapeParser; -import org.elasticsearch.common.geo.parsers.GeoWKTParser; -import org.locationtech.spatial4j.shape.Shape; - import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.geo.GeoShapeType; import org.elasticsearch.common.geo.XShapeCollection; +import org.elasticsearch.common.geo.parsers.GeoWKTParser; +import org.elasticsearch.common.geo.parsers.ShapeParser; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.locationtech.spatial4j.shape.Shape; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; -public class GeometryCollectionBuilder extends ShapeBuilder { +public class GeometryCollectionBuilder extends ShapeBuilder { public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION; diff --git a/server/src/main/java/org/elasticsearch/common/geo/builders/MultiPolygonBuilder.java b/server/src/main/java/org/elasticsearch/common/geo/builders/MultiPolygonBuilder.java index 3d917bcff6e48..bac74c29dd805 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/builders/MultiPolygonBuilder.java +++ b/server/src/main/java/org/elasticsearch/common/geo/builders/MultiPolygonBuilder.java @@ -20,15 +20,14 @@ package org.elasticsearch.common.geo.builders; import org.elasticsearch.common.geo.GeoShapeType; -import org.elasticsearch.common.geo.parsers.ShapeParser; -import org.elasticsearch.common.geo.parsers.GeoWKTParser; -import org.locationtech.spatial4j.shape.Shape; -import org.locationtech.jts.geom.Coordinate; - import org.elasticsearch.common.geo.XShapeCollection; +import org.elasticsearch.common.geo.parsers.GeoWKTParser; +import org.elasticsearch.common.geo.parsers.ShapeParser; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.spatial4j.shape.Shape; import java.io.IOException; import java.util.ArrayList; @@ -36,7 +35,7 @@ import java.util.Locale; import java.util.Objects; -public class MultiPolygonBuilder extends ShapeBuilder { +public class MultiPolygonBuilder extends ShapeBuilder { public static final GeoShapeType TYPE = GeoShapeType.MULTIPOLYGON; diff --git a/server/src/main/java/org/elasticsearch/common/inject/AbstractProcessor.java b/server/src/main/java/org/elasticsearch/common/inject/AbstractProcessor.java index 8b501a561292e..30b799601487f 100644 --- a/server/src/main/java/org/elasticsearch/common/inject/AbstractProcessor.java +++ b/server/src/main/java/org/elasticsearch/common/inject/AbstractProcessor.java @@ -85,7 +85,7 @@ public Boolean visit(ScopeBinding scopeBinding) { } @Override - public Boolean visit(InjectionRequest injectionRequest) { + public Boolean visit(InjectionRequest injectionRequest) { return false; } diff --git a/server/src/main/java/org/elasticsearch/common/inject/Binder.java b/server/src/main/java/org/elasticsearch/common/inject/Binder.java index 2a4799cefccb1..03d164bcbaa52 100644 --- a/server/src/main/java/org/elasticsearch/common/inject/Binder.java +++ b/server/src/main/java/org/elasticsearch/common/inject/Binder.java @@ -360,7 +360,7 @@ void bindListener(Matcher> typeMatcher, * @return a binder that shares its configuration with this binder. * @since 2.0 */ - Binder skipSources(Class... classesToSkip); + Binder skipSources(Class... classesToSkip); /** * Creates a new private child environment for bindings and other configuration. The returned diff --git a/server/src/main/java/org/elasticsearch/common/inject/BindingProcessor.java b/server/src/main/java/org/elasticsearch/common/inject/BindingProcessor.java index e560eeb1efd63..971b100a6799e 100644 --- a/server/src/main/java/org/elasticsearch/common/inject/BindingProcessor.java +++ b/server/src/main/java/org/elasticsearch/common/inject/BindingProcessor.java @@ -72,7 +72,7 @@ public Boolean visit(Binding command) { if (Void.class.equals(command.getKey().getRawType())) { if (command instanceof ProviderInstanceBinding - && ((ProviderInstanceBinding) command).getProviderInstance() instanceof ProviderMethod) { + && ((ProviderInstanceBinding) command).getProviderInstance() instanceof ProviderMethod) { errors.voidProviderMethod(); } else { errors.missingConstantValues(); @@ -274,7 +274,7 @@ private void putBinding(BindingImpl binding) { */ private boolean isOkayDuplicate(Binding original, BindingImpl binding) { if (original instanceof ExposedBindingImpl) { - ExposedBindingImpl exposed = (ExposedBindingImpl) original; + ExposedBindingImpl exposed = (ExposedBindingImpl) original; InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector(); return (exposedFrom == binding.getInjector()); } diff --git a/server/src/main/java/org/elasticsearch/common/inject/spi/ElementVisitor.java b/server/src/main/java/org/elasticsearch/common/inject/spi/ElementVisitor.java index 6711456004380..8440ab98b5cb8 100644 --- a/server/src/main/java/org/elasticsearch/common/inject/spi/ElementVisitor.java +++ b/server/src/main/java/org/elasticsearch/common/inject/spi/ElementVisitor.java @@ -46,7 +46,7 @@ public interface ElementVisitor { /** * Visit a request to inject the instance fields and methods of an instance. */ - V visit(InjectionRequest request); + V visit(InjectionRequest request); /** * Visit a request to inject the static fields and methods of type. diff --git a/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java b/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java index eb4e294642417..8847c8138a706 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java +++ b/server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java @@ -83,7 +83,7 @@ protected AbstractScopedSettings(Settings settings, Set> settingsSet, this.keySettings = Collections.unmodifiableMap(keySettings); } - protected void validateSettingKey(Setting setting) { + protected void validateSettingKey(Setting setting) { if (isValidKey(setting.getKey()) == false && (setting.isGroupSetting() && isValidGroupKey(setting.getKey()) || isValidAffixKey(setting.getKey())) == false || setting.getKey().endsWith(".0")) { throw new IllegalArgumentException("illegal settings key: [" + setting.getKey() + "]"); @@ -366,7 +366,7 @@ void validate(final String key, final Settings settings, final boolean validateD * @throws IllegalArgumentException if the setting is invalid */ void validate(final String key, final Settings settings, final boolean validateDependencies, final boolean validateInternalIndex) { - Setting setting = getRaw(key); + Setting setting = getRaw(key); if (setting == null) { LevensteinDistance ld = new LevensteinDistance(); List> scoredKeys = new ArrayList<>(); diff --git a/server/src/main/java/org/elasticsearch/common/util/BigObjectArray.java b/server/src/main/java/org/elasticsearch/common/util/BigObjectArray.java index 1ed012e2bb393..77ac63a984f55 100644 --- a/server/src/main/java/org/elasticsearch/common/util/BigObjectArray.java +++ b/server/src/main/java/org/elasticsearch/common/util/BigObjectArray.java @@ -32,7 +32,7 @@ */ final class BigObjectArray extends AbstractBigArray implements ObjectArray { - private static final BigObjectArray ESTIMATOR = new BigObjectArray(0, BigArrays.NON_RECYCLING_INSTANCE); + private static final BigObjectArray ESTIMATOR = new BigObjectArray(0, BigArrays.NON_RECYCLING_INSTANCE); private Object[][] pages; diff --git a/server/src/main/java/org/elasticsearch/index/fielddata/plain/AtomicDoubleFieldData.java b/server/src/main/java/org/elasticsearch/index/fielddata/plain/AtomicDoubleFieldData.java index 82ae0bb5bf1ea..6fd08b82668f6 100644 --- a/server/src/main/java/org/elasticsearch/index/fielddata/plain/AtomicDoubleFieldData.java +++ b/server/src/main/java/org/elasticsearch/index/fielddata/plain/AtomicDoubleFieldData.java @@ -48,7 +48,7 @@ public long ramBytesUsed() { } @Override - public final ScriptDocValues getScriptValues() { + public final ScriptDocValues getScriptValues() { return new ScriptDocValues.Doubles(getDoubleValues()); } @@ -69,7 +69,7 @@ public static AtomicNumericFieldData empty(final int maxDoc) { public SortedNumericDoubleValues getDoubleValues() { return FieldData.emptySortedNumericDoubles(); } - + @Override public Collection getChildResources() { return Collections.emptyList(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java index e19bdb6708370..69b6a6e04a936 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BinaryFieldMapper.java @@ -80,7 +80,8 @@ public BinaryFieldMapper build(BuilderContext context) { public static class TypeParser implements Mapper.TypeParser { @Override - public Mapper.Builder parse(String name, Map node, ParserContext parserContext) throws MapperParsingException { + public BinaryFieldMapper.Builder parse(String name, Map node, ParserContext parserContext) + throws MapperParsingException { BinaryFieldMapper.Builder builder = new BinaryFieldMapper.Builder(name); parseField(builder, name, node, parserContext); return builder; diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java index c50a7d18113bf..cb44e777f871d 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java @@ -94,7 +94,8 @@ public BooleanFieldMapper build(BuilderContext context) { public static class TypeParser implements Mapper.TypeParser { @Override - public Mapper.Builder parse(String name, Map node, ParserContext parserContext) throws MapperParsingException { + public BooleanFieldMapper.Builder parse(String name, Map node, ParserContext parserContext) + throws MapperParsingException { BooleanFieldMapper.Builder builder = new BooleanFieldMapper.Builder(name); parseField(builder, name, node, parserContext); for (Iterator> iterator = node.entrySet().iterator(); iterator.hasNext();) { diff --git a/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java index a3ef36204f032..f06ee48d06b67 100644 --- a/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java @@ -163,7 +163,7 @@ protected final int doHashCode() { } @Override - protected final boolean doEquals(BaseTermQueryBuilder other) { + protected final boolean doEquals(QB other) { return Objects.equals(fieldName, other.fieldName) && Objects.equals(value, other.value); } diff --git a/server/src/main/java/org/elasticsearch/ingest/PipelineExecutionService.java b/server/src/main/java/org/elasticsearch/ingest/PipelineExecutionService.java index f1062f7b5384c..a8aca4fdfe59d 100644 --- a/server/src/main/java/org/elasticsearch/ingest/PipelineExecutionService.java +++ b/server/src/main/java/org/elasticsearch/ingest/PipelineExecutionService.java @@ -53,7 +53,7 @@ public PipelineExecutionService(PipelineStore store, ThreadPool threadPool) { this.threadPool = threadPool; } - public void executeBulkRequest(Iterable actionRequests, + public void executeBulkRequest(Iterable> actionRequests, BiConsumer itemFailureHandler, Consumer completionHandler) { threadPool.executor(ThreadPool.Names.WRITE).execute(new AbstractRunnable() { @@ -65,7 +65,7 @@ public void onFailure(Exception e) { @Override protected void doRun() throws Exception { - for (DocWriteRequest actionRequest : actionRequests) { + for (DocWriteRequest actionRequest : actionRequests) { IndexRequest indexRequest = null; if (actionRequest instanceof IndexRequest) { indexRequest = (IndexRequest) actionRequest; diff --git a/server/src/main/java/org/elasticsearch/plugins/ActionPlugin.java b/server/src/main/java/org/elasticsearch/plugins/ActionPlugin.java index eb8b7130d7054..54d9ade581e89 100644 --- a/server/src/main/java/org/elasticsearch/plugins/ActionPlugin.java +++ b/server/src/main/java/org/elasticsearch/plugins/ActionPlugin.java @@ -19,9 +19,9 @@ package org.elasticsearch.plugins; +import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; -import org.elasticsearch.action.Action; import org.elasticsearch.action.support.ActionFilter; import org.elasticsearch.action.support.TransportAction; import org.elasticsearch.action.support.TransportActions; @@ -68,7 +68,7 @@ public interface ActionPlugin { * Client actions added by this plugin. This defaults to all of the {@linkplain Action} in * {@linkplain ActionPlugin#getActions()}. */ - default List getClientActions() { + default List> getClientActions() { return getActions().stream().map(a -> a.action).collect(Collectors.toList()); } diff --git a/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java b/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java index e59bd718d3226..7888f6cd5a098 100644 --- a/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java @@ -115,7 +115,7 @@ public abstract class AbstractHighlighterBuilder template, QueryBuilder queryBuilder) { preTags = template.preTags; postTags = template.postTags; fragmentSize = template.fragmentSize; diff --git a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextBuilder.java b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextBuilder.java index 9e31d8370cbe3..b6713f81ec48c 100644 --- a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextBuilder.java @@ -22,7 +22,7 @@ /** * Builder for {@link ContextMapping} */ -public abstract class ContextBuilder { +public abstract class ContextBuilder> { protected String name; diff --git a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java index 7eab4e072f146..1aa82eeb2190a 100644 --- a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java +++ b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java @@ -143,7 +143,7 @@ public final XContentBuilder toXContent(XContentBuilder builder, Params params) public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - ContextMapping that = (ContextMapping) o; + ContextMapping that = (ContextMapping) o; if (type != that.type) return false; return name.equals(that.name); } diff --git a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMappings.java b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMappings.java index 4d6b53296f157..961d7fd9f59a7 100644 --- a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMappings.java +++ b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMappings.java @@ -57,10 +57,10 @@ public class ContextMappings implements ToXContent { private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(Loggers.getLogger(ContextMappings.class)); - private final List contextMappings; - private final Map contextNameMap; + private final List> contextMappings; + private final Map> contextNameMap; - public ContextMappings(List contextMappings) { + public ContextMappings(List> contextMappings) { if (contextMappings.size() > 255) { // we can support more, but max of 255 (1 byte) unique context types per suggest field // seems reasonable? @@ -68,7 +68,7 @@ public ContextMappings(List contextMappings) { } this.contextMappings = contextMappings; contextNameMap = new HashMap<>(contextMappings.size()); - for (ContextMapping mapping : contextMappings) { + for (ContextMapping mapping : contextMappings) { contextNameMap.put(mapping.name(), mapping); } } @@ -84,8 +84,8 @@ public int size() { /** * Returns a context mapping by its name */ - public ContextMapping get(String name) { - ContextMapping contextMapping = contextNameMap.get(name); + public ContextMapping get(String name) { + ContextMapping contextMapping = contextNameMap.get(name); if (contextMapping == null) { List keys = new ArrayList<>(contextNameMap.keySet()); Collections.sort(keys); @@ -138,7 +138,7 @@ protected Iterable contexts() { for (int typeId = 0; typeId < contextMappings.size(); typeId++) { scratch.setCharAt(0, (char) typeId); scratch.setLength(1); - ContextMapping mapping = contextMappings.get(typeId); + ContextMapping mapping = contextMappings.get(typeId); Set contexts = new HashSet<>(mapping.parseContext(document)); if (this.contexts.get(mapping.name()) != null) { contexts.addAll(this.contexts.get(mapping.name())); @@ -173,7 +173,7 @@ public ContextQuery toContextQuery(CompletionQuery query, Map mapping = contextMappings.get(typeId); List internalQueryContext = queryContexts.get(mapping.name()); if (internalQueryContext != null) { for (ContextMapping.InternalQueryContext context : internalQueryContext) { @@ -204,7 +204,7 @@ public Map> getNamedContexts(List contex for (CharSequence typedContext : contexts) { int typeId = typedContext.charAt(0); assert typeId < contextMappings.size() : "Returned context has invalid type"; - ContextMapping mapping = contextMappings.get(typeId); + ContextMapping mapping = contextMappings.get(typeId); Set contextEntries = contextMap.get(mapping.name()); if (contextEntries == null) { contextEntries = new HashSet<>(); @@ -224,10 +224,10 @@ public Map> getNamedContexts(List contex * */ public static ContextMappings load(Object configuration, Version indexVersionCreated) throws ElasticsearchParseException { - final List contextMappings; + final List> contextMappings; if (configuration instanceof List) { contextMappings = new ArrayList<>(); - List configurations = (List)configuration; + List configurations = (List) configuration; for (Object contextConfig : configurations) { contextMappings.add(load((Map) contextConfig, indexVersionCreated)); } @@ -242,10 +242,10 @@ public static ContextMappings load(Object configuration, Version indexVersionCre return new ContextMappings(contextMappings); } - private static ContextMapping load(Map contextConfig, Version indexVersionCreated) { + private static ContextMapping load(Map contextConfig, Version indexVersionCreated) { String name = extractRequiredValue(contextConfig, FIELD_NAME); String type = extractRequiredValue(contextConfig, FIELD_TYPE); - final ContextMapping contextMapping; + final ContextMapping contextMapping; switch (Type.fromString(type)) { case CATEGORY: contextMapping = CategoryContextMapping.load(name, contextConfig); @@ -276,7 +276,7 @@ private static String extractRequiredValue(Map contextConfig, St */ @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - for (ContextMapping contextMapping : contextMappings) { + for (ContextMapping contextMapping : contextMappings) { builder.startObject(); contextMapping.toXContent(builder, params); builder.endObject(); diff --git a/server/src/test/java/org/apache/lucene/grouping/CollapsingTopDocsCollectorTests.java b/server/src/test/java/org/apache/lucene/grouping/CollapsingTopDocsCollectorTests.java index 0290a6c5d100b..bce5965e50b6b 100644 --- a/server/src/test/java/org/apache/lucene/grouping/CollapsingTopDocsCollectorTests.java +++ b/server/src/test/java/org/apache/lucene/grouping/CollapsingTopDocsCollectorTests.java @@ -75,7 +75,7 @@ public String toString() { } } - interface CollapsingDocValuesProducer { + interface CollapsingDocValuesProducer> { T randomGroup(int maxGroup); void add(Document doc, T value, boolean multivalued); @@ -83,14 +83,14 @@ interface CollapsingDocValuesProducer { SortField sortField(boolean multivalued); } - void assertSearchCollapse(CollapsingDocValuesProducer dvProducers, boolean numeric) throws IOException { + > void assertSearchCollapse(CollapsingDocValuesProducer dvProducers, boolean numeric) throws IOException { assertSearchCollapse(dvProducers, numeric, true, true); assertSearchCollapse(dvProducers, numeric, true, false); assertSearchCollapse(dvProducers, numeric, false, true); assertSearchCollapse(dvProducers, numeric, false, false); } - private void assertSearchCollapse(CollapsingDocValuesProducer dvProducers, + private > void assertSearchCollapse(CollapsingDocValuesProducer dvProducers, boolean numeric, boolean multivalued, boolean trackMaxScores) throws IOException { final int numDocs = randomIntBetween(1000, 2000); @@ -120,7 +120,7 @@ private void assertSearchCollapse(CollapsingDocValuesProd int expectedNumGroups = values.size(); - final CollapsingTopDocsCollector collapsingCollector; + final CollapsingTopDocsCollector collapsingCollector; if (numeric) { collapsingCollector = CollapsingTopDocsCollector.createNumeric(collapseField.getField(), sort, expectedNumGroups, trackMaxScores); @@ -199,7 +199,7 @@ private void assertSearchCollapse(CollapsingDocValuesProd final Weight weight = searcher.createNormalizedWeight(new MatchAllDocsQuery(), true); for (int shardIDX = 0; shardIDX < subSearchers.length; shardIDX++) { final SegmentSearcher subSearcher = subSearchers[shardIDX]; - final CollapsingTopDocsCollector c; + final CollapsingTopDocsCollector c; if (numeric) { c = CollapsingTopDocsCollector.createNumeric(collapseField.getField(), sort, expectedNumGroups, trackMaxScores); } else { @@ -221,7 +221,7 @@ private static void assertTopDocsEquals(CollapseTopFieldDocs topDocs1, CollapseT } public void testCollapseLong() throws Exception { - CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { + CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { @Override public Long randomGroup(int maxGroup) { return randomNonNegativeLong() % maxGroup; @@ -249,7 +249,7 @@ public SortField sortField(boolean multivalued) { } public void testCollapseInt() throws Exception { - CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { + CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { @Override public Integer randomGroup(int maxGroup) { return randomIntBetween(0, maxGroup - 1); @@ -277,10 +277,10 @@ public SortField sortField(boolean multivalued) { } public void testCollapseFloat() throws Exception { - CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { + CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { @Override public Float randomGroup(int maxGroup) { - return new Float(randomIntBetween(0, maxGroup - 1)); + return Float.valueOf(randomIntBetween(0, maxGroup - 1)); } @Override @@ -305,10 +305,10 @@ public SortField sortField(boolean multivalued) { } public void testCollapseDouble() throws Exception { - CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { + CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { @Override public Double randomGroup(int maxGroup) { - return new Double(randomIntBetween(0, maxGroup - 1)); + return Double.valueOf(randomIntBetween(0, maxGroup - 1)); } @Override @@ -333,7 +333,7 @@ public SortField sortField(boolean multivalued) { } public void testCollapseString() throws Exception { - CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { + CollapsingDocValuesProducer producer = new CollapsingDocValuesProducer() { @Override public BytesRef randomGroup(int maxGroup) { return new BytesRef(Integer.toString(randomIntBetween(0, maxGroup - 1))); @@ -383,7 +383,7 @@ public void testEmptyNumericSegment() throws Exception { SortField sortField = new SortField("group", SortField.Type.LONG); sortField.setMissingValue(Long.MAX_VALUE); Sort sort = new Sort(sortField); - final CollapsingTopDocsCollector collapsingCollector = + final CollapsingTopDocsCollector collapsingCollector = CollapsingTopDocsCollector.createNumeric("group", sort, 10, false); searcher.search(new MatchAllDocsQuery(), collapsingCollector); CollapseTopFieldDocs collapseTopFieldDocs = collapsingCollector.getTopDocs(); @@ -419,7 +419,7 @@ public void testEmptySortedSegment() throws Exception { final IndexReader reader = w.getReader(); final IndexSearcher searcher = newSearcher(reader); Sort sort = new Sort(new SortField("group", SortField.Type.STRING_VAL)); - final CollapsingTopDocsCollector collapsingCollector = + final CollapsingTopDocsCollector collapsingCollector = CollapsingTopDocsCollector.createKeyword("group", sort, 10, false); searcher.search(new MatchAllDocsQuery(), collapsingCollector); CollapseTopFieldDocs collapseTopFieldDocs = collapsingCollector.getTopDocs(); diff --git a/server/src/test/java/org/elasticsearch/action/ActionTests.java b/server/src/test/java/org/elasticsearch/action/ActionTests.java index c159d36ca9158..a7dca3f098d05 100644 --- a/server/src/test/java/org/elasticsearch/action/ActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/ActionTests.java @@ -24,7 +24,7 @@ public class ActionTests extends ESTestCase { public void testEquals() { - class FakeAction extends Action { + class FakeAction extends Action { protected FakeAction(String name) { super(name); } diff --git a/server/src/test/java/org/elasticsearch/action/bulk/BulkRequestTests.java b/server/src/test/java/org/elasticsearch/action/bulk/BulkRequestTests.java index 1d03d065e7af7..f1842b5b0dd1d 100644 --- a/server/src/test/java/org/elasticsearch/action/bulk/BulkRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/bulk/BulkRequestTests.java @@ -124,7 +124,7 @@ public void testBulkAllowExplicitIndex() throws Exception { public void testBulkAddIterable() { BulkRequest bulkRequest = Requests.bulkRequest(); - List requests = new ArrayList<>(); + List> requests = new ArrayList<>(); requests.add(new IndexRequest("test", "test", "id").source(Requests.INDEX_CONTENT_TYPE, "field", "value")); requests.add(new UpdateRequest("test", "test", "id").doc(Requests.INDEX_CONTENT_TYPE, "field", "value")); requests.add(new DeleteRequest("test", "test", "id")); @@ -279,7 +279,7 @@ public void testSmileIsSupported() throws IOException { BulkRequest bulkRequest = new BulkRequest(); bulkRequest.add(data, null, null, xContentType); assertEquals(1, bulkRequest.requests().size()); - DocWriteRequest docWriteRequest = bulkRequest.requests().get(0); + DocWriteRequest docWriteRequest = bulkRequest.requests().get(0); assertEquals(DocWriteRequest.OpType.INDEX, docWriteRequest.opType()); assertEquals("index", docWriteRequest.index()); assertEquals("type", docWriteRequest.type()); diff --git a/server/src/test/java/org/elasticsearch/action/bulk/TransportBulkActionIngestTests.java b/server/src/test/java/org/elasticsearch/action/bulk/TransportBulkActionIngestTests.java index bcd16386df3d4..66527726573a5 100644 --- a/server/src/test/java/org/elasticsearch/action/bulk/TransportBulkActionIngestTests.java +++ b/server/src/test/java/org/elasticsearch/action/bulk/TransportBulkActionIngestTests.java @@ -84,7 +84,7 @@ public class TransportBulkActionIngestTests extends ESTestCase { @Captor ArgumentCaptor> remoteResponseHandler; @Captor - ArgumentCaptor> bulkDocsItr; + ArgumentCaptor>> bulkDocsItr; /** The actual action we want to test, with real indexing mocked */ TestTransportBulkAction action; @@ -225,7 +225,7 @@ public void testIngestLocal() throws Exception { assertTrue(failureCalled.get()); // now check success - Iterator req = bulkDocsItr.getValue().iterator(); + Iterator> req = bulkDocsItr.getValue().iterator(); failureHandler.getValue().accept((IndexRequest)req.next(), exception); // have an exception for our one index request indexRequest2.setPipeline(null); // this is done by the real pipeline execution service when processing completionHandler.getValue().accept(null); diff --git a/server/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java b/server/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java index bfa45bb072dcf..012cc71437a80 100644 --- a/server/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java +++ b/server/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java @@ -18,9 +18,6 @@ */ package org.elasticsearch.action.support.replication; -import org.elasticsearch.action.support.ActionTestUtils; -import org.elasticsearch.action.support.PlainActionFuture; -import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.NoShardAvailableActionException; import org.elasticsearch.action.UnavailableShardsException; @@ -28,7 +25,9 @@ import org.elasticsearch.action.admin.indices.flush.FlushResponse; import org.elasticsearch.action.admin.indices.flush.TransportFlushAction; import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.ActionTestUtils; import org.elasticsearch.action.support.DefaultShardOperationFailedException; +import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.action.support.broadcast.BroadcastRequest; import org.elasticsearch.action.support.broadcast.BroadcastResponse; import org.elasticsearch.cluster.ClusterState; @@ -41,6 +40,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.concurrent.ConcurrentCollections; +import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; @@ -104,6 +104,7 @@ threadPool, BigArrays.NON_RECYCLING_INSTANCE, circuitBreakerService, new NamedWr new ActionFilters(new HashSet<>()), new IndexNameExpressionResolver(Settings.EMPTY), null); } + @Override @After public void tearDown() throws Exception { super.tearDown(); @@ -244,13 +245,15 @@ public FlushResponse assertImmediateResponse(String index, TransportFlushAction return flushResponse; } - public BroadcastResponse executeAndAssertImmediateResponse(TransportBroadcastReplicationAction broadcastAction, DummyBroadcastRequest request) { + public BroadcastResponse executeAndAssertImmediateResponse( + TransportBroadcastReplicationAction broadcastAction, + DummyBroadcastRequest request) { PlainActionFuture response = PlainActionFuture.newFuture(); broadcastAction.execute(request, response); return response.actionGet("5s"); } - private void assertBroadcastResponse(int total, int successful, int failed, BroadcastResponse response, Class exceptionClass) { + private void assertBroadcastResponse(int total, int successful, int failed, BroadcastResponse response, Class exceptionClass) { assertThat(response.getSuccessfulShards(), equalTo(successful)); assertThat(response.getTotalShards(), equalTo(total)); assertThat(response.getFailedShards(), equalTo(failed)); diff --git a/server/src/test/java/org/elasticsearch/action/termvectors/AbstractTermVectorsTestCase.java b/server/src/test/java/org/elasticsearch/action/termvectors/AbstractTermVectorsTestCase.java index bd76557f9a86f..e7606ec071895 100644 --- a/server/src/test/java/org/elasticsearch/action/termvectors/AbstractTermVectorsTestCase.java +++ b/server/src/test/java/org/elasticsearch/action/termvectors/AbstractTermVectorsTestCase.java @@ -167,7 +167,7 @@ protected static class TestConfig { public final boolean requestPositions; public final boolean requestOffsets; public final boolean requestPayloads; - public Class expectedException = null; + public Class expectedException = null; public TestConfig(TestDoc doc, String[] selectedFields, boolean requestPositions, boolean requestOffsets, boolean requestPayloads) { this.doc = doc; @@ -177,7 +177,7 @@ public TestConfig(TestDoc doc, String[] selectedFields, boolean requestPositions this.requestPayloads = requestPayloads; } - public TestConfig expectedException(Class exceptionClass) { + public TestConfig expectedException(Class exceptionClass) { this.expectedException = exceptionClass; return this; } diff --git a/server/src/test/java/org/elasticsearch/client/AbstractClientHeadersTestCase.java b/server/src/test/java/org/elasticsearch/client/AbstractClientHeadersTestCase.java index 5dea451dbacfd..31f6963536c50 100644 --- a/server/src/test/java/org/elasticsearch/client/AbstractClientHeadersTestCase.java +++ b/server/src/test/java/org/elasticsearch/client/AbstractClientHeadersTestCase.java @@ -20,8 +20,8 @@ package org.elasticsearch.client; import org.elasticsearch.ExceptionsHelper; -import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteAction; import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotAction; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsAction; @@ -56,7 +56,7 @@ public abstract class AbstractClientHeadersTestCase extends ESTestCase { .put(ThreadContext.PREFIX + ".key2", "val 2") .build(); - private static final Action[] ACTIONS = new Action[] { + private static final Action[] ACTIONS = new Action[] { // client actions GetAction.INSTANCE, SearchAction.INSTANCE, DeleteAction.INSTANCE, DeleteStoredScriptAction.INSTANCE, IndexAction.INSTANCE, @@ -92,7 +92,7 @@ public void tearDown() throws Exception { terminate(threadPool); } - protected abstract Client buildClient(Settings headersSettings, Action[] testedActions); + protected abstract Client buildClient(Settings headersSettings, Action[] testedActions); public void testActions() { diff --git a/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java b/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java index 023932be6a9d0..420f5c5caefb2 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/geo/BaseGeoParsingTestCase.java @@ -18,13 +18,13 @@ */ package org.elasticsearch.common.geo; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; import org.elasticsearch.common.geo.parsers.ShapeParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.hamcrest.ElasticsearchGeoAssertions; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.spatial4j.shape.Shape; import org.locationtech.spatial4j.shape.ShapeCollection; import org.locationtech.spatial4j.shape.jts.JtsGeometry; @@ -49,7 +49,7 @@ abstract class BaseGeoParsingTestCase extends ESTestCase { public abstract void testParseEnvelope() throws IOException; public abstract void testParseGeometryCollection() throws IOException; - protected void assertValidException(XContentBuilder builder, Class expectedException) throws IOException { + protected void assertValidException(XContentBuilder builder, Class expectedException) throws IOException { try (XContentParser parser = createParser(builder)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, expectedException); diff --git a/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java b/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java index 5f2c721533de9..20e159ded41e4 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/geo/builders/AbstractShapeBuilderTestCase.java @@ -37,7 +37,7 @@ import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; -public abstract class AbstractShapeBuilderTestCase extends ESTestCase { +public abstract class AbstractShapeBuilderTestCase> extends ESTestCase { private static final int NUMBER_OF_TESTBUILDERS = 20; private static NamedWriteableRegistry namedWriteableRegistry; @@ -81,7 +81,7 @@ public void testFromXContent() throws IOException { XContentBuilder shuffled = shuffleXContent(builder); try (XContentParser shapeContentParser = createParser(shuffled)) { shapeContentParser.nextToken(); - ShapeBuilder parsedShape = ShapeParser.parse(shapeContentParser); + ShapeBuilder parsedShape = ShapeParser.parse(shapeContentParser); assertNotSame(testShape, parsedShape); assertEquals(testShape, parsedShape); assertEquals(testShape.hashCode(), parsedShape.hashCode()); diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java index 690e7567e59ff..0efeae29c3cce 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java @@ -629,7 +629,7 @@ public void testToXContent() throws Exception { public void testMap() throws Exception { Map> maps = new HashMap<>(); - maps.put("{'map':null}", (Map) null); + maps.put("{'map':null}", (Map) null); maps.put("{'map':{}}", Collections.emptyMap()); maps.put("{'map':{'key':'value'}}", singletonMap("key", "value")); @@ -654,7 +654,7 @@ public void testMap() throws Exception { public void testIterable() throws Exception { Map> iterables = new HashMap<>(); - iterables.put("{'iter':null}", (Iterable) null); + iterables.put("{'iter':null}", (Iterable) null); iterables.put("{'iter':[]}", Collections.emptyList()); iterables.put("{'iter':['a','b']}", Arrays.asList("a", "b")); @@ -944,7 +944,7 @@ public void testSelfReferencingIterable() throws IOException { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder() .startObject() - .field("field", (Iterable) values) + .field("field", values) .endObject()); assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } @@ -959,7 +959,7 @@ public void testSelfReferencingIterableOneLevel() throws IOException { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder() .startObject() - .field("field", (Iterable) values) + .field("field", values) .endObject()); assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } @@ -972,7 +972,7 @@ public void testSelfReferencingIterableTwoLevels() throws IOException { List it1 = new ArrayList<>(); map0.put("foo", 0); - map0.put("it1", (Iterable) it1); // map 0 -> it1 + map0.put("it1", it1); // map 0 -> it1 it1.add(map1); it1.add(map2); // it 1 -> map 1, map 2 diff --git a/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataImplTestCase.java b/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataImplTestCase.java index df6328feabc86..cd1dc01d9ef4a 100644 --- a/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataImplTestCase.java +++ b/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataImplTestCase.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.util.List; + import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -72,7 +73,7 @@ protected long minRamBytesUsed() { public void testDeletedDocs() throws Exception { add2SingleValuedDocumentsAndDeleteOneOfThem(); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); List readerContexts = refreshReader(); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData fieldData = indexFieldData.load(readerContext); @@ -86,7 +87,7 @@ public void testDeletedDocs() throws Exception { public void testSingleValueAllSet() throws Exception { fillSingleValueAllSet(); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); List readerContexts = refreshReader(); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData fieldData = indexFieldData.load(readerContext); @@ -156,7 +157,7 @@ public void assertValues(SortedBinaryDocValues values, int docId, String... actu public void testSingleValueWithMissing() throws Exception { fillSingleValueWithMissing(); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); List readerContexts = refreshReader(); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData fieldData = indexFieldData.load(readerContext); @@ -177,7 +178,7 @@ public void testMultiValueAllSet() throws Exception { // the segments are force merged to a single segment so that the sorted binary doc values can be asserted within a single segment. // Previously we used the SlowCompositeReaderWrapper but this is an unideal solution so force merging is a better idea. writer.forceMerge(1); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); List readerContexts = refreshReader(); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData fieldData = indexFieldData.load(readerContext); @@ -211,7 +212,7 @@ public void testMultiValueAllSet() throws Exception { public void testMultiValueWithMissing() throws Exception { fillMultiValueWithMissing(); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); List readerContexts = refreshReader(); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData fieldData = indexFieldData.load(readerContext); @@ -227,7 +228,7 @@ public void testMultiValueWithMissing() throws Exception { public void testMissingValueForAll() throws Exception { fillAllMissing(); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); List readerContexts = refreshReader(); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData fieldData = indexFieldData.load(readerContext); @@ -251,7 +252,7 @@ public void testMissingValueForAll() throws Exception { public void testSortMultiValuesFields() throws Exception { fillExtendedMvSet(); - IndexFieldData indexFieldData = getForField("value"); + IndexFieldData indexFieldData = getForField("value"); IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer)); SortField sortField = diff --git a/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataTestCase.java b/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataTestCase.java index c204690c76e07..ee8f18aa11e6b 100644 --- a/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataTestCase.java +++ b/server/src/test/java/org/elasticsearch/index/fielddata/AbstractFieldDataTestCase.java @@ -170,7 +170,7 @@ public void testEmpty() throws Exception { writer.addDocument(d); refreshReader(); - IndexFieldData fieldData = getForField("non_existing_field"); + IndexFieldData fieldData = getForField("non_existing_field"); int max = randomInt(7); for (LeafReaderContext readerContext : readerContexts) { AtomicFieldData previous = null; diff --git a/server/src/test/java/org/elasticsearch/index/fielddata/AbstractStringFieldDataTestCase.java b/server/src/test/java/org/elasticsearch/index/fielddata/AbstractStringFieldDataTestCase.java index a478d2c37426d..04cd13766176b 100644 --- a/server/src/test/java/org/elasticsearch/index/fielddata/AbstractStringFieldDataTestCase.java +++ b/server/src/test/java/org/elasticsearch/index/fielddata/AbstractStringFieldDataTestCase.java @@ -260,7 +260,7 @@ public void testActualMissingValue(boolean reverse) throws IOException { } } - final IndexFieldData indexFieldData = getForField("value"); + final IndexFieldData indexFieldData = getForField("value"); final String missingValue = values[1]; IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer)); SortField sortField = indexFieldData.sortField(missingValue, MultiValueMode.MIN, null, reverse); @@ -315,7 +315,7 @@ public void testSortMissing(boolean first, boolean reverse) throws IOException { writer.commit(); } } - final IndexFieldData indexFieldData = getForField("value"); + final IndexFieldData indexFieldData = getForField("value"); IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer)); SortField sortField = indexFieldData.sortField(first ? "_first" : "_last", MultiValueMode.MIN, null, reverse); TopFieldDocs topDocs = searcher.search(new MatchAllDocsQuery(), randomBoolean() ? numDocs : randomIntBetween(10, numDocs), new Sort(sortField)); diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/AggregationTestScriptsPlugin.java b/server/src/test/java/org/elasticsearch/search/aggregations/AggregationTestScriptsPlugin.java index bc98dda41d661..38d9e62604c46 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/AggregationTestScriptsPlugin.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/AggregationTestScriptsPlugin.java @@ -22,6 +22,7 @@ import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.script.MockScriptPlugin; import org.elasticsearch.script.Script; +import org.elasticsearch.script.ScriptType; import java.util.HashMap; import java.util.Map; @@ -29,8 +30,6 @@ import static java.util.Collections.singletonMap; -import org.elasticsearch.script.ScriptType; - /** * This class contains various mocked scripts that are used in aggregations integration tests. */ @@ -68,32 +67,32 @@ protected Map, Object>> pluginScripts() { }); scripts.put("doc['value'].value", vars -> { - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); return doc.get("value"); }); scripts.put("doc['value'].value - dec", vars -> { int dec = (int) vars.get("dec"); - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); ScriptDocValues.Longs value = (ScriptDocValues.Longs) doc.get("value"); return value.getValue() - dec; }); scripts.put("doc['value'].value + inc", vars -> { int inc = (int) vars.get("inc"); - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); ScriptDocValues.Longs value = (ScriptDocValues.Longs) doc.get("value"); return value.getValue() + inc; }); scripts.put("doc['values'].values", vars -> { - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); return doc.get("values"); }); scripts.put(DECREMENT_ALL_VALUES.getIdOrCode(), vars -> { int dec = (int) vars.get("dec"); - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); ScriptDocValues.Longs values = (ScriptDocValues.Longs) doc.get("values"); double[] res = new double[values.size()]; diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/AggregationsTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/AggregationsTests.java index 29d8e327d5cd7..79984f5894904 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/AggregationsTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/AggregationsTests.java @@ -99,10 +99,10 @@ */ public class AggregationsTests extends ESTestCase { - private static final List aggsTests = getAggsTests(); + private static final List> aggsTests = getAggsTests(); - private static List getAggsTests() { - List aggsTests = new ArrayList<>(); + private static List> getAggsTests() { + List> aggsTests = new ArrayList<>(); aggsTests.add(new InternalCardinalityTests()); aggsTests.add(new InternalTDigestPercentilesTests()); aggsTests.add(new InternalTDigestPercentilesRanksTests()); @@ -156,11 +156,11 @@ protected NamedXContentRegistry xContentRegistry() { @Before public void init() throws Exception { - for (InternalAggregationTestCase aggsTest : aggsTests) { + for (InternalAggregationTestCase aggsTest : aggsTests) { if (aggsTest instanceof InternalMultiBucketAggregationTestCase) { // Lower down the number of buckets generated by multi bucket aggregation tests in // order to avoid too many aggregations to be created. - ((InternalMultiBucketAggregationTestCase) aggsTest).setMaxNumberOfBuckets(3); + ((InternalMultiBucketAggregationTestCase) aggsTest).setMaxNumberOfBuckets(3); } aggsTest.setUp(); } @@ -168,7 +168,7 @@ public void init() throws Exception { @After public void cleanUp() throws Exception { - for (InternalAggregationTestCase aggsTest : aggsTests) { + for (InternalAggregationTestCase aggsTest : aggsTests) { aggsTest.tearDown(); } } @@ -268,9 +268,9 @@ private static InternalAggregations createTestInstance(final int minNumAggs, fin int numAggs = randomIntBetween(minNumAggs, 4); List aggs = new ArrayList<>(numAggs); for (int i = 0; i < numAggs; i++) { - InternalAggregationTestCase testCase = randomFrom(aggsTests); + InternalAggregationTestCase testCase = randomFrom(aggsTests); if (testCase instanceof InternalMultiBucketAggregationTestCase) { - InternalMultiBucketAggregationTestCase multiBucketAggTestCase = (InternalMultiBucketAggregationTestCase) testCase; + InternalMultiBucketAggregationTestCase multiBucketAggTestCase = (InternalMultiBucketAggregationTestCase) testCase; if (currentDepth < maxDepth) { multiBucketAggTestCase.setSubAggregationsSupplier( () -> createTestInstance(0, currentDepth + 1, maxDepth) @@ -281,7 +281,7 @@ private static InternalAggregations createTestInstance(final int minNumAggs, fin ); } } else if (testCase instanceof InternalSingleBucketAggregationTestCase) { - InternalSingleBucketAggregationTestCase singleBucketAggTestCase = (InternalSingleBucketAggregationTestCase) testCase; + InternalSingleBucketAggregationTestCase singleBucketAggTestCase = (InternalSingleBucketAggregationTestCase) testCase; if (currentDepth < maxDepth) { singleBucketAggTestCase.subAggregationsSupplier = () -> createTestInstance(0, currentDepth + 1, maxDepth); } else { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityIT.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityIT.java index b8b33b97e4d00..c770bef7df613 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityIT.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/CardinalityIT.java @@ -69,23 +69,23 @@ protected Map, Object>> pluginScripts() { scripts.put("_value", vars -> vars.get("_value")); scripts.put("doc['str_value'].value", vars -> { - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); return doc.get("str_value"); }); scripts.put("doc['str_values'].values", vars -> { - Map doc = (Map) vars.get("doc"); + Map doc = (Map) vars.get("doc"); ScriptDocValues.Strings strValue = (ScriptDocValues.Strings) doc.get("str_values"); return strValue.getValues(); }); scripts.put("doc[' + singleNumericField() + '].value", vars -> { - Map doc = (Map) vars.get("doc"); + Map doc =(Map) vars.get("doc"); return doc.get(singleNumericField()); }); scripts.put("doc[' + multiNumericField(false) + '].values", vars -> { - Map doc = (Map) vars.get("doc"); + Map doc =(Map) vars.get("doc"); return ((ScriptDocValues) doc.get(multiNumericField(false))).getValues(); }); diff --git a/server/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java b/server/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java index 0717e1be2121e..a3fff7f9d5bcc 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java @@ -890,7 +890,7 @@ public void testSkipDuplicates() throws Exception { assertSuggestions(searchResponse, true, "suggestions", expected); } - public void assertSuggestions(String suggestionName, SuggestionBuilder suggestBuilder, String... suggestions) { + public void assertSuggestions(String suggestionName, SuggestionBuilder suggestBuilder, String... suggestions) { SearchResponse searchResponse = client().prepareSearch(INDEX).suggest(new SuggestBuilder().addSuggestion(suggestionName, suggestBuilder)).execute().actionGet(); assertSuggestions(searchResponse, suggestionName, suggestions); } @@ -971,7 +971,7 @@ private void createIndexAndMappingAndSettings(Settings settings, CompletionMappi if (completionMappingBuilder.contextMappings != null) { mapping = mapping.startArray("contexts"); - for (Map.Entry contextMapping : completionMappingBuilder.contextMappings.entrySet()) { + for (Map.Entry> contextMapping : completionMappingBuilder.contextMappings.entrySet()) { mapping = mapping.startObject() .field("name", contextMapping.getValue().name()) .field("type", contextMapping.getValue().type().name()); @@ -1189,7 +1189,7 @@ static class CompletionMappingBuilder { String indexAnalyzer = "simple"; Boolean preserveSeparators = random().nextBoolean(); Boolean preservePositionIncrements = random().nextBoolean(); - LinkedHashMap contextMappings = null; + LinkedHashMap> contextMappings = null; public CompletionMappingBuilder searchAnalyzer(String searchAnalyzer) { this.searchAnalyzer = searchAnalyzer; @@ -1208,7 +1208,7 @@ public CompletionMappingBuilder preservePositionIncrements(Boolean preservePosit return this; } - public CompletionMappingBuilder context(LinkedHashMap contextMappings) { + public CompletionMappingBuilder context(LinkedHashMap> contextMappings) { this.contextMappings = contextMappings; return this; } diff --git a/server/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java b/server/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java index 13f7e55277cc4..00defee8daaf4 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java @@ -19,6 +19,7 @@ package org.elasticsearch.search.suggest; import com.carrotsearch.randomizedtesting.generators.RandomStrings; + import org.apache.lucene.util.LuceneTestCase.SuppressCodecs; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexResponse; @@ -68,7 +69,7 @@ protected int numberOfReplicas() { } public void testContextPrefix() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("cat", ContextBuilder.category("cat").field("cat").build()); boolean addAnotherContext = randomBoolean(); if (addAnotherContext) { @@ -99,7 +100,7 @@ public void testContextPrefix() throws Exception { } public void testContextRegex() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("cat", ContextBuilder.category("cat").field("cat").build()); boolean addAnotherContext = randomBoolean(); if (addAnotherContext) { @@ -130,7 +131,7 @@ public void testContextRegex() throws Exception { } public void testContextFuzzy() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("cat", ContextBuilder.category("cat").field("cat").build()); boolean addAnotherContext = randomBoolean(); if (addAnotherContext) { @@ -162,7 +163,7 @@ public void testContextFuzzy() throws Exception { public void testContextFilteringWorksWithUTF8Categories() throws Exception { CategoryContextMapping contextMapping = ContextBuilder.category("cat").field("cat").build(); - LinkedHashMap map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); + LinkedHashMap> map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); IndexResponse indexResponse = client().prepareIndex(INDEX, TYPE, "1") @@ -183,7 +184,7 @@ public void testContextFilteringWorksWithUTF8Categories() throws Exception { public void testSingleContextFiltering() throws Exception { CategoryContextMapping contextMapping = ContextBuilder.category("cat").field("cat").build(); - LinkedHashMap map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); + LinkedHashMap> map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); int numDocs = 10; @@ -209,7 +210,7 @@ public void testSingleContextFiltering() throws Exception { public void testSingleContextBoosting() throws Exception { CategoryContextMapping contextMapping = ContextBuilder.category("cat").field("cat").build(); - LinkedHashMap map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); + LinkedHashMap> map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); int numDocs = 10; @@ -237,7 +238,7 @@ public void testSingleContextBoosting() throws Exception { public void testSingleContextMultipleContexts() throws Exception { CategoryContextMapping contextMapping = ContextBuilder.category("cat").field("cat").build(); - LinkedHashMap map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); + LinkedHashMap> map = new LinkedHashMap<>(Collections.singletonMap("cat", contextMapping)); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); int numDocs = 10; @@ -262,7 +263,7 @@ public void testSingleContextMultipleContexts() throws Exception { } public void testMultiContextFiltering() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("cat", ContextBuilder.category("cat").field("cat").build()); map.put("type", ContextBuilder.category("type").field("type").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); @@ -306,7 +307,7 @@ public void testMultiContextFiltering() throws Exception { @AwaitsFix(bugUrl = "multiple context boosting is broken, as a suggestion, contexts pair is treated as (num(context) entries)") public void testMultiContextBoosting() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("cat", ContextBuilder.category("cat").field("cat").build()); map.put("type", ContextBuilder.category("type").field("type").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); @@ -361,7 +362,7 @@ public void testMultiContextBoosting() throws Exception { } public void testMissingContextValue() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("cat", ContextBuilder.category("cat").field("cat").build()); map.put("type", ContextBuilder.category("type").field("type").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); @@ -391,7 +392,7 @@ public void testMissingContextValue() throws Exception { } public void testSeveralContexts() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); final int numContexts = randomIntBetween(2, 5); for (int i = 0; i < numContexts; i++) { map.put("type" + i, ContextBuilder.category("type" + i).field("type" + i).build()); @@ -421,7 +422,7 @@ public void testSeveralContexts() throws Exception { } public void testSimpleGeoPrefix() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("geo", ContextBuilder.geo("geo").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); @@ -446,7 +447,7 @@ public void testSimpleGeoPrefix() throws Exception { } public void testGeoFiltering() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("geo", ContextBuilder.geo("geo").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); @@ -478,7 +479,7 @@ public void testGeoFiltering() throws Exception { } public void testGeoBoosting() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("geo", ContextBuilder.geo("geo").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); @@ -511,7 +512,7 @@ public void testGeoBoosting() throws Exception { } public void testGeoPointContext() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("geo", ContextBuilder.geo("geo").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); @@ -551,7 +552,7 @@ public void testGeoNeighbours() throws Exception { neighbours.add("gcpu"); neighbours.add("u10h"); - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("geo", ContextBuilder.geo("geo").precision(4).build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); createIndexAndMapping(mapping); @@ -640,7 +641,7 @@ public void testGeoField() throws Exception { } public void testSkipDuplicatesWithContexts() throws Exception { - LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap> map = new LinkedHashMap<>(); map.put("type", ContextBuilder.category("type").field("type").build()); map.put("cat", ContextBuilder.category("cat").field("cat").build()); final CompletionMappingBuilder mapping = new CompletionMappingBuilder().context(map); @@ -706,7 +707,7 @@ private void createIndexAndMappingAndSettings(Settings settings, CompletionMappi List categoryContextFields = new ArrayList<>(); if (completionMappingBuilder.contextMappings != null) { mapping.startArray("contexts"); - for (Map.Entry contextMapping : completionMappingBuilder.contextMappings.entrySet()) { + for (Map.Entry> contextMapping : completionMappingBuilder.contextMappings.entrySet()) { mapping.startObject() .field("name", contextMapping.getValue().name()) .field("type", contextMapping.getValue().type().name()); diff --git a/server/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java b/server/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java index 862916890e1bb..37fdb7e0aa08b 100644 --- a/server/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java @@ -48,7 +48,7 @@ public class CompletionSuggesterBuilderTests extends AbstractSuggestionBuilderTe private static final Map> contextMap = new HashMap<>(); private static String categoryContextName; private static String geoQueryContextName; - private static List contextMappings = new ArrayList<>(); + private static List> contextMappings = new ArrayList<>(); @Override protected CompletionSuggestionBuilder randomSuggestionBuilder() { diff --git a/server/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchGeoAssertions.java b/server/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchGeoAssertions.java index 7213d7bf9802f..5842b179078d0 100644 --- a/server/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchGeoAssertions.java +++ b/server/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchGeoAssertions.java @@ -19,13 +19,13 @@ package org.elasticsearch.test.hamcrest; +import org.elasticsearch.common.geo.GeoDistance; +import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.parsers.ShapeParser; -import org.locationtech.spatial4j.shape.Shape; -import org.locationtech.spatial4j.shape.ShapeCollection; -import org.locationtech.spatial4j.shape.impl.GeoCircle; -import org.locationtech.spatial4j.shape.impl.RectangleImpl; -import org.locationtech.spatial4j.shape.jts.JtsGeometry; -import org.locationtech.spatial4j.shape.jts.JtsPoint; +import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.common.xcontent.XContentParser; +import org.hamcrest.Matcher; +import org.junit.Assert; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.LineString; @@ -33,12 +33,12 @@ import org.locationtech.jts.geom.MultiPoint; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Polygon; -import org.elasticsearch.common.geo.GeoDistance; -import org.elasticsearch.common.geo.GeoPoint; -import org.elasticsearch.common.unit.DistanceUnit; -import org.elasticsearch.common.xcontent.XContentParser; -import org.hamcrest.Matcher; -import org.junit.Assert; +import org.locationtech.spatial4j.shape.Shape; +import org.locationtech.spatial4j.shape.ShapeCollection; +import org.locationtech.spatial4j.shape.impl.GeoCircle; +import org.locationtech.spatial4j.shape.impl.RectangleImpl; +import org.locationtech.spatial4j.shape.jts.JtsGeometry; +import org.locationtech.spatial4j.shape.jts.JtsPoint; import java.util.Arrays; import java.util.Collections; @@ -208,9 +208,9 @@ public static void assertEquals(Shape s1, Shape s2) { } else if (s1 instanceof ShapeCollection && s2 instanceof ShapeCollection) { assertEquals((ShapeCollection)s1, (ShapeCollection)s2); } else if (s1 instanceof GeoCircle && s2 instanceof GeoCircle) { - Assert.assertEquals((GeoCircle)s1, (GeoCircle)s2); + Assert.assertEquals(s1, s2); } else if (s1 instanceof RectangleImpl && s2 instanceof RectangleImpl) { - Assert.assertEquals((RectangleImpl)s1, (RectangleImpl)s2); + Assert.assertEquals(s1, s2); } else { //We want to know the type of the shape because we test shape equality in a special way... //... in particular we test that one ring is equivalent to another ring even if the points are rotated or reversed. @@ -254,7 +254,7 @@ private static double distance(double lat1, double lon1, double lat2, double lon return GeoDistance.ARC.calculate(lat1, lon1, lat2, lon2, DistanceUnit.DEFAULT); } - public static void assertValidException(XContentParser parser, Class expectedException) { + public static void assertValidException(XContentParser parser, Class expectedException) { try { ShapeParser.parse(parser).build(); Assert.fail("process completed successfully when " + expectedException.getName() + " expected"); diff --git a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java index c4bf2518a9f8f..35dac2e99e00d 100644 --- a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java +++ b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java @@ -20,6 +20,7 @@ package org.elasticsearch.bootstrap; import com.carrotsearch.randomizedtesting.RandomizedRunner; + import org.apache.logging.log4j.Logger; import org.apache.lucene.util.LuceneTestCase; import org.elasticsearch.common.Booleans; @@ -175,7 +176,7 @@ public boolean implies(ProtectionDomain domain, Permission permission) { /** Add the codebase url of the given classname to the codebases map, if the class exists. */ private static void addClassCodebase(Map codebases, String name, String classname) { try { - Class clazz = BootstrapForTesting.class.getClassLoader().loadClass(classname); + Class clazz = BootstrapForTesting.class.getClassLoader().loadClass(classname); if (codebases.put(name, clazz.getProtectionDomain().getCodeSource().getLocation()) != null) { throw new IllegalStateException("Already added " + name + " codebase for testing"); } diff --git a/test/framework/src/main/java/org/elasticsearch/transport/AbstractSimpleTransportTestCase.java b/test/framework/src/main/java/org/elasticsearch/transport/AbstractSimpleTransportTestCase.java index 0b676e1403481..dd8dd5f81ffc9 100644 --- a/test/framework/src/main/java/org/elasticsearch/transport/AbstractSimpleTransportTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/transport/AbstractSimpleTransportTestCase.java @@ -823,7 +823,7 @@ public void handleException(TransportException exp) { }); try { - StringMessageResponse message = res.txGet(); + res.txGet(); fail("exception should be thrown"); } catch (Exception e) { assertThat(e, instanceOf(ReceiveTimeoutTransportException.class)); @@ -939,8 +939,8 @@ public void handleException(TransportException exp) { } public void testTracerLog() throws InterruptedException { - TransportRequestHandler handler = (request, channel, task) -> channel.sendResponse(new StringMessageResponse("")); - TransportRequestHandler handlerWithError = new TransportRequestHandler() { + TransportRequestHandler handler = (request, channel, task) -> channel.sendResponse(new StringMessageResponse("")); + TransportRequestHandler handlerWithError = new TransportRequestHandler() { @Override public void messageReceived(StringMessageRequest request, TransportChannel channel, Task task) throws Exception { if (request.timeout() > 0) { @@ -952,7 +952,7 @@ public void messageReceived(StringMessageRequest request, TransportChannel chann }; final Semaphore requestCompleted = new Semaphore(0); - TransportResponseHandler noopResponseHandler = new TransportResponseHandler() { + TransportResponseHandler noopResponseHandler = new TransportResponseHandler() { @Override public StringMessageResponse newInstance() { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java index 0bf6601593dee..d3ddac3289999 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.core; import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.MetaData; @@ -157,7 +158,6 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPlugin { - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") static Optional X_PACK_FEATURE = Optional.of("x-pack"); @Override @@ -205,7 +205,7 @@ static Settings additionalSettings(final Settings settings, final boolean enable } @Override - public List getClientActions() { + public List> getClientActions() { return Arrays.asList( // deprecation DeprecationInfoAction.INSTANCE, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java index 920081572cfc7..d14c72383d6a8 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java @@ -9,9 +9,9 @@ import org.apache.lucene.util.SetOnce; import org.elasticsearch.SpecialPermission; import org.elasticsearch.Version; +import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; -import org.elasticsearch.action.Action; import org.elasticsearch.action.support.ActionFilter; import org.elasticsearch.client.Client; import org.elasticsearch.client.transport.TransportClient; @@ -261,8 +261,8 @@ public Collection createComponents(Client client, ClusterService cluster } @Override - public List getClientActions() { - List actions = new ArrayList<>(); + public List> getClientActions() { + List> actions = new ArrayList<>(); actions.addAll(licensing.getClientActions()); actions.addAll(super.getClientActions()); return actions; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionFactory.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionFactory.java index 3618b2de4080b..8c6d82f718735 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionFactory.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionFactory.java @@ -24,5 +24,6 @@ protected ActionFactory(Logger actionLogger) { /** * Parses the given xcontent and creates a concrete action */ - public abstract ExecutableAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException; + public abstract ExecutableAction parseExecutable(String watchId, String actionId, XContentParser parser) + throws IOException; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionWrapper.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionWrapper.java index 47d3500f2e920..f2cdc63c6e94c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionWrapper.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/actions/ActionWrapper.java @@ -40,14 +40,14 @@ public class ActionWrapper implements ToXContentObject { @Nullable private final ExecutableCondition condition; @Nullable - private final ExecutableTransform transform; + private final ExecutableTransform transform; private final ActionThrottler throttler; - private final ExecutableAction action; + private final ExecutableAction action; public ActionWrapper(String id, ActionThrottler throttler, @Nullable ExecutableCondition condition, - @Nullable ExecutableTransform transform, - ExecutableAction action) { + @Nullable ExecutableTransform transform, + ExecutableAction action) { this.id = id; this.condition = condition; this.throttler = throttler; @@ -63,7 +63,7 @@ public ExecutableCondition condition() { return condition; } - public ExecutableTransform transform() { + public ExecutableTransform transform() { return transform; } @@ -71,7 +71,7 @@ public Throttler throttler() { return throttler; } - public ExecutableAction action() { + public ExecutableAction action() { return action; } @@ -196,9 +196,9 @@ static ActionWrapper parse(String watchId, String actionId, XContentParser parse assert parser.currentToken() == XContentParser.Token.START_OBJECT; ExecutableCondition condition = null; - ExecutableTransform transform = null; + ExecutableTransform transform = null; TimeValue throttlePeriod = null; - ExecutableAction action = null; + ExecutableAction action = null; String currentFieldName = null; XContentParser.Token token; diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/datafeed/extractor/aggregation/AggregationTestUtils.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/datafeed/extractor/aggregation/AggregationTestUtils.java index 40ea8419765ec..16b62cc23de19 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/datafeed/extractor/aggregation/AggregationTestUtils.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/datafeed/extractor/aggregation/AggregationTestUtils.java @@ -46,7 +46,7 @@ static Aggregations createAggs(List aggsList) { } @SuppressWarnings("unchecked") - static Histogram createHistogramAggregation(String name, List histogramBuckets) { + static Histogram createHistogramAggregation(String name, List histogramBuckets) { Histogram histogram = mock(Histogram.class); when((List)histogram.getBuckets()).thenReturn(histogramBuckets); when(histogram.getName()).thenReturn(name); @@ -72,7 +72,7 @@ static NumericMetricsAggregation.SingleValue createSingleValue(String name, doub static Terms createTerms(String name, Term... terms) { Terms termsAgg = mock(Terms.class); when(termsAgg.getName()).thenReturn(name); - List buckets = new ArrayList<>(); + List buckets = new ArrayList<>(); for (Term term: terms) { StringTerms.Bucket bucket = mock(StringTerms.Bucket.class); when(bucket.getKey()).thenReturn(term.key); diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/BasicDistributedJobsIT.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/BasicDistributedJobsIT.java index e3d67bb0bdb71..9e8d17e84b44a 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/BasicDistributedJobsIT.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/integration/BasicDistributedJobsIT.java @@ -206,7 +206,7 @@ public void testDedicatedMlNode() throws Exception { assertBusy(() -> { ClusterState clusterState = client().admin().cluster().prepareState().get().getState(); PersistentTasksCustomMetaData tasks = clusterState.getMetaData().custom(PersistentTasksCustomMetaData.TYPE); - PersistentTask task = tasks.getTask(MlMetadata.jobTaskId(jobId)); + PersistentTask task = tasks.getTask(MlMetadata.jobTaskId(jobId)); DiscoveryNode node = clusterState.nodes().resolveNode(task.getExecutorNode()); assertThat(node.getAttributes(), hasEntry(MachineLearning.ML_ENABLED_NODE_ATTR, "true")); diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/BatchedDocumentsIteratorTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/BatchedDocumentsIteratorTests.java index 47a168aefad6b..f5a4e34bc67ec 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/BatchedDocumentsIteratorTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/BatchedDocumentsIteratorTests.java @@ -172,7 +172,7 @@ void finishMock() { if (responses.size() > 0) { ActionFuture first = wrapResponse(responses.get(0)); if (responses.size() > 1) { - List rest = new ArrayList<>(); + List> rest = new ArrayList<>(); for (int i = 1; i < responses.size(); ++i) { rest.add(wrapResponse(responses.get(i))); } diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectCommunicatorTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectCommunicatorTests.java index cedc65c2ee225..57e5f6cfdb3ff 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectCommunicatorTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectCommunicatorTests.java @@ -229,6 +229,7 @@ private AutodetectProcess mockAutodetectProcessWithOutputStream() throws IOExcep return process; } + @SuppressWarnings("unchecked") private AutodetectCommunicator createAutodetectCommunicator(ExecutorService executorService, AutodetectProcess autodetectProcess, AutoDetectResultProcessor autoDetectResultProcessor, Consumer finishHandler) throws IOException { @@ -242,12 +243,13 @@ private AutodetectCommunicator createAutodetectCommunicator(ExecutorService exec new NamedXContentRegistry(Collections.emptyList()), executorService); } + @SuppressWarnings("unchecked") private AutodetectCommunicator createAutodetectCommunicator(AutodetectProcess autodetectProcess, AutoDetectResultProcessor autoDetectResultProcessor) throws IOException { ExecutorService executorService = mock(ExecutorService.class); when(executorService.submit(any(Callable.class))).thenReturn(mock(Future.class)); doAnswer(invocationOnMock -> { - Callable runnable = (Callable) invocationOnMock.getArguments()[0]; + Callable runnable = (Callable) invocationOnMock.getArguments()[0]; runnable.call(); return mock(Future.class); }).when(executorService).submit(any(Callable.class)); diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManagerTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManagerTests.java index fa41cf0918f71..a1b9aad452b9e 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManagerTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/AutodetectProcessManagerTests.java @@ -31,7 +31,6 @@ import org.elasticsearch.xpack.core.ml.job.config.JobUpdate; import org.elasticsearch.xpack.core.ml.job.config.MlFilter; import org.elasticsearch.xpack.core.ml.job.config.ModelPlotConfig; -import org.elasticsearch.xpack.ml.job.process.autodetect.params.AutodetectParams; import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.DataCounts; import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.ModelSizeStats; import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.ModelSnapshot; @@ -42,6 +41,7 @@ import org.elasticsearch.xpack.ml.job.persistence.JobDataCountsPersister; import org.elasticsearch.xpack.ml.job.persistence.JobProvider; import org.elasticsearch.xpack.ml.job.persistence.JobResultsPersister; +import org.elasticsearch.xpack.ml.job.process.autodetect.params.AutodetectParams; import org.elasticsearch.xpack.ml.job.process.autodetect.params.DataLoadParams; import org.elasticsearch.xpack.ml.job.process.autodetect.params.FlushJobParams; import org.elasticsearch.xpack.ml.job.process.autodetect.params.TimeRange; @@ -202,6 +202,7 @@ public void testOpenJob() { verify(jobTask).updatePersistentTaskState(eq(new JobTaskState(JobState.OPENED, 1L)), any()); } + @SuppressWarnings("unchecked") public void testOpenJob_exceedMaxNumJobs() { when(jobManager.getJobOrThrowIfUnknown("foo")).thenReturn(createJobDetails("foo")); when(jobManager.getJobOrThrowIfUnknown("bar")).thenReturn(createJobDetails("bar")); @@ -214,7 +215,7 @@ public void testOpenJob_exceedMaxNumJobs() { ThreadPool.Cancellable cancellable = mock(ThreadPool.Cancellable.class); when(threadPool.scheduleWithFixedDelay(any(), any(), any())).thenReturn(cancellable); ExecutorService executorService = mock(ExecutorService.class); - Future future = mock(Future.class); + Future future = mock(Future.class); when(executorService.submit(any(Callable.class))).thenReturn(future); when(threadPool.executor(anyString())).thenReturn(EsExecutors.newDirectExecutorService()); AutodetectProcess autodetectProcess = mock(AutodetectProcess.class); @@ -230,7 +231,6 @@ public void testOpenJob_exceedMaxNumJobs() { doReturn(executorService).when(manager).createAutodetectExecutorService(any()); doAnswer(invocationOnMock -> { - @SuppressWarnings("unchecked") CheckedConsumer consumer = (CheckedConsumer) invocationOnMock.getArguments()[2]; consumer.accept(null); return null; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 19760ccab0202..09de32643ed93 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -403,7 +403,7 @@ private IllegalArgumentException illegalArgument(String message) { } private static String getAction(BulkItemRequest item) { - final DocWriteRequest docWriteRequest = item.request(); + final DocWriteRequest docWriteRequest = item.request(); switch (docWriteRequest.opType()) { case INDEX: case CREATE: diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java index 67e21aadcbceb..5d9176b18976e 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java @@ -129,14 +129,14 @@ private static boolean isInternalAction(String action) { */ public static class AsyncAuthorizer { - private final ActionListener listener; + private final ActionListener listener; private final BiConsumer consumer; private final Authentication authentication; private volatile Role userRoles; private volatile Role runAsRoles; private CountDown countDown = new CountDown(2); // we expect only two responses!! - public AsyncAuthorizer(Authentication authentication, ActionListener listener, BiConsumer consumer) { + public AsyncAuthorizer(Authentication authentication, ActionListener listener, BiConsumer consumer) { this.consumer = consumer; this.listener = listener; this.authentication = authentication; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java index 77bf8e6a4008e..7d4469133687e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java @@ -37,9 +37,9 @@ import static org.elasticsearch.test.SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.iterableWithSize; +import static org.hamcrest.Matchers.nullValue; public class AuditTrailTests extends SecurityIntegTestCase { @@ -163,7 +163,7 @@ private Collection> getAuditEvents() throws Exception { .request(); request.indicesOptions().ignoreUnavailable(); - final PlainActionFuture>> listener = new PlainActionFuture(); + final PlainActionFuture>> listener = new PlainActionFuture<>(); ScrollHelper.fetchAllByEntity(client, request, listener, SearchHit::getSourceAsMap); return listener.get(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index cd685b8f34c28..bb32ed699950c 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -199,7 +199,6 @@ public void shutdownThreadpool() throws InterruptedException { } } - @SuppressWarnings("unchecked") public void testTokenFirstMissingSecondFound() throws Exception { when(firstRealm.token(threadContext)).thenReturn(null); when(secondRealm.token(threadContext)).thenReturn(token); @@ -227,7 +226,6 @@ public void testTokenMissing() throws Exception { verifyNoMoreInteractions(auditTrail); } - @SuppressWarnings("unchecked") public void testAuthenticateBothSupportSecondSucceeds() throws Exception { User user = new User("_username", "r1"); when(firstRealm.supports(token)).thenReturn(true); @@ -698,7 +696,7 @@ public void testRunAsLookupSameRealm() throws Exception { mockAuthenticate(secondRealm, token, user); mockRealmLookupReturnsNull(firstRealm, "run_as"); doAnswer((i) -> { - ActionListener listener = (ActionListener) i.getArguments()[1]; + ActionListener listener = (ActionListener) i.getArguments()[1]; listener.onResponse(new User("looked up user", new String[]{"some role"})); return null; }).when(secondRealm).lookupUser(eq("run_as"), any(ActionListener.class)); @@ -735,6 +733,7 @@ public void testRunAsLookupSameRealm() throws Exception { assertTrue(completed.get()); } + @SuppressWarnings("unchecked") public void testRunAsLookupDifferentRealm() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); threadContext.putHeader(AuthenticationServiceField.RUN_AS_USER_HEADER, "run_as"); @@ -742,7 +741,7 @@ public void testRunAsLookupDifferentRealm() throws Exception { when(secondRealm.supports(token)).thenReturn(true); mockAuthenticate(secondRealm, token, new User("lookup user", new String[]{"user"})); doAnswer((i) -> { - ActionListener listener = (ActionListener) i.getArguments()[1]; + ActionListener listener = (ActionListener) i.getArguments()[1]; listener.onResponse(new User("looked up user", new String[]{"some role"})); return null; }).when(firstRealm).lookupUser(eq("run_as"), any(ActionListener.class)); @@ -805,6 +804,7 @@ public void testRunAsWithEmptyRunAsUsername() throws Exception { } } + @SuppressWarnings("unchecked") public void testAuthenticateTransportDisabledRunAsUser() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); threadContext.putHeader(AuthenticationServiceField.RUN_AS_USER_HEADER, "run_as"); @@ -813,7 +813,7 @@ public void testAuthenticateTransportDisabledRunAsUser() throws Exception { mockAuthenticate(secondRealm, token, new User("lookup user", new String[]{"user"})); mockRealmLookupReturnsNull(firstRealm, "run_as"); doAnswer((i) -> { - ActionListener listener = (ActionListener) i.getArguments()[1]; + ActionListener listener = (ActionListener) i.getArguments()[1]; listener.onResponse(new User("looked up user", new String[]{"some role"}, null, null, null, false)); return null; }).when(secondRealm).lookupUser(eq("run_as"), any(ActionListener.class)); @@ -833,7 +833,8 @@ public void testAuthenticateRestDisabledRunAsUser() throws Exception { mockAuthenticate(secondRealm, token, new User("lookup user", new String[]{"user"})); mockRealmLookupReturnsNull(firstRealm, "run_as"); doAnswer((i) -> { - ActionListener listener = (ActionListener) i.getArguments()[1]; + @SuppressWarnings("unchecked") + ActionListener listener = (ActionListener) i.getArguments()[1]; listener.onResponse(new User("looked up user", new String[]{"some role"}, null, null, null, false)); return null; }).when(secondRealm).lookupUser(eq("run_as"), any(ActionListener.class)); @@ -984,9 +985,10 @@ void assertThreadContextContainsAuthentication(Authentication authentication) th assertThat(threadContext.getHeader(AuthenticationField.AUTHENTICATION_KEY), equalTo((Object) authentication.encode())); } + @SuppressWarnings("unchecked") private void mockAuthenticate(Realm realm, AuthenticationToken token, User user) { doAnswer((i) -> { - ActionListener listener = (ActionListener) i.getArguments()[1]; + ActionListener listener = (ActionListener) i.getArguments()[1]; if (user == null) { listener.onResponse(AuthenticationResult.notHandled()); } else { @@ -1008,9 +1010,10 @@ private Authentication authenticateBlocking(String action, TransportMessage mess return future.actionGet(); } + @SuppressWarnings("unchecked") private static void mockRealmLookupReturnsNull(Realm realm, String username) { doAnswer((i) -> { - ActionListener listener = (ActionListener) i.getArguments()[1]; + ActionListener listener = (ActionListener) i.getArguments()[1]; listener.onResponse(null); return null; }).when(realm).lookupUser(eq(username), any(ActionListener.class)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index bcd31c32f7f78..11ee0a6a0012e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -168,6 +168,7 @@ public class AuthorizationServiceTests extends ESTestCase { private Map roleMap = new HashMap<>(); private CompositeRolesStore rolesStore; + @SuppressWarnings("unchecked") @Before public void setup() { rolesStore = mock(CompositeRolesStore.class); @@ -208,7 +209,7 @@ public void setup() { } private void authorize(Authentication authentication, String action, TransportRequest request) { - PlainActionFuture future = new PlainActionFuture(); + PlainActionFuture future = new PlainActionFuture<>(); AuthorizationUtils.AsyncAuthorizer authorizer = new AuthorizationUtils.AsyncAuthorizer(authentication, future, (userRoles, runAsRoles) -> { authorizationService.authorize(authentication, action, request, userRoles, runAsRoles); @@ -598,7 +599,6 @@ public void testAuditTrailIsRecordedWhenIndexWildcardThrowsError() { public void testRunAsRequestWithNoRolesUser() { final TransportRequest request = mock(TransportRequest.class); final Authentication authentication = createAuthentication(new User("run as me", null, new User("test user", "admin"))); - final User user = new User("run as me", null, new User("test user", "admin")); assertNotEquals(authentication.getUser().authenticatedUser(), authentication); assertThrowsAuthorizationExceptionRunAs( () -> authorize(authentication, "indices:a", request), diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/InputRegistry.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/InputRegistry.java index 460725c3dda98..732653d829307 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/InputRegistry.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/InputRegistry.java @@ -33,7 +33,7 @@ public InputRegistry(Settings settings, Map factories) { * @param parser The parser containing the input definition * @return A new input instance from the parser */ - public ExecutableInput parse(String watchId, XContentParser parser) throws IOException { + public ExecutableInput parse(String watchId, XContentParser parser) throws IOException { String type = null; if (parser.currentToken() != XContentParser.Token.START_OBJECT) { @@ -42,7 +42,7 @@ public ExecutableInput parse(String watchId, XContentParser parser) throws IOExc } XContentParser.Token token; - ExecutableInput input = null; + ExecutableInput input = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { type = parser.currentName(); @@ -50,7 +50,7 @@ public ExecutableInput parse(String watchId, XContentParser parser) throws IOExc throw new ElasticsearchParseException("could not parse input for watch [{}]. expected field indicating the input type, " + "but found [{}] instead", watchId, token); } else if (token == XContentParser.Token.START_OBJECT) { - InputFactory factory = factories.get(type); + InputFactory factory = factories.get(type); if (factory == null) { throw new ElasticsearchParseException("could not parse input for watch [{}]. unknown input type [{}]", watchId, type); } diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/ActionWrapperTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/ActionWrapperTests.java index 7754e622d5a6b..a81868f05edfc 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/ActionWrapperTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/ActionWrapperTests.java @@ -8,6 +8,7 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.watcher.actions.Action; import org.elasticsearch.xpack.core.watcher.actions.ActionStatus; +import org.elasticsearch.xpack.core.watcher.actions.ActionStatus.AckStatus.State; import org.elasticsearch.xpack.core.watcher.actions.ActionWrapper; import org.elasticsearch.xpack.core.watcher.actions.ActionWrapperResult; import org.elasticsearch.xpack.core.watcher.actions.ExecutableAction; @@ -22,7 +23,6 @@ import java.util.HashMap; import java.util.Map; -import static org.elasticsearch.xpack.core.watcher.actions.ActionStatus.AckStatus.State; import static org.hamcrest.Matchers.is; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -32,7 +32,8 @@ public class ActionWrapperTests extends ESTestCase { private DateTime now = DateTime.now(DateTimeZone.UTC); private Watch watch = mock(Watch.class); - private ExecutableAction executableAction = mock(ExecutableAction.class); + @SuppressWarnings("unchecked") + private ExecutableAction executableAction = mock(ExecutableAction.class); private ActionWrapper actionWrapper = new ActionWrapper("_action", null, NeverCondition.INSTANCE, null, executableAction); public void testThatUnmetActionConditionResetsAckStatus() throws Exception { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/throttler/ActionThrottleTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/throttler/ActionThrottleTests.java index bc22d58917931..05256ba5fc476 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/throttler/ActionThrottleTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/throttler/ActionThrottleTests.java @@ -57,7 +57,7 @@ public void testSingleActionAckThrottle() throws Exception { .trigger(schedule(interval("60m"))); AvailableAction availableAction = randomFrom(AvailableAction.values()); - Action.Builder action = availableAction.action(); + Action.Builder action = availableAction.action(); watchSourceBuilder.addAction("test_id", action); watcherClient().putWatch(new PutWatchRequest("_id", watchSourceBuilder.buildAsBytes(XContentType.JSON), @@ -98,7 +98,7 @@ public void testRandomMultiActionAckThrottle() throws Exception { Set ackingActions = new HashSet<>(); for (int i = 0; i < scaledRandomIntBetween(5,10); ++i) { AvailableAction availableAction = randomFrom(AvailableAction.values()); - Action.Builder action = availableAction.action(); + Action.Builder action = availableAction.action(); watchSourceBuilder.addAction("test_id" + i, action); if (randomBoolean()) { ackingActions.add("test_id" + i); @@ -352,7 +352,7 @@ public void testFailingActionDoesGetThrottled() throws Exception { enum AvailableAction { EMAIL { @Override - public Action.Builder action() throws Exception { + public Action.Builder action() throws Exception { EmailTemplate.Builder emailBuilder = EmailTemplate.builder(); emailBuilder.from("test@test.com"); emailBuilder.to("test@test.com"); @@ -367,7 +367,7 @@ public String type() { }, WEBHOOK { @Override - public Action.Builder action() throws Exception { + public Action.Builder action() throws Exception { HttpRequestTemplate.Builder requestBuilder = HttpRequestTemplate.builder("localhost", 1234) .path("/") .method(HttpMethod.GET); @@ -381,7 +381,7 @@ public String type() { }, LOGGING { @Override - public Action.Builder action() throws Exception { + public Action.Builder action() throws Exception { return LoggingAction.builder(new TextTemplate("_logging")); } @@ -392,7 +392,7 @@ public String type() { }, INDEX { @Override - public Action.Builder action() throws Exception { + public Action.Builder action() throws Exception { return IndexAction.builder("test_index", "test_type"); } @@ -402,7 +402,7 @@ public String type() { } }; - public abstract Action.Builder action() throws Exception; + public abstract Action.Builder action() throws Exception; public abstract String type(); } From adfcea2af6c5eaaf4160d223664bea138b41095f Mon Sep 17 00:00:00 2001 From: Michael Basnight Date: Mon, 25 Jun 2018 10:54:39 -0500 Subject: [PATCH 07/23] Add package pre-install check for java binary (#31343) The package installation relies on java being in the path. If java is not in the path, the tests fail at post-install time. This commit adds a pre-install check to validate that java exists, and if it fails, the package is never installed, and thus keeps a system clean, rather than aborting at post-install and leaving behind a mess. Closes #29665 --- .../packages/src/common/scripts/preinst | 12 +++++++++++ .../packaging/tests/30_deb_package.bats | 8 +++++++ .../packaging/tests/40_rpm_package.bats | 8 +++++++ .../test/resources/packaging/utils/utils.bash | 21 +++++++++++++++++-- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/distribution/packages/src/common/scripts/preinst b/distribution/packages/src/common/scripts/preinst index 2aec2172ad856..22f2405af3c2b 100644 --- a/distribution/packages/src/common/scripts/preinst +++ b/distribution/packages/src/common/scripts/preinst @@ -9,6 +9,18 @@ # $1=1 : indicates an new install # $1=2 : indicates an upgrade +# Check for these at preinst time due to failures in postinst if they do not exist +if [ -x "$JAVA_HOME/bin/java" ]; then + JAVA="$JAVA_HOME/bin/java" +else + JAVA=`which java` +fi + +if [ -z "$JAVA" ]; then + echo "could not find java; set JAVA_HOME or ensure java is in PATH" + exit 1 +fi + case "$1" in # Debian #################################################### diff --git a/qa/vagrant/src/test/resources/packaging/tests/30_deb_package.bats b/qa/vagrant/src/test/resources/packaging/tests/30_deb_package.bats index 397660b239a46..749c72c8b312f 100644 --- a/qa/vagrant/src/test/resources/packaging/tests/30_deb_package.bats +++ b/qa/vagrant/src/test/resources/packaging/tests/30_deb_package.bats @@ -72,6 +72,14 @@ setup() { [ "$status" -eq 1 ] } +@test "[DEB] temporarily remove java and ensure the install fails" { + move_java + run dpkg -i elasticsearch-oss-$(cat version).deb + output=$status + unmove_java + [ "$output" -eq 1 ] +} + @test "[DEB] install package" { dpkg -i elasticsearch-oss-$(cat version).deb } diff --git a/qa/vagrant/src/test/resources/packaging/tests/40_rpm_package.bats b/qa/vagrant/src/test/resources/packaging/tests/40_rpm_package.bats index 52347c7ef4e41..cb12d4b50e02b 100644 --- a/qa/vagrant/src/test/resources/packaging/tests/40_rpm_package.bats +++ b/qa/vagrant/src/test/resources/packaging/tests/40_rpm_package.bats @@ -71,6 +71,14 @@ setup() { [ "$status" -eq 1 ] } +@test "[RPM] temporarily remove java and ensure the install fails" { + move_java + run rpm -i elasticsearch-oss-$(cat version).rpm + output=$status + unmove_java + [ "$output" -eq 1 ] +} + @test "[RPM] install package" { rpm -i elasticsearch-oss-$(cat version).rpm } diff --git a/qa/vagrant/src/test/resources/packaging/utils/utils.bash b/qa/vagrant/src/test/resources/packaging/utils/utils.bash index 53662ca9d3c1d..c07037a5f275b 100644 --- a/qa/vagrant/src/test/resources/packaging/utils/utils.bash +++ b/qa/vagrant/src/test/resources/packaging/utils/utils.bash @@ -68,8 +68,11 @@ if [ ! -x "`which unzip 2>/dev/null`" ]; then fi if [ ! -x "`which java 2>/dev/null`" ]; then - echo "'java' command is mandatory to run the tests" - exit 1 + # there are some tests that move java temporarily + if [ ! -x "`command -v java.bak 2>/dev/null`" ]; then + echo "'java' command is mandatory to run the tests" + exit 1 + fi fi # Returns 0 if the 'dpkg' command is available @@ -578,3 +581,17 @@ file_privileges_for_user_from_umask() { echo $((0777 & ~$(sudo -E -u $user sh -c umask) & ~0111)) } + +# move java to simulate it not being in the path +move_java() { + which_java=`command -v java` + assert_file_exist $which_java + mv $which_java ${which_java}.bak +} + +# move java back to its original location +unmove_java() { + which_java=`command -v java.bak` + assert_file_exist $which_java + mv $which_java `dirname $which_java`/java +} From bb1d4aaf176a80818477f07072ccaa15c29fefc2 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Mon, 25 Jun 2018 18:25:34 +0200 Subject: [PATCH 08/23] Watcher: Fix put watch action (#31524) If no version is specified when putting a watch, the index API should be used instead of the update API, so that the whole watch gets overwritten instead of being merged with the existing one. Merging only happens when a version is specified, so that credentials can be omitted, which is important for the watcher UI. --- ...watch_gets_overwritten_without_version.yml | 73 +++++++++++++++++++ .../actions/put/TransportPutWatchAction.java | 29 ++++++-- 2 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugin/src/test/resources/rest-api-spec/test/watcher/put_watch/90_ensure_watch_gets_overwritten_without_version.yml diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/watcher/put_watch/90_ensure_watch_gets_overwritten_without_version.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/watcher/put_watch/90_ensure_watch_gets_overwritten_without_version.yml new file mode 100644 index 0000000000000..4bea2f655e624 --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/watcher/put_watch/90_ensure_watch_gets_overwritten_without_version.yml @@ -0,0 +1,73 @@ +--- +"Test put watch api without version overwrites watch": + - do: + cluster.health: + wait_for_status: yellow + + - do: + xpack.watcher.put_watch: + id: "my_watch" + body: > + { + "trigger": { + "schedule": { + "hourly": { + "minute": [ 0, 5 ] + } + } + }, + "input": { + "simple": { + "foo": "bar" + } + }, + "actions": { + "logging": { + "logging": { + "text": "yaml test" + } + } + } + } + - match: { _id: "my_watch" } + + - do: + xpack.watcher.get_watch: + id: "my_watch" + - match: { watch.input.simple.foo: "bar" } + + # change the simple input fields, then ensure the old + # field does not exist on get + - do: + xpack.watcher.put_watch: + id: "my_watch" + body: > + { + "trigger": { + "schedule": { + "hourly": { + "minute": [ 0, 5 ] + } + } + }, + "input": { + "simple": { + "spam": "eggs" + } + }, + "actions": { + "logging": { + "logging": { + "text": "yaml test" + } + } + } + } + - match: { _id: "my_watch" } + + - do: + xpack.watcher.get_watch: + id: "my_watch" + - match: { watch.input.simple.spam: "eggs" } + - is_false: watch.input.simple.foo + diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/put/TransportPutWatchAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/put/TransportPutWatchAction.java index 84efc21594365..5be1236574f37 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/put/TransportPutWatchAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transport/actions/put/TransportPutWatchAction.java @@ -7,6 +7,8 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.action.update.UpdateRequest; @@ -89,18 +91,29 @@ protected void doExecute(PutWatchRequest request, ActionListenerwrap(response -> { + executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, updateRequest, + ActionListener.wrap(response -> { + boolean created = response.getResult() == DocWriteResponse.Result.CREATED; + listener.onResponse(new PutWatchResponse(response.getId(), response.getVersion(), created)); + }, listener::onFailure), + client::update); + } else { + IndexRequest indexRequest = new IndexRequest(Watch.INDEX, Watch.DOC_TYPE, request.getId()); + indexRequest.source(builder); + indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); + executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, indexRequest, + ActionListener.wrap(response -> { boolean created = response.getResult() == DocWriteResponse.Result.CREATED; listener.onResponse(new PutWatchResponse(response.getId(), response.getVersion(), created)); }, listener::onFailure), - client::update); + client::index); + } } } catch (Exception e) { listener.onFailure(e); From 237650e9c054149fd08213b38a81a3666c1868e5 Mon Sep 17 00:00:00 2001 From: Igor Motov Date: Mon, 25 Jun 2018 12:20:27 -0700 Subject: [PATCH 09/23] Add x-opaque-id to search slow logs (#31539) Add x-opaque-id to search slow logs only. Indexing slow log and audit logs will be handled as separate PRs. Relates #31521 --- .../org/elasticsearch/http/netty4/Netty4HttpClient.java | 3 ++- .../java/org/elasticsearch/http/nio/Netty4HttpClient.java | 5 +++-- .../main/java/org/elasticsearch/action/ActionModule.java | 3 ++- .../java/org/elasticsearch/http/DefaultRestChannel.java | 3 ++- .../main/java/org/elasticsearch/index/SearchSlowLog.java | 6 ++++++ server/src/main/java/org/elasticsearch/node/Node.java | 3 ++- server/src/main/java/org/elasticsearch/tasks/Task.java | 5 +++++ .../action/admin/cluster/node/tasks/TasksIT.java | 6 +++--- .../org/elasticsearch/http/DefaultRestChannelTests.java | 7 ++++--- .../java/org/elasticsearch/index/SearchSlowLogTests.java | 6 ++++++ 10 files changed, 35 insertions(+), 12 deletions(-) diff --git a/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java b/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java index 9719d15778b53..0fa331ba138f6 100644 --- a/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java +++ b/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java @@ -44,6 +44,7 @@ import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.tasks.Task; import java.io.Closeable; import java.net.SocketAddress; @@ -74,7 +75,7 @@ static Collection returnHttpResponseBodies(Collection static Collection returnOpaqueIds(Collection responses) { List list = new ArrayList<>(responses.size()); for (HttpResponse response : responses) { - list.add(response.headers().get("X-Opaque-Id")); + list.add(response.headers().get(Task.X_OPAQUE_ID)); } return list; } diff --git a/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/Netty4HttpClient.java b/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/Netty4HttpClient.java index 32f294f47ce9c..becebade37348 100644 --- a/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/Netty4HttpClient.java +++ b/plugins/transport-nio/src/test/java/org/elasticsearch/http/nio/Netty4HttpClient.java @@ -44,6 +44,7 @@ import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.tasks.Task; import java.io.Closeable; import java.net.SocketAddress; @@ -74,7 +75,7 @@ static Collection returnHttpResponseBodies(Collection static Collection returnOpaqueIds(Collection responses) { List list = new ArrayList<>(responses.size()); for (HttpResponse response : responses) { - list.add(response.headers().get("X-Opaque-Id")); + list.add(response.headers().get(Task.X_OPAQUE_ID)); } return list; } @@ -90,7 +91,7 @@ public Collection get(SocketAddress remoteAddress, String... u for (int i = 0; i < uris.length; i++) { final HttpRequest httpRequest = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, uris[i]); httpRequest.headers().add(HOST, "localhost"); - httpRequest.headers().add("X-Opaque-ID", String.valueOf(i)); + httpRequest.headers().add(Task.X_OPAQUE_ID, String.valueOf(i)); requests.add(httpRequest); } return sendRequests(remoteAddress, requests); diff --git a/server/src/main/java/org/elasticsearch/action/ActionModule.java b/server/src/main/java/org/elasticsearch/action/ActionModule.java index 324e75d64d80f..48e1cef08d00a 100644 --- a/server/src/main/java/org/elasticsearch/action/ActionModule.java +++ b/server/src/main/java/org/elasticsearch/action/ActionModule.java @@ -316,6 +316,7 @@ import org.elasticsearch.rest.action.search.RestMultiSearchAction; import org.elasticsearch.rest.action.search.RestSearchAction; import org.elasticsearch.rest.action.search.RestSearchScrollAction; +import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.usage.UsageService; @@ -369,7 +370,7 @@ public ActionModule(boolean transportClient, Settings settings, IndexNameExpress destructiveOperations = new DestructiveOperations(settings, clusterSettings); Set headers = Stream.concat( actionPlugins.stream().flatMap(p -> p.getRestHeaders().stream()), - Stream.of("X-Opaque-Id") + Stream.of(Task.X_OPAQUE_ID) ).collect(Collectors.toSet()); UnaryOperator restWrapper = null; for (ActionPlugin plugin : actionPlugins) { diff --git a/server/src/main/java/org/elasticsearch/http/DefaultRestChannel.java b/server/src/main/java/org/elasticsearch/http/DefaultRestChannel.java index 38bf1e751ef9d..9d21896182c67 100644 --- a/server/src/main/java/org/elasticsearch/http/DefaultRestChannel.java +++ b/server/src/main/java/org/elasticsearch/http/DefaultRestChannel.java @@ -38,6 +38,8 @@ import java.util.List; import java.util.Map; +import static org.elasticsearch.tasks.Task.X_OPAQUE_ID; + /** * The default rest channel for incoming requests. This class implements the basic logic for sending a rest * response. It will set necessary headers nad ensure that bytes are released after the response is sent. @@ -50,7 +52,6 @@ public class DefaultRestChannel extends AbstractRestChannel implements RestChann static final String CONTENT_TYPE = "content-type"; static final String CONTENT_LENGTH = "content-length"; static final String SET_COOKIE = "set-cookie"; - static final String X_OPAQUE_ID = "X-Opaque-Id"; private final HttpRequest httpRequest; private final BigArrays bigArrays; diff --git a/server/src/main/java/org/elasticsearch/index/SearchSlowLog.java b/server/src/main/java/org/elasticsearch/index/SearchSlowLog.java index f3c5d07f1f2f4..10b4c4318a30e 100644 --- a/server/src/main/java/org/elasticsearch/index/SearchSlowLog.java +++ b/server/src/main/java/org/elasticsearch/index/SearchSlowLog.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.index.shard.SearchOperationListener; import org.elasticsearch.search.internal.SearchContext; +import org.elasticsearch.tasks.Task; import java.util.Collections; import java.util.concurrent.TimeUnit; @@ -174,6 +175,11 @@ public String toString() { } else { sb.append("source[], "); } + if (context.getTask().getHeader(Task.X_OPAQUE_ID) != null) { + sb.append("id[").append(context.getTask().getHeader(Task.X_OPAQUE_ID)).append("], "); + } else { + sb.append("id[], "); + } return sb.toString(); } } diff --git a/server/src/main/java/org/elasticsearch/node/Node.java b/server/src/main/java/org/elasticsearch/node/Node.java index 4440153dd361e..64bc55edb7109 100644 --- a/server/src/main/java/org/elasticsearch/node/Node.java +++ b/server/src/main/java/org/elasticsearch/node/Node.java @@ -136,6 +136,7 @@ import org.elasticsearch.search.fetch.FetchPhase; import org.elasticsearch.snapshots.SnapshotShardsService; import org.elasticsearch.snapshots.SnapshotsService; +import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskResultsService; import org.elasticsearch.threadpool.ExecutorBuilder; import org.elasticsearch.threadpool.ThreadPool; @@ -447,7 +448,7 @@ protected Node(final Environment environment, Collection final Transport transport = networkModule.getTransportSupplier().get(); Set taskHeaders = Stream.concat( pluginsService.filterPlugins(ActionPlugin.class).stream().flatMap(p -> p.getTaskHeaders().stream()), - Stream.of("X-Opaque-Id") + Stream.of(Task.X_OPAQUE_ID) ).collect(Collectors.toSet()); final TransportService transportService = newTransportService(settings, transport, threadPool, networkModule.getTransportInterceptor(), localNodeFactory, settingsModule.getClusterSettings(), taskHeaders); diff --git a/server/src/main/java/org/elasticsearch/tasks/Task.java b/server/src/main/java/org/elasticsearch/tasks/Task.java index 9fd9019cd213c..f639846b418e3 100644 --- a/server/src/main/java/org/elasticsearch/tasks/Task.java +++ b/server/src/main/java/org/elasticsearch/tasks/Task.java @@ -34,6 +34,11 @@ */ public class Task { + /** + * The request header to mark tasks with specific ids + */ + public static final String X_OPAQUE_ID = "X-Opaque-Id"; + private final long id; private final String type; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java index 09a64a016ab8d..d33fff45308f3 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java @@ -357,7 +357,7 @@ public void testSearchTaskDescriptions() { .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get(); Map headers = new HashMap<>(); - headers.put("X-Opaque-Id", "my_id"); + headers.put(Task.X_OPAQUE_ID, "my_id"); headers.put("Foo-Header", "bar"); headers.put("Custom-Task-Header", "my_value"); assertSearchResponse( @@ -404,7 +404,7 @@ public void testSearchTaskHeaderLimit() { int maxSize = Math.toIntExact(SETTING_HTTP_MAX_HEADER_SIZE.getDefault(Settings.EMPTY).getBytes() / 2 + 1); Map headers = new HashMap<>(); - headers.put("X-Opaque-Id", "my_id"); + headers.put(Task.X_OPAQUE_ID, "my_id"); headers.put("Custom-Task-Header", randomAlphaOfLengthBetween(maxSize, maxSize + 100)); IllegalArgumentException ex = expectThrows( IllegalArgumentException.class, @@ -415,7 +415,7 @@ public void testSearchTaskHeaderLimit() { private void assertTaskHeaders(TaskInfo taskInfo) { assertThat(taskInfo.getHeaders().keySet(), hasSize(2)); - assertEquals("my_id", taskInfo.getHeaders().get("X-Opaque-Id")); + assertEquals("my_id", taskInfo.getHeaders().get(Task.X_OPAQUE_ID)); assertEquals("my_value", taskInfo.getHeaders().get("Custom-Task-Header")); } diff --git a/server/src/test/java/org/elasticsearch/http/DefaultRestChannelTests.java b/server/src/test/java/org/elasticsearch/http/DefaultRestChannelTests.java index bc499ed8a420a..fd68376109802 100644 --- a/server/src/test/java/org/elasticsearch/http/DefaultRestChannelTests.java +++ b/server/src/test/java/org/elasticsearch/http/DefaultRestChannelTests.java @@ -36,6 +36,7 @@ import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestResponse; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; @@ -180,7 +181,7 @@ public void testResponse() { public void testHeadersSet() { Settings settings = Settings.builder().build(); final TestRequest httpRequest = new TestRequest(HttpRequest.HttpVersion.HTTP_1_1, RestRequest.Method.GET, "/"); - httpRequest.getHeaders().put(DefaultRestChannel.X_OPAQUE_ID, Collections.singletonList("abc")); + httpRequest.getHeaders().put(Task.X_OPAQUE_ID, Collections.singletonList("abc")); final RestRequest request = RestRequest.request(xContentRegistry(), httpRequest, httpChannel); HttpHandlingSettings handlingSettings = HttpHandlingSettings.fromSettings(settings); @@ -200,7 +201,7 @@ public void testHeadersSet() { Map> headers = httpResponse.headers; assertNull(headers.get("non-existent-header")); assertEquals(customHeaderValue, headers.get(customHeader).get(0)); - assertEquals("abc", headers.get(DefaultRestChannel.X_OPAQUE_ID).get(0)); + assertEquals("abc", headers.get(Task.X_OPAQUE_ID).get(0)); assertEquals(Integer.toString(resp.content().length()), headers.get(DefaultRestChannel.CONTENT_LENGTH).get(0)); assertEquals(resp.contentType(), headers.get(DefaultRestChannel.CONTENT_TYPE).get(0)); } @@ -208,7 +209,7 @@ public void testHeadersSet() { public void testCookiesSet() { Settings settings = Settings.builder().put(HttpTransportSettings.SETTING_HTTP_RESET_COOKIES.getKey(), true).build(); final TestRequest httpRequest = new TestRequest(HttpRequest.HttpVersion.HTTP_1_1, RestRequest.Method.GET, "/"); - httpRequest.getHeaders().put(DefaultRestChannel.X_OPAQUE_ID, Collections.singletonList("abc")); + httpRequest.getHeaders().put(Task.X_OPAQUE_ID, Collections.singletonList("abc")); final RestRequest request = RestRequest.request(xContentRegistry(), httpRequest, httpChannel); HttpHandlingSettings handlingSettings = HttpHandlingSettings.fromSettings(settings); diff --git a/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java b/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java index 23d2f7bcafa96..adb7a087367d2 100644 --- a/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java +++ b/server/src/test/java/org/elasticsearch/index/SearchSlowLogTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.index; import org.elasticsearch.Version; +import org.elasticsearch.action.search.SearchTask; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.bytes.BytesReference; @@ -34,12 +35,15 @@ import org.elasticsearch.search.internal.AliasFilter; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.ShardSearchRequest; +import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.test.TestSearchContext; import org.elasticsearch.threadpool.ThreadPool; import java.io.IOException; +import java.util.Collections; +import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; @@ -166,10 +170,12 @@ public void testSlowLogSearchContextPrinterToLog() throws IOException { SearchContext searchContext = createSearchContext(index); SearchSourceBuilder source = SearchSourceBuilder.searchSource().query(QueryBuilders.matchAllQuery()); searchContext.request().source(source); + searchContext.setTask(new SearchTask(0, "n/a", "n/a", "test", null, Collections.singletonMap(Task.X_OPAQUE_ID, "my_id"))); SearchSlowLog.SlowLogSearchContextPrinter p = new SearchSlowLog.SlowLogSearchContextPrinter(searchContext, 10); assertThat(p.toString(), startsWith("[foo][0]")); // Makes sure that output doesn't contain any new lines assertThat(p.toString(), not(containsString("\n"))); + assertThat(p.toString(), endsWith("id[my_id], ")); } public void testLevelSetting() { From c6012ed5753dfa9475a2e3be6b31a33253c5bb4f Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Mon, 25 Jun 2018 17:17:16 -0700 Subject: [PATCH 10/23] fix writeIndex evaluation for aliases (#31562) AliasOrIndex.Alias#writeIndex was returning a write index when an alias was pointing to only one index, regardless whether `is_write_index` was set to `false`. This fixes that so that there is no write index in such a case that an alias points to only one index with `is_write_index=false`. --- .../elasticsearch/cluster/metadata/AliasOrIndex.java | 10 +++++++--- .../metadata/MetaDataIndexAliasesServiceTests.java | 3 +-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/AliasOrIndex.java b/server/src/main/java/org/elasticsearch/cluster/metadata/AliasOrIndex.java index d8bb04a1a39c3..497dc49198bfc 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/AliasOrIndex.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/AliasOrIndex.java @@ -157,9 +157,13 @@ public void computeAndValidateWriteIndex() { List writeIndices = referenceIndexMetaDatas.stream() .filter(idxMeta -> Boolean.TRUE.equals(idxMeta.getAliases().get(aliasName).writeIndex())) .collect(Collectors.toList()); - if (referenceIndexMetaDatas.size() == 1) { - writeIndex.set(referenceIndexMetaDatas.get(0)); - } else if (writeIndices.size() == 1) { + + if (writeIndices.isEmpty() && referenceIndexMetaDatas.size() == 1 + && referenceIndexMetaDatas.get(0).getAliases().get(aliasName).writeIndex() == null) { + writeIndices.add(referenceIndexMetaDatas.get(0)); + } + + if (writeIndices.size() == 1) { writeIndex.set(writeIndices.get(0)); } else if (writeIndices.size() > 1) { List writeIndicesStrings = writeIndices.stream() diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesServiceTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesServiceTests.java index 812dfd8f6f686..e1fbc47c4a022 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesServiceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexAliasesServiceTests.java @@ -136,8 +136,7 @@ public void testAddWriteOnlyWithNoExistingAliases() { ClusterState after = service.innerExecute(before, Arrays.asList( new AliasAction.Add("test", "alias", null, null, null, false))); assertFalse(after.metaData().index("test").getAliases().get("alias").writeIndex()); - assertThat(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex(), - equalTo(after.metaData().index("test"))); + assertNull(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex()); after = service.innerExecute(before, Arrays.asList( new AliasAction.Add("test", "alias", null, null, null, null))); From 357a07e7a21fefa6144de6829e1e2042a2960786 Mon Sep 17 00:00:00 2001 From: Sue Gallagher <36747279+Sue-Gallagher@users.noreply.github.com> Date: Mon, 25 Jun 2018 17:25:32 -0700 Subject: [PATCH 11/23] [DOCS] Fix heading format errors (#31483) * [DOCS] Fix heading format errors. Closes #31327 * [DOCS] Fix heading format errors. Closes #31327 --- .../aggregations/bucket/composite-aggregation.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc index 019094cfa3fe2..3bfa8d91f8b4e 100644 --- a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc +++ b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc @@ -224,7 +224,7 @@ Time values can also be specified via abbreviations supported by < Supports expressive date <> -====== Time Zone +*Time Zone* Date-times are stored in Elasticsearch in UTC. By default, all bucketing and rounding is also done in UTC. The `time_zone` parameter can be used to indicate From 424be027283588ac5fb76dffbee1c1cb88e75ff5 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Tue, 26 Jun 2018 00:01:45 -0400 Subject: [PATCH 12/23] Enhance thread context uniqueness assertion This commit enhances the assertion message when de-duplicating values on a thread context header so that if this assertion trips we can see the values and their correpsonding unique values to understand why this assertion might trip. --- .../elasticsearch/common/util/concurrent/ThreadContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/elasticsearch/common/util/concurrent/ThreadContext.java index ba72561f0c145..490f3d680e428 100644 --- a/server/src/main/java/org/elasticsearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/elasticsearch/common/util/concurrent/ThreadContext.java @@ -489,7 +489,8 @@ private ThreadContextStruct putResponse(final String key, final String value, fi final List existingValues = newResponseHeaders.get(key); if (existingValues != null) { final Set existingUniqueValues = existingValues.stream().map(uniqueValue).collect(Collectors.toSet()); - assert existingValues.size() == existingUniqueValues.size(); + assert existingValues.size() == existingUniqueValues.size() : + "existing values: [" + existingValues + "], existing unique values [" + existingUniqueValues + "]"; if (existingUniqueValues.contains(uniqueValue.apply(value))) { return this; } From be9292cac6a4741af678dbf885daebc963977336 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Tue, 26 Jun 2018 10:07:25 +0200 Subject: [PATCH 13/23] [Test] Add full cluster restart test for Rollup (#31533) This pull request adds a full cluster restart test for a Rollup job. The test creates and starts a Rollup job on the cluster and checks that the job already exists and is correctly started on the upgraded cluster. This test allows to test that the persistent task state is correctly parsed from the cluster state after the upgrade, as the status field has been renamed to state in #31031. The test undercovers a ClassCastException that can be thrown in the RollupIndexer when the timestamp as a very low value that fits into an integer. When it's the case, the value is parsed back as an Integer instead of Long object and (long) position.get(rollupFieldName) fails. --- .../xpack/rollup/job/RollupIndexer.java | 6 +- .../xpack/restart/FullClusterRestartIT.java | 150 +++++++++++++----- 2 files changed, 117 insertions(+), 39 deletions(-) diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/job/RollupIndexer.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/job/RollupIndexer.java index 3ba3611293fdc..5abd701ce4b2e 100644 --- a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/job/RollupIndexer.java +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/job/RollupIndexer.java @@ -415,7 +415,11 @@ private QueryBuilder createBoundaryQuery(Map position) { DateHistoGroupConfig dateHisto = job.getConfig().getGroupConfig().getDateHisto(); String fieldName = dateHisto.getField(); String rollupFieldName = fieldName + "." + DateHistogramAggregationBuilder.NAME; - long lowerBound = position != null ? (long) position.get(rollupFieldName) : 0; + long lowerBound = 0L; + if (position != null) { + Number value = (Number) position.get(rollupFieldName); + lowerBound = value.longValue(); + } assert lowerBound <= maxBoundary; final RangeQueryBuilder query = new RangeQueryBuilder(fieldName) .gte(lowerBound) diff --git a/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java b/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java index 2502944a99691..5276abdbfb1d8 100644 --- a/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java +++ b/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java @@ -9,6 +9,7 @@ import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.elasticsearch.Version; +import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.common.Booleans; @@ -20,7 +21,6 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.StreamsUtils; import org.elasticsearch.test.rest.ESRestTestCase; -import org.elasticsearch.xpack.core.monitoring.exporter.MonitoringTemplateUtils; import org.elasticsearch.xpack.core.watcher.client.WatchSourceBuilder; import org.elasticsearch.xpack.core.watcher.support.xcontent.ObjectPath; import org.elasticsearch.xpack.security.support.SecurityIndexManager; @@ -30,6 +30,7 @@ import org.elasticsearch.xpack.watcher.condition.InternalAlwaysCondition; import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule; import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger; +import org.hamcrest.Matcher; import org.junit.Before; import java.io.IOException; @@ -38,6 +39,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -254,6 +256,71 @@ public void testWatcher() throws Exception { } } + /** + * Tests that a RollUp job created on a old cluster is correctly restarted after the upgrade. + */ + public void testRollupAfterRestart() throws Exception { + assumeTrue("Rollup can be tested with 6.3.0 and onwards", oldClusterVersion.onOrAfter(Version.V_6_3_0)); + if (runningAgainstOldCluster) { + final int numDocs = 59; + final int year = randomIntBetween(1970, 2018); + + // index documents for the rollup job + final StringBuilder bulk = new StringBuilder(); + for (int i = 0; i < numDocs; i++) { + bulk.append("{\"index\":{\"_index\":\"rollup-docs\",\"_type\":\"doc\"}}\n"); + String date = String.format(Locale.ROOT, "%04d-01-01T00:%02d:00Z", year, i); + bulk.append("{\"timestamp\":\"").append(date).append("\",\"value\":").append(i).append("}\n"); + } + bulk.append("\r\n"); + + final Request bulkRequest = new Request("POST", "/_bulk"); + bulkRequest.setJsonEntity(bulk.toString()); + client().performRequest(bulkRequest); + + // create the rollup job + final Request createRollupJobRequest = new Request("PUT", "/_xpack/rollup/job/rollup-job-test"); + createRollupJobRequest.setJsonEntity("{" + + "\"index_pattern\":\"rollup-*\"," + + "\"rollup_index\":\"results-rollup\"," + + "\"cron\":\"*/30 * * * * ?\"," + + "\"page_size\":100," + + "\"groups\":{" + + " \"date_histogram\":{" + + " \"field\":\"timestamp\"," + + " \"interval\":\"5m\"" + + " }" + + "}," + + "\"metrics\":[" + + " {\"field\":\"value\",\"metrics\":[\"min\",\"max\",\"sum\"]}" + + "]" + + "}"); + + Map createRollupJobResponse = toMap(client().performRequest(createRollupJobRequest)); + assertThat(createRollupJobResponse.get("acknowledged"), equalTo(Boolean.TRUE)); + + // start the rollup job + final Request startRollupJobRequest = new Request("POST", "_xpack/rollup/job/rollup-job-test/_start"); + Map startRollupJobResponse = toMap(client().performRequest(startRollupJobRequest)); + assertThat(startRollupJobResponse.get("started"), equalTo(Boolean.TRUE)); + + assertRollUpJob("rollup-job-test"); + + } else { + + final Request clusterHealthRequest = new Request("GET", "/_cluster/health"); + clusterHealthRequest.addParameter("wait_for_status", "yellow"); + clusterHealthRequest.addParameter("wait_for_no_relocating_shards", "true"); + if (oldClusterVersion.onOrAfter(Version.V_6_2_0)) { + clusterHealthRequest.addParameter("wait_for_no_initializing_shards", "true"); + } + Map clusterHealthResponse = toMap(client().performRequest(clusterHealthRequest)); + assertThat(clusterHealthResponse.get("timed_out"), equalTo(Boolean.FALSE)); + + assertRollUpJob("rollup-job-test"); + } + } + public void testSqlFailsOnIndexWithTwoTypes() throws IOException { // TODO this isn't going to trigger until we backport to 6.1 assumeTrue("It is only possible to build an index that sql doesn't like before 6.0.0", @@ -393,43 +460,6 @@ private void waitForHits(String indexName, int expectedHits) throws Exception { }, 30, TimeUnit.SECONDS); } - @SuppressWarnings("unchecked") - private void waitForMonitoringTemplates() throws Exception { - assertBusy(() -> { - final Map templates = toMap(client().performRequest("GET", "/_template/.monitoring-*")); - - // in earlier versions, we published legacy templates in addition to the current ones to support transitioning - assertThat(templates.size(), greaterThanOrEqualTo(MonitoringTemplateUtils.TEMPLATE_IDS.length)); - - // every template should be updated to whatever the current version is - for (final String templateId : MonitoringTemplateUtils.TEMPLATE_IDS) { - final String templateName = MonitoringTemplateUtils.templateName(templateId); - final Map template = (Map) templates.get(templateName); - - assertThat(template.get("version"), is(MonitoringTemplateUtils.LAST_UPDATED_VERSION)); - } - }, 30, TimeUnit.SECONDS); - } - - @SuppressWarnings("unchecked") - private void waitForClusterStats(final String expectedVersion) throws Exception { - assertBusy(() -> { - final Map params = new HashMap<>(3); - params.put("q", "type:cluster_stats"); - params.put("size", "1"); - params.put("sort", "timestamp:desc"); - - final Map response = toMap(client().performRequest("GET", "/.monitoring-es-*/_search", params)); - final Map hits = (Map) response.get("hits"); - - assertThat("No cluster_stats documents found.", (int)hits.get("total"), greaterThanOrEqualTo(1)); - - final Map hit = (Map) ((List) hits.get("hits")).get(0); - final Map source = (Map) hit.get("_source"); - assertThat(source.get("version"), is(expectedVersion)); - }, 30, TimeUnit.SECONDS); - } - static Map toMap(Response response) throws IOException { return toMap(EntityUtils.toString(response.getEntity())); } @@ -492,4 +522,48 @@ private void assertRoleInfo(final String role) throws Exception { assertNotNull(response.get("cluster")); assertNotNull(response.get("indices")); } + + @SuppressWarnings("unchecked") + private void assertRollUpJob(final String rollupJob) throws Exception { + final Matcher expectedStates = anyOf(equalTo("indexing"), equalTo("started")); + waitForRollUpJob(rollupJob, expectedStates); + + // check that the rollup job is started using the RollUp API + final Request getRollupJobRequest = new Request("GET", "_xpack/rollup/job/" + rollupJob); + Map getRollupJobResponse = toMap(client().performRequest(getRollupJobRequest)); + assertThat(ObjectPath.eval("jobs.0.status.job_state", getRollupJobResponse), expectedStates); + + // check that the rollup job is started using the Tasks API + final Request taskRequest = new Request("GET", "_tasks"); + taskRequest.addParameter("detailed", "true"); + taskRequest.addParameter("actions", "xpack/rollup/*"); + Map taskResponse = toMap(client().performRequest(taskRequest)); + Map taskResponseNodes = (Map) taskResponse.get("nodes"); + Map taskResponseNode = (Map) taskResponseNodes.values().iterator().next(); + Map taskResponseTasks = (Map) taskResponseNode.get("tasks"); + Map taskResponseStatus = (Map) taskResponseTasks.values().iterator().next(); + assertThat(ObjectPath.eval("status.job_state", taskResponseStatus), expectedStates); + + // check that the rollup job is started using the Cluster State API + final Request clusterStateRequest = new Request("GET", "_cluster/state/metadata"); + Map clusterStateResponse = toMap(client().performRequest(clusterStateRequest)); + Map rollupJobTask = ObjectPath.eval("metadata.persistent_tasks.tasks.0", clusterStateResponse); + assertThat(ObjectPath.eval("id", rollupJobTask), equalTo("rollup-job-test")); + + // Persistent task state field has been renamed in 6.4.0 from "status" to "state" + final String stateFieldName = (runningAgainstOldCluster && oldClusterVersion.before(Version.V_6_4_0)) ? "status" : "state"; + + final String jobStateField = "task.xpack/rollup/job." + stateFieldName + ".job_state"; + assertThat("Expected field [" + jobStateField + "] to be started or indexing in " + rollupJobTask, + ObjectPath.eval(jobStateField, rollupJobTask), expectedStates); + } + + private void waitForRollUpJob(final String rollupJob, final Matcher expectedStates) throws Exception { + assertBusy(() -> { + final Request getRollupJobRequest = new Request("GET", "_xpack/rollup/job/" + rollupJob); + Response getRollupJobResponse = client().performRequest(getRollupJobRequest); + assertThat(getRollupJobResponse.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); + assertThat(ObjectPath.eval("jobs.0.status.job_state", toMap(getRollupJobResponse)), expectedStates); + }, 30L, TimeUnit.SECONDS); + } } From ca4c857a9022b0db9dc8a10465224d1e9037a433 Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Tue, 26 Jun 2018 12:39:53 +0200 Subject: [PATCH 14/23] Improve test times for tests using `RandomObjects::addFields` (#31556) Currently RandomObjects::addFields can potentially generate a large number of fields This commit decreases the chances that a new object or array is added as a new branch of an object, which lowers the probability of ending up with very big documents generated. It also reduces the number of documents generated for the SimulatePipelineResponseTests from 10 to 5 to reduce the testing time required for parsing. --- .../action/ingest/SimulateDocumentVerboseResultTests.java | 2 +- .../action/ingest/SimulatePipelineResponseTests.java | 2 +- .../src/main/java/org/elasticsearch/test/RandomObjects.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResultTests.java b/server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResultTests.java index 5701bcc27800f..6b673c49efa0b 100644 --- a/server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResultTests.java +++ b/server/src/test/java/org/elasticsearch/action/ingest/SimulateDocumentVerboseResultTests.java @@ -31,7 +31,7 @@ public class SimulateDocumentVerboseResultTests extends AbstractXContentTestCase { static SimulateDocumentVerboseResult createTestInstance(boolean withFailures) { - int numDocs = randomIntBetween(0, 10); + int numDocs = randomIntBetween(0, 5); List results = new ArrayList<>(); for (int i = 0; i results = new ArrayList<>(numResults); for (int i = 0; i < numResults; i++) { if (isVerbose) { diff --git a/test/framework/src/main/java/org/elasticsearch/test/RandomObjects.java b/test/framework/src/main/java/org/elasticsearch/test/RandomObjects.java index a509645495858..06eefb7ccba14 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/RandomObjects.java +++ b/test/framework/src/main/java/org/elasticsearch/test/RandomObjects.java @@ -187,9 +187,9 @@ public static BytesReference randomSource(Random random, XContentType xContentTy * Randomly adds fields, objects, or arrays to the provided builder. The maximum depth is 5. */ private static void addFields(Random random, XContentBuilder builder, int minNumFields, int currentDepth) throws IOException { - int numFields = randomIntBetween(random, minNumFields, 10); + int numFields = randomIntBetween(random, minNumFields, 5); for (int i = 0; i < numFields; i++) { - if (currentDepth < 5 && random.nextBoolean()) { + if (currentDepth < 5 && random.nextInt(100) >= 70) { if (random.nextBoolean()) { builder.startObject(RandomStrings.randomAsciiOfLengthBetween(random, 6, 10)); addFields(random, builder, minNumFields, currentDepth + 1); From 232c71b6bf22bdddee6faa8d46b5a96029b03942 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 26 Jun 2018 09:26:48 -0400 Subject: [PATCH 15/23] QA: Create xpack yaml features (#31403) This creates a YAML test "features" that indices if the cluster being tested has xpack installed (`xpack`) or if it does *not* have xpack installed (`no_xpack`). It uses those features to centralize skipping a few tests that fail if xpack is installed. The plan is to use this in a followup to skip docs tests that require xpack when xpack is not installed. We *plan* to use the declaration of required license level on the docs page to generate the required `skip`. Closes #30933. --- qa/mixed-cluster/build.gradle | 7 ---- .../test/cat.templates/10_basic.yml | 6 ++-- .../test/rest/ESRestTestCase.java | 32 +++++++++++++++++-- .../test/rest/yaml/Features.java | 23 ++++++++++--- .../integration/MlRestTestStateCleaner.java | 10 +++--- .../rollup/RollupRestTestStateCleaner.java | 8 ++--- .../xpack/test/rest/XPackRestIT.java | 4 +-- .../build.gradle | 3 -- .../ml/integration/DatafeedJobsRestIT.java | 2 +- .../xpack/ml/integration/MlJobIT.java | 2 +- 10 files changed, 63 insertions(+), 34 deletions(-) diff --git a/qa/mixed-cluster/build.gradle b/qa/mixed-cluster/build.gradle index da99bbb4c8036..ac57d51def7c6 100644 --- a/qa/mixed-cluster/build.gradle +++ b/qa/mixed-cluster/build.gradle @@ -57,13 +57,6 @@ for (Version version : bwcVersions.wireCompatible) { tasks.getByName("${baseName}#mixedClusterTestRunner").configure { /* To support taking index snapshots, we have to set path.repo setting */ systemProperty 'tests.path.repo', new File(buildDir, "cluster/shared/repo") - if ('zip'.equals(extension.distribution)) { - systemProperty 'tests.rest.blacklist', [ - 'cat.templates/10_basic/No templates', - 'cat.templates/10_basic/Sort templates', - 'cat.templates/10_basic/Multiple template', - ].join(',') - } } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yml index 78b7a4277570a..fe0d7ee30730f 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yml @@ -15,7 +15,7 @@ --- "No templates": - skip: - features: default_shards + features: default_shards, no_xpack - do: cat.templates: {} @@ -177,7 +177,7 @@ --- "Sort templates": - skip: - features: default_shards + features: default_shards, no_xpack - do: indices.put_template: name: test @@ -227,7 +227,7 @@ --- "Multiple template": - skip: - features: default_shards + features: default_shards, no_xpack - do: indices.put_template: name: test_1 diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java index 672d19d5dc2a6..495df4aa461a9 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java @@ -31,6 +31,7 @@ import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; import org.apache.http.ssl.SSLContexts; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksAction; +import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.RestClient; @@ -40,6 +41,8 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.ThreadContext; +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; @@ -91,13 +94,38 @@ public abstract class ESRestTestCase extends ESTestCase { /** * Convert the entity from a {@link Response} into a map of maps. */ - public Map entityAsMap(Response response) throws IOException { + public static Map entityAsMap(Response response) throws IOException { XContentType xContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue()); - try (XContentParser parser = createParser(xContentType.xContent(), response.getEntity().getContent())) { + // EMPTY and THROW are fine here because `.map` doesn't use named x content or deprecation + try (XContentParser parser = xContentType.xContent().createParser( + NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, + response.getEntity().getContent())) { return parser.map(); } } + /** + * Does the cluster being tested have xpack installed? + */ + public static boolean hasXPack() throws IOException { + RestClient client = adminClient(); + if (client == null) { + throw new IllegalStateException("must be called inside of a rest test case test"); + } + Map response = entityAsMap(client.performRequest(new Request("GET", "_nodes/plugins"))); + Map nodes = (Map) response.get("nodes"); + for (Map.Entry node : nodes.entrySet()) { + Map nodeInfo = (Map) node.getValue(); + for (Object module: (List) nodeInfo.get("modules")) { + Map moduleInfo = (Map) module; + if (moduleInfo.get("name").toString().startsWith("x-pack-")) { + return true; + } + } + } + return false; + } + private static List clusterHosts; /** * A client for the running Elasticsearch cluster diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/Features.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/Features.java index 757fc2218d51c..cfce0653d31c2 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/Features.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/Features.java @@ -19,9 +19,12 @@ package org.elasticsearch.test.rest.yaml; +import java.io.IOException; import java.util.Arrays; import java.util.List; +import org.elasticsearch.test.rest.ESRestTestCase; + import static java.util.Collections.unmodifiableList; /** @@ -53,11 +56,23 @@ private Features() { * Tells whether all the features provided as argument are supported */ public static boolean areAllSupported(List features) { - for (String feature : features) { - if (!SUPPORTED.contains(feature)) { - return false; + try { + for (String feature : features) { + if (feature.equals("xpack")) { + if (false == ESRestTestCase.hasXPack()) { + return false; + } + } else if (feature.equals("no_xpack")) { + if (ESRestTestCase.hasXPack()) { + return false; + } + } else if (false == SUPPORTED.contains(feature)) { + return false; + } } + return true; + } catch (IOException e) { + throw new RuntimeException("error checking if xpack is available", e); } - return true; } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/integration/MlRestTestStateCleaner.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/integration/MlRestTestStateCleaner.java index 23f357eb1885e..4be0cefe525e6 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/integration/MlRestTestStateCleaner.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/integration/MlRestTestStateCleaner.java @@ -20,18 +20,16 @@ public class MlRestTestStateCleaner { private final Logger logger; private final RestClient adminClient; - private final ESRestTestCase testCase; - public MlRestTestStateCleaner(Logger logger, RestClient adminClient, ESRestTestCase testCase) { + public MlRestTestStateCleaner(Logger logger, RestClient adminClient) { this.logger = logger; this.adminClient = adminClient; - this.testCase = testCase; } public void clearMlMetadata() throws IOException { deleteAllDatafeeds(); deleteAllJobs(); - // indices will be deleted by the ESIntegTestCase class + // indices will be deleted by the ESRestTestCase class } @SuppressWarnings("unchecked") @@ -41,7 +39,7 @@ private void deleteAllDatafeeds() throws IOException { final Response datafeedsResponse = adminClient.performRequest(datafeedsRequest); @SuppressWarnings("unchecked") final List> datafeeds = - (List>) XContentMapValues.extractValue("datafeeds", testCase.entityAsMap(datafeedsResponse)); + (List>) XContentMapValues.extractValue("datafeeds", ESRestTestCase.entityAsMap(datafeedsResponse)); if (datafeeds == null) { return; } @@ -83,7 +81,7 @@ private void deleteAllJobs() throws IOException { final Response response = adminClient.performRequest(jobsRequest); @SuppressWarnings("unchecked") final List> jobConfigs = - (List>) XContentMapValues.extractValue("jobs", testCase.entityAsMap(response)); + (List>) XContentMapValues.extractValue("jobs", ESRestTestCase.entityAsMap(response)); if (jobConfigs == null) { return; } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/rollup/RollupRestTestStateCleaner.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/rollup/RollupRestTestStateCleaner.java index a9a8223863d72..9938f3a41962b 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/rollup/RollupRestTestStateCleaner.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/rollup/RollupRestTestStateCleaner.java @@ -29,18 +29,16 @@ public class RollupRestTestStateCleaner { private final Logger logger; private final RestClient adminClient; - private final ESRestTestCase testCase; - public RollupRestTestStateCleaner(Logger logger, RestClient adminClient, ESRestTestCase testCase) { + public RollupRestTestStateCleaner(Logger logger, RestClient adminClient) { this.logger = logger; this.adminClient = adminClient; - this.testCase = testCase; } public void clearRollupMetadata() throws Exception { deleteAllJobs(); waitForPendingTasks(); - // indices will be deleted by the ESIntegTestCase class + // indices will be deleted by the ESRestTestCase class } private void waitForPendingTasks() throws Exception { @@ -75,7 +73,7 @@ private void waitForPendingTasks() throws Exception { @SuppressWarnings("unchecked") private void deleteAllJobs() throws Exception { Response response = adminClient.performRequest("GET", "/_xpack/rollup/job/_all"); - Map jobs = testCase.entityAsMap(response); + Map jobs = ESRestTestCase.entityAsMap(response); @SuppressWarnings("unchecked") List> jobConfigs = (List>) XContentMapValues.extractValue("jobs", jobs); diff --git a/x-pack/plugin/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestIT.java b/x-pack/plugin/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestIT.java index 99a6e29e334f6..412c75f0e639c 100644 --- a/x-pack/plugin/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestIT.java +++ b/x-pack/plugin/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestIT.java @@ -252,7 +252,7 @@ public void cleanup() throws Exception { */ private void clearMlState() throws Exception { if (isMachineLearningTest()) { - new MlRestTestStateCleaner(logger, adminClient(), this).clearMlMetadata(); + new MlRestTestStateCleaner(logger, adminClient()).clearMlMetadata(); } } @@ -263,7 +263,7 @@ private void clearMlState() throws Exception { */ private void clearRollupState() throws Exception { if (isRollupTest()) { - new RollupRestTestStateCleaner(logger, adminClient(), this).clearRollupMetadata(); + new RollupRestTestStateCleaner(logger, adminClient()).clearRollupMetadata(); } } diff --git a/x-pack/qa/core-rest-tests-with-security/build.gradle b/x-pack/qa/core-rest-tests-with-security/build.gradle index 1daae6dc9f50a..7f2706a773aa9 100644 --- a/x-pack/qa/core-rest-tests-with-security/build.gradle +++ b/x-pack/qa/core-rest-tests-with-security/build.gradle @@ -16,9 +16,6 @@ integTestRunner { 'index/10_with_id/Index with ID', 'indices.get_alias/10_basic/Get alias against closed indices', 'indices.get_alias/20_empty/Check empty aliases when getting all aliases via /_alias', - 'cat.templates/10_basic/No templates', - 'cat.templates/10_basic/Sort templates', - 'cat.templates/10_basic/Multiple template', ].join(',') systemProperty 'tests.rest.cluster.username', System.getProperty('tests.rest.cluster.username', 'test_user') diff --git a/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/DatafeedJobsRestIT.java b/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/DatafeedJobsRestIT.java index 6731e27aaac19..54d8090a7a421 100644 --- a/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/DatafeedJobsRestIT.java +++ b/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/DatafeedJobsRestIT.java @@ -802,7 +802,7 @@ public static void openJob(RestClient client, String jobId) throws IOException { @After public void clearMlState() throws Exception { - new MlRestTestStateCleaner(logger, adminClient(), this).clearMlMetadata(); + new MlRestTestStateCleaner(logger, adminClient()).clearMlMetadata(); XPackRestTestHelper.waitForPendingTasks(adminClient()); } diff --git a/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java b/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java index 114fbdd4e5dd3..6713e66692ded 100644 --- a/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java +++ b/x-pack/qa/ml-native-tests/src/test/java/org/elasticsearch/xpack/ml/integration/MlJobIT.java @@ -676,7 +676,7 @@ private static String responseEntityToString(Response response) throws IOExcepti @After public void clearMlState() throws Exception { - new MlRestTestStateCleaner(logger, adminClient(), this).clearMlMetadata(); + new MlRestTestStateCleaner(logger, adminClient()).clearMlMetadata(); XPackRestTestHelper.waitForPendingTasks(adminClient()); } } From 544e473908c10674446b31edc4027a91c29ff82e Mon Sep 17 00:00:00 2001 From: Igor Motov Date: Tue, 26 Jun 2018 06:44:10 -0700 Subject: [PATCH 16/23] Improve robustness of geo shape parser for malformed shapes (#31449) Ensures that malformed geoshapes are more reliably ignored if "ignore_malformed" is set to true instead of failing the entire document. Closes #31428 --- .../common/geo/parsers/GeoJsonParser.java | 116 ++++++++++-------- .../common/geo/GeoJsonShapeParserTests.java | 50 +++++++- 2 files changed, 117 insertions(+), 49 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/geo/parsers/GeoJsonParser.java b/server/src/main/java/org/elasticsearch/common/geo/parsers/GeoJsonParser.java index 49b7d68b583ff..af0e0248471d5 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/parsers/GeoJsonParser.java +++ b/server/src/main/java/org/elasticsearch/common/geo/parsers/GeoJsonParser.java @@ -55,57 +55,66 @@ protected static ShapeBuilder parse(XContentParser parser, GeoShapeFieldMapper s String malformedException = null; XContentParser.Token token; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - String fieldName = parser.currentName(); - - if (ShapeParser.FIELD_TYPE.match(fieldName, parser.getDeprecationHandler())) { - parser.nextToken(); - final GeoShapeType type = GeoShapeType.forName(parser.text()); - if (shapeType != null && shapeType.equals(type) == false) { - malformedException = ShapeParser.FIELD_TYPE + " already parsed as [" - + shapeType + "] cannot redefine as [" + type + "]"; + try { + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + String fieldName = parser.currentName(); + + if (ShapeParser.FIELD_TYPE.match(fieldName, parser.getDeprecationHandler())) { + parser.nextToken(); + final GeoShapeType type = GeoShapeType.forName(parser.text()); + if (shapeType != null && shapeType.equals(type) == false) { + malformedException = ShapeParser.FIELD_TYPE + " already parsed as [" + + shapeType + "] cannot redefine as [" + type + "]"; + } else { + shapeType = type; + } + } else if (ShapeParser.FIELD_COORDINATES.match(fieldName, parser.getDeprecationHandler())) { + parser.nextToken(); + CoordinateNode tempNode = parseCoordinates(parser, ignoreZValue.value()); + if (coordinateNode != null && tempNode.numDimensions() != coordinateNode.numDimensions()) { + throw new ElasticsearchParseException("Exception parsing coordinates: " + + "number of dimensions do not match"); + } + coordinateNode = tempNode; + } else if (ShapeParser.FIELD_GEOMETRIES.match(fieldName, parser.getDeprecationHandler())) { + if (shapeType == null) { + shapeType = GeoShapeType.GEOMETRYCOLLECTION; + } else if (shapeType.equals(GeoShapeType.GEOMETRYCOLLECTION) == false) { + malformedException = "cannot have [" + ShapeParser.FIELD_GEOMETRIES + "] with type set to [" + + shapeType + "]"; + } + parser.nextToken(); + geometryCollections = parseGeometries(parser, shapeMapper); + } else if (CircleBuilder.FIELD_RADIUS.match(fieldName, parser.getDeprecationHandler())) { + if (shapeType == null) { + shapeType = GeoShapeType.CIRCLE; + } else if (shapeType != null && shapeType.equals(GeoShapeType.CIRCLE) == false) { + malformedException = "cannot have [" + CircleBuilder.FIELD_RADIUS + "] with type set to [" + + shapeType + "]"; + } + parser.nextToken(); + radius = DistanceUnit.Distance.parseDistance(parser.text()); + } else if (ShapeParser.FIELD_ORIENTATION.match(fieldName, parser.getDeprecationHandler())) { + if (shapeType != null + && (shapeType.equals(GeoShapeType.POLYGON) || shapeType.equals(GeoShapeType.MULTIPOLYGON)) == false) { + malformedException = "cannot have [" + ShapeParser.FIELD_ORIENTATION + "] with type set to [" + shapeType + "]"; + } + parser.nextToken(); + requestedOrientation = ShapeBuilder.Orientation.fromString(parser.text()); } else { - shapeType = type; + parser.nextToken(); + parser.skipChildren(); } - } else if (ShapeParser.FIELD_COORDINATES.match(fieldName, parser.getDeprecationHandler())) { - parser.nextToken(); - CoordinateNode tempNode = parseCoordinates(parser, ignoreZValue.value()); - if (coordinateNode != null && tempNode.numDimensions() != coordinateNode.numDimensions()) { - throw new ElasticsearchParseException("Exception parsing coordinates: " + - "number of dimensions do not match"); - } - coordinateNode = tempNode; - } else if (ShapeParser.FIELD_GEOMETRIES.match(fieldName, parser.getDeprecationHandler())) { - if (shapeType == null) { - shapeType = GeoShapeType.GEOMETRYCOLLECTION; - } else if (shapeType.equals(GeoShapeType.GEOMETRYCOLLECTION) == false) { - malformedException = "cannot have [" + ShapeParser.FIELD_GEOMETRIES + "] with type set to [" - + shapeType + "]"; - } - parser.nextToken(); - geometryCollections = parseGeometries(parser, shapeMapper); - } else if (CircleBuilder.FIELD_RADIUS.match(fieldName, parser.getDeprecationHandler())) { - if (shapeType == null) { - shapeType = GeoShapeType.CIRCLE; - } else if (shapeType != null && shapeType.equals(GeoShapeType.CIRCLE) == false) { - malformedException = "cannot have [" + CircleBuilder.FIELD_RADIUS + "] with type set to [" - + shapeType + "]"; - } - parser.nextToken(); - radius = DistanceUnit.Distance.parseDistance(parser.text()); - } else if (ShapeParser.FIELD_ORIENTATION.match(fieldName, parser.getDeprecationHandler())) { - if (shapeType != null - && (shapeType.equals(GeoShapeType.POLYGON) || shapeType.equals(GeoShapeType.MULTIPOLYGON)) == false) { - malformedException = "cannot have [" + ShapeParser.FIELD_ORIENTATION + "] with type set to [" + shapeType + "]"; - } - parser.nextToken(); - requestedOrientation = ShapeBuilder.Orientation.fromString(parser.text()); - } else { - parser.nextToken(); - parser.skipChildren(); } } + } catch (Exception ex) { + // Skip all other fields until the end of the object + while (parser.currentToken() != XContentParser.Token.END_OBJECT && parser.currentToken() != null) { + parser.nextToken(); + parser.skipChildren(); + } + throw ex; } if (malformedException != null) { @@ -144,6 +153,12 @@ protected static ShapeBuilder parse(XContentParser parser, GeoShapeFieldMapper s * XContentParser */ private static CoordinateNode parseCoordinates(XContentParser parser, boolean ignoreZValue) throws IOException { + if (parser.currentToken() == XContentParser.Token.START_OBJECT) { + parser.skipChildren(); + parser.nextToken(); + throw new ElasticsearchParseException("coordinates cannot be specified as objects"); + } + XContentParser.Token token = parser.nextToken(); // Base cases if (token != XContentParser.Token.START_ARRAY && @@ -168,8 +183,13 @@ private static CoordinateNode parseCoordinates(XContentParser parser, boolean ig } private static Coordinate parseCoordinate(XContentParser parser, boolean ignoreZValue) throws IOException { + if (parser.currentToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("geo coordinates must be numbers"); + } double lon = parser.doubleValue(); - parser.nextToken(); + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("geo coordinates must be numbers"); + } double lat = parser.doubleValue(); XContentParser.Token token = parser.nextToken(); // alt (for storing purposes only - future use includes 3d shapes) diff --git a/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java b/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java index bb462ac60342f..f054450f00abe 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/GeoJsonShapeParserTests.java @@ -145,6 +145,7 @@ public void testParseMultiDimensionShapes() throws IOException { XContentParser parser = createParser(pointGeoJson); parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); // multi dimension linestring XContentBuilder lineGeoJson = XContentFactory.jsonBuilder() @@ -159,6 +160,7 @@ public void testParseMultiDimensionShapes() throws IOException { parser = createParser(lineGeoJson); parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } @Override @@ -196,6 +198,7 @@ public void testParseEnvelope() throws IOException { try (XContentParser parser = createParser(multilinesGeoJson)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test #4: "envelope" with empty coordinates @@ -206,6 +209,7 @@ public void testParseEnvelope() throws IOException { try (XContentParser parser = createParser(multilinesGeoJson)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } } @@ -291,6 +295,7 @@ public void testInvalidDimensionalPolygon() throws IOException { try (XContentParser parser = createParser(polygonGeoJson)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } } @@ -306,6 +311,7 @@ public void testParseInvalidPoint() throws IOException { try (XContentParser parser = createParser(invalidPoint1)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 2: create an invalid point object with an empty number of coordinates @@ -318,6 +324,7 @@ public void testParseInvalidPoint() throws IOException { try (XContentParser parser = createParser(invalidPoint2)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } } @@ -331,6 +338,7 @@ public void testParseInvalidMultipoint() throws IOException { try (XContentParser parser = createParser(invalidMultipoint1)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 2: create an invalid multipoint object with null coordinate @@ -343,6 +351,7 @@ public void testParseInvalidMultipoint() throws IOException { try (XContentParser parser = createParser(invalidMultipoint2)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 3: create a valid formatted multipoint object with invalid number (0) of coordinates @@ -356,6 +365,7 @@ public void testParseInvalidMultipoint() throws IOException { try (XContentParser parser = createParser(invalidMultipoint3)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } } @@ -392,6 +402,7 @@ public void testParseInvalidMultiPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, multiPolygonGeoJson)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class); + assertNull(parser.nextToken()); } } @@ -432,8 +443,9 @@ public void testParseInvalidDimensionalMultiPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, multiPolygonGeoJson)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } - } + } public void testParseOGCPolygonWithoutHoles() throws IOException { @@ -650,6 +662,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 2: create an invalid polygon with only 1 point @@ -664,6 +677,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 3: create an invalid polygon with 0 points @@ -678,6 +692,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 4: create an invalid polygon with null value points @@ -692,6 +707,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, IllegalArgumentException.class); + assertNull(parser.nextToken()); } // test case 5: create an invalid polygon with 1 invalid LinearRing @@ -704,6 +720,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, IllegalArgumentException.class); + assertNull(parser.nextToken()); } // test case 6: create an invalid polygon with 0 LinearRings @@ -714,6 +731,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } // test case 7: create an invalid polygon with 0 LinearRings @@ -726,6 +744,7 @@ public void testParseInvalidPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, invalidPoly)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); } } @@ -794,6 +813,7 @@ public void testParseSelfCrossingPolygon() throws IOException { try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) { parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class); + assertNull(parser.nextToken()); } } @@ -1165,4 +1185,32 @@ public void testParseOrientationOption() throws IOException { ElasticsearchGeoAssertions.assertMultiPolygon(shape); } } + + public void testParseInvalidShapes() throws IOException { + // single dimensions point + XContentBuilder tooLittlePointGeoJson = XContentFactory.jsonBuilder() + .startObject() + .field("type", "Point") + .startArray("coordinates").value(10.0).endArray() + .endObject(); + + try (XContentParser parser = createParser(tooLittlePointGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); + } + + // zero dimensions point + XContentBuilder emptyPointGeoJson = XContentFactory.jsonBuilder() + .startObject() + .field("type", "Point") + .startObject("coordinates").field("foo", "bar").endObject() + .endObject(); + + try (XContentParser parser = createParser(emptyPointGeoJson)) { + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + assertNull(parser.nextToken()); + } + } } From 08b8d11e303e6d949d7999b0470cb0af835ed283 Mon Sep 17 00:00:00 2001 From: Alpar Torok Date: Tue, 26 Jun 2018 06:49:03 -0700 Subject: [PATCH 17/23] Add support for switching distribution for all integration tests (#30874) * remove left-over comment * make sure of the property for plugins * skip installing modules if these exist in the distribution * Log the distrbution being ran * Don't allow running with integ-tests-zip passed externally * top level x-pack/qa can't run with oss distro * Add support for matching objects in lists Makes it possible to have a key that points to a list and assert that a certain object is present in the list. All keys have to be present and values have to match. The objects in the source list may have additional fields. example: ``` match: { 'nodes.$master.plugins': { name: ingest-attachment } } ``` * Update plugin and module tests to work with other distributions Some of the tests expected that the integration tests will always be ran with the `integ-test-zip` distribution so that there will be no other plugins loaded. With this change, we check for the presence of the plugin without assuming exclusivity. * Allow modules to run on other distros as well To match the behavior of tets.distributions * Add and use a new `contains` assertion Replaces the previus changes that caused `match` to do a partial match. * Implement PR review comments --- .../gradle/plugin/PluginBuildPlugin.groovy | 6 +- .../gradle/test/ClusterFormationTasks.groovy | 9 ++- .../rest-api-spec/test/stats/10_basic.yml | 2 +- .../test/analysis-common/10_basic.yml | 2 +- .../rest-api-spec/test/ingest/10_basic.yml | 44 +++++----- .../test/lang_expression/10_basic.yml | 2 +- .../test/lang_mustache/10_basic.yml | 2 +- .../rest-api-spec/test/painless/10_basic.yml | 2 +- .../test/repository_url/10_basic.yml | 2 +- .../resources/rest-api-spec/test/10_basic.yml | 2 +- .../test/discovery_azure_classic/10_basic.yml | 2 +- .../test/discovery_ec2/10_basic.yml | 2 +- plugins/discovery-file/build.gradle | 2 +- .../test/discovery_gce/10_basic.yml | 2 +- .../examples/painless-whitelist/build.gradle | 4 +- .../test/painless_whitelist/10_basic.yml | 2 +- .../test/example-rescore/10_basic.yml | 2 +- .../test/script_expert_scoring/10_basic.yml | 2 +- .../test/ingest_attachment/10_basic.yml | 4 +- .../test/ingest_geoip/10_basic.yml | 4 +- .../test/ingest-useragent/10_basic.yml | 4 +- .../test/repository_azure/10_basic.yml | 2 +- .../test/repository_gcs/10_basic.yml | 2 +- plugins/repository-hdfs/build.gradle | 1 - .../test/hdfs_repository/10_basic.yml | 2 +- .../test/secure_hdfs_repository/10_basic.yml | 2 +- .../test/repository_s3/10_basic.yml | 2 +- .../rest-api-spec/test/store_smb/10_basic.yml | 2 +- .../rest/yaml/section/ContainsAssertion.java | 80 +++++++++++++++++++ .../rest/yaml/section/ExecutableSection.java | 1 + .../rest/yaml/section/AssertionTests.java | 16 ++++ x-pack/plugin/build.gradle | 4 + .../rest-api-spec/test/xpack/10_basic.yml | 22 ++--- 33 files changed, 174 insertions(+), 65 deletions(-) create mode 100644 test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ContainsAssertion.java diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy index 28008f4313c97..0a60d6ef87a44 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy @@ -71,7 +71,9 @@ public class PluginBuildPlugin extends BuildPlugin { if (isModule) { project.integTestCluster.module(project) project.tasks.run.clusterConfig.module(project) - project.tasks.run.clusterConfig.distribution = 'integ-test-zip' + project.tasks.run.clusterConfig.distribution = System.getProperty( + 'run.distribution', 'integ-test-zip' + ) } else { project.integTestCluster.plugin(project.path) project.tasks.run.clusterConfig.plugin(project.path) @@ -111,7 +113,7 @@ public class PluginBuildPlugin extends BuildPlugin { private static void createIntegTestTask(Project project) { RestIntegTestTask integTest = project.tasks.create('integTest', RestIntegTestTask.class) integTest.mustRunAfter(project.precommit, project.test) - project.integTestCluster.distribution = 'integ-test-zip' + project.integTestCluster.distribution = System.getProperty('tests.distribution', 'integ-test-zip') project.check.dependsOn(integTest) } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy index 14aa53e4a1762..336db08a019bb 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy @@ -88,6 +88,9 @@ class ClusterFormationTasks { Configuration currentDistro = project.configurations.create("${prefix}_elasticsearchDistro") Configuration bwcDistro = project.configurations.create("${prefix}_elasticsearchBwcDistro") Configuration bwcPlugins = project.configurations.create("${prefix}_elasticsearchBwcPlugins") + if (System.getProperty('tests.distribution', 'oss-zip') == 'integ-test-zip') { + throw new Exception("tests.distribution=integ-test-zip is not supported") + } configureDistributionDependency(project, config.distribution, currentDistro, VersionProperties.elasticsearch) if (config.numBwcNodes > 0) { if (config.bwcVersion == null) { @@ -533,7 +536,8 @@ class ClusterFormationTasks { static Task configureInstallModuleTask(String name, Project project, Task setup, NodeInfo node, Project module) { if (node.config.distribution != 'integ-test-zip') { - throw new GradleException("Module ${module.path} not allowed be installed distributions other than integ-test-zip because they should already have all modules bundled!") + project.logger.lifecycle("Not installing modules for $name, ${node.config.distribution} already has them") + return setup } if (module.plugins.hasPlugin(PluginBuildPlugin) == false) { throw new GradleException("Task ${name} cannot include module ${module.path} which is not an esplugin") @@ -643,6 +647,9 @@ class ClusterFormationTasks { BuildPlugin.requireJavaHome(start, node.javaVersion) } start.doLast(elasticsearchRunner) + start.doFirst { + project.logger.info("Starting node in ${node.clusterName} distribution: ${node.config.distribution}") + } return start } diff --git a/modules/aggs-matrix-stats/src/test/resources/rest-api-spec/test/stats/10_basic.yml b/modules/aggs-matrix-stats/src/test/resources/rest-api-spec/test/stats/10_basic.yml index 5ca9a323387ec..cde34dfa10760 100644 --- a/modules/aggs-matrix-stats/src/test/resources/rest-api-spec/test/stats/10_basic.yml +++ b/modules/aggs-matrix-stats/src/test/resources/rest-api-spec/test/stats/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: aggs-matrix-stats } + - contains: { nodes.$master.modules: { name: aggs-matrix-stats } } diff --git a/modules/analysis-common/src/test/resources/rest-api-spec/test/analysis-common/10_basic.yml b/modules/analysis-common/src/test/resources/rest-api-spec/test/analysis-common/10_basic.yml index d27a0861b2e38..b9b905639fd70 100644 --- a/modules/analysis-common/src/test/resources/rest-api-spec/test/analysis-common/10_basic.yml +++ b/modules/analysis-common/src/test/resources/rest-api-spec/test/analysis-common/10_basic.yml @@ -8,4 +8,4 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: analysis-common } + - contains: { nodes.$master.modules: { name: analysis-common } } diff --git a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/10_basic.yml b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/10_basic.yml index a58c329a7c525..12efaa9570372 100644 --- a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/10_basic.yml +++ b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/10_basic.yml @@ -8,25 +8,25 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: ingest-common } - - match: { nodes.$master.ingest.processors.0.type: append } - - match: { nodes.$master.ingest.processors.1.type: convert } - - match: { nodes.$master.ingest.processors.2.type: date } - - match: { nodes.$master.ingest.processors.3.type: date_index_name } - - match: { nodes.$master.ingest.processors.4.type: dot_expander } - - match: { nodes.$master.ingest.processors.5.type: fail } - - match: { nodes.$master.ingest.processors.6.type: foreach } - - match: { nodes.$master.ingest.processors.7.type: grok } - - match: { nodes.$master.ingest.processors.8.type: gsub } - - match: { nodes.$master.ingest.processors.9.type: join } - - match: { nodes.$master.ingest.processors.10.type: json } - - match: { nodes.$master.ingest.processors.11.type: kv } - - match: { nodes.$master.ingest.processors.12.type: lowercase } - - match: { nodes.$master.ingest.processors.13.type: remove } - - match: { nodes.$master.ingest.processors.14.type: rename } - - match: { nodes.$master.ingest.processors.15.type: script } - - match: { nodes.$master.ingest.processors.16.type: set } - - match: { nodes.$master.ingest.processors.17.type: sort } - - match: { nodes.$master.ingest.processors.18.type: split } - - match: { nodes.$master.ingest.processors.19.type: trim } - - match: { nodes.$master.ingest.processors.20.type: uppercase } + - contains: { nodes.$master.modules: { name: ingest-common } } + - contains: { nodes.$master.ingest.processors: { type: append } } + - contains: { nodes.$master.ingest.processors: { type: convert } } + - contains: { nodes.$master.ingest.processors: { type: date } } + - contains: { nodes.$master.ingest.processors: { type: date_index_name } } + - contains: { nodes.$master.ingest.processors: { type: dot_expander } } + - contains: { nodes.$master.ingest.processors: { type: fail } } + - contains: { nodes.$master.ingest.processors: { type: foreach } } + - contains: { nodes.$master.ingest.processors: { type: grok } } + - contains: { nodes.$master.ingest.processors: { type: gsub } } + - contains: { nodes.$master.ingest.processors: { type: join } } + - contains: { nodes.$master.ingest.processors: { type: json } } + - contains: { nodes.$master.ingest.processors: { type: kv } } + - contains: { nodes.$master.ingest.processors: { type: lowercase } } + - contains: { nodes.$master.ingest.processors: { type: remove } } + - contains: { nodes.$master.ingest.processors: { type: rename } } + - contains: { nodes.$master.ingest.processors: { type: script } } + - contains: { nodes.$master.ingest.processors: { type: set } } + - contains: { nodes.$master.ingest.processors: { type: sort } } + - contains: { nodes.$master.ingest.processors: { type: split } } + - contains: { nodes.$master.ingest.processors: { type: trim } } + - contains: { nodes.$master.ingest.processors: { type: uppercase } } diff --git a/modules/lang-expression/src/test/resources/rest-api-spec/test/lang_expression/10_basic.yml b/modules/lang-expression/src/test/resources/rest-api-spec/test/lang_expression/10_basic.yml index cc777bd826bbc..0ca21cab93089 100644 --- a/modules/lang-expression/src/test/resources/rest-api-spec/test/lang_expression/10_basic.yml +++ b/modules/lang-expression/src/test/resources/rest-api-spec/test/lang_expression/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: lang-expression } + - contains: { nodes.$master.modules: { name: lang-expression } } diff --git a/modules/lang-mustache/src/test/resources/rest-api-spec/test/lang_mustache/10_basic.yml b/modules/lang-mustache/src/test/resources/rest-api-spec/test/lang_mustache/10_basic.yml index 5deabe038906d..1a014e9cceaa6 100644 --- a/modules/lang-mustache/src/test/resources/rest-api-spec/test/lang_mustache/10_basic.yml +++ b/modules/lang-mustache/src/test/resources/rest-api-spec/test/lang_mustache/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: lang-mustache } + - contains: { nodes.$master.modules: { name: lang-mustache } } diff --git a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/10_basic.yml b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/10_basic.yml index 1c81782f33a67..6d008a484ee3f 100644 --- a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/10_basic.yml +++ b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: lang-painless } + - contains: { nodes.$master.modules: { name: lang-painless } } diff --git a/modules/repository-url/src/test/resources/rest-api-spec/test/repository_url/10_basic.yml b/modules/repository-url/src/test/resources/rest-api-spec/test/repository_url/10_basic.yml index 7edbc4c08fbf7..2def885234c3e 100644 --- a/modules/repository-url/src/test/resources/rest-api-spec/test/repository_url/10_basic.yml +++ b/modules/repository-url/src/test/resources/rest-api-spec/test/repository_url/10_basic.yml @@ -112,7 +112,7 @@ teardown: - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: repository-url } + - contains: { nodes.$master.modules: { name: repository-url } } --- "Restore with repository-url using http://": diff --git a/modules/transport-netty4/src/test/resources/rest-api-spec/test/10_basic.yml b/modules/transport-netty4/src/test/resources/rest-api-spec/test/10_basic.yml index e74b7f58c7520..e8b23fa71408b 100644 --- a/modules/transport-netty4/src/test/resources/rest-api-spec/test/10_basic.yml +++ b/modules/transport-netty4/src/test/resources/rest-api-spec/test/10_basic.yml @@ -10,7 +10,7 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.0.name: transport-netty4 } + - contains: { nodes.$master.modules: { name: transport-netty4 } } - do: cluster.stats: {} diff --git a/plugins/discovery-azure-classic/src/test/resources/rest-api-spec/test/discovery_azure_classic/10_basic.yml b/plugins/discovery-azure-classic/src/test/resources/rest-api-spec/test/discovery_azure_classic/10_basic.yml index ea042d8a52da8..6d12da177ea66 100644 --- a/plugins/discovery-azure-classic/src/test/resources/rest-api-spec/test/discovery_azure_classic/10_basic.yml +++ b/plugins/discovery-azure-classic/src/test/resources/rest-api-spec/test/discovery_azure_classic/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: discovery-azure-classic } + - contains: { nodes.$master.plugins: { name: discovery-azure-classic } } diff --git a/plugins/discovery-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml b/plugins/discovery-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml index d612c75db979c..3c5866663b94b 100644 --- a/plugins/discovery-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml +++ b/plugins/discovery-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: discovery-ec2 } + - contains: { nodes.$master.plugins: { name: discovery-ec2 } } diff --git a/plugins/discovery-file/build.gradle b/plugins/discovery-file/build.gradle index 529b8cbef304d..e7f2b3442716f 100644 --- a/plugins/discovery-file/build.gradle +++ b/plugins/discovery-file/build.gradle @@ -38,7 +38,7 @@ task setupSeedNodeAndUnicastHostsFile(type: DefaultTask) { // setup the initial cluster with one node that will serve as the seed node // for unicast discovery ClusterConfiguration config = new ClusterConfiguration(project) -config.distribution = 'integ-test-zip' +config.distribution = System.getProperty('tests.distribution', 'integ-test-zip') config.clusterName = 'discovery-file-test-cluster' List nodes = ClusterFormationTasks.setup(project, 'initialCluster', setupSeedNodeAndUnicastHostsFile, config) File srcUnicastHostsFile = file('build/cluster/unicast_hosts.txt') diff --git a/plugins/discovery-gce/src/test/resources/rest-api-spec/test/discovery_gce/10_basic.yml b/plugins/discovery-gce/src/test/resources/rest-api-spec/test/discovery_gce/10_basic.yml index 6f48aa6c29e90..f16599c40fa32 100644 --- a/plugins/discovery-gce/src/test/resources/rest-api-spec/test/discovery_gce/10_basic.yml +++ b/plugins/discovery-gce/src/test/resources/rest-api-spec/test/discovery_gce/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: discovery-gce } + - contains: { nodes.$master.plugins: { name: discovery-gce } } diff --git a/plugins/examples/painless-whitelist/build.gradle b/plugins/examples/painless-whitelist/build.gradle index 12bbff8b0419e..ef1ca7d741e9a 100644 --- a/plugins/examples/painless-whitelist/build.gradle +++ b/plugins/examples/painless-whitelist/build.gradle @@ -30,8 +30,8 @@ dependencies { compileOnly project(':modules:lang-painless') } -integTestCluster { - distribution = 'zip' +if (System.getProperty('tests.distribution') == null) { + integTestCluster.distribution = 'oss-zip' } test.enabled = false diff --git a/plugins/examples/painless-whitelist/src/test/resources/rest-api-spec/test/painless_whitelist/10_basic.yml b/plugins/examples/painless-whitelist/src/test/resources/rest-api-spec/test/painless_whitelist/10_basic.yml index f0abcf117da15..a915c08067e5c 100644 --- a/plugins/examples/painless-whitelist/src/test/resources/rest-api-spec/test/painless_whitelist/10_basic.yml +++ b/plugins/examples/painless-whitelist/src/test/resources/rest-api-spec/test/painless_whitelist/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: painless-whitelist } + - contains: { nodes.$master.plugins: { name: painless-whitelist } } diff --git a/plugins/examples/rescore/src/test/resources/rest-api-spec/test/example-rescore/10_basic.yml b/plugins/examples/rescore/src/test/resources/rest-api-spec/test/example-rescore/10_basic.yml index 75c22d6b578bd..62a47df9d7869 100644 --- a/plugins/examples/rescore/src/test/resources/rest-api-spec/test/example-rescore/10_basic.yml +++ b/plugins/examples/rescore/src/test/resources/rest-api-spec/test/example-rescore/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: example-rescore } + - contains: { nodes.$master.plugins: { name: example-rescore } } diff --git a/plugins/examples/script-expert-scoring/src/test/resources/rest-api-spec/test/script_expert_scoring/10_basic.yml b/plugins/examples/script-expert-scoring/src/test/resources/rest-api-spec/test/script_expert_scoring/10_basic.yml index b4fafd69dd4ab..26980a95b730b 100644 --- a/plugins/examples/script-expert-scoring/src/test/resources/rest-api-spec/test/script_expert_scoring/10_basic.yml +++ b/plugins/examples/script-expert-scoring/src/test/resources/rest-api-spec/test/script_expert_scoring/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: script-expert-scoring } + - contains: { nodes.$master.plugins: { name: script-expert-scoring } } diff --git a/plugins/ingest-attachment/src/test/resources/rest-api-spec/test/ingest_attachment/10_basic.yml b/plugins/ingest-attachment/src/test/resources/rest-api-spec/test/ingest_attachment/10_basic.yml index 88accac7730e7..42be90f77f944 100644 --- a/plugins/ingest-attachment/src/test/resources/rest-api-spec/test/ingest_attachment/10_basic.yml +++ b/plugins/ingest-attachment/src/test/resources/rest-api-spec/test/ingest_attachment/10_basic.yml @@ -7,6 +7,6 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: ingest-attachment } - - match: { nodes.$master.ingest.processors.0.type: attachment } + - contains: { 'nodes.$master.plugins': { name: ingest-attachment } } + - contains: { 'nodes.$master.ingest.processors': { type: attachment } } diff --git a/plugins/ingest-geoip/src/test/resources/rest-api-spec/test/ingest_geoip/10_basic.yml b/plugins/ingest-geoip/src/test/resources/rest-api-spec/test/ingest_geoip/10_basic.yml index 7a06326a86411..413745eab4051 100644 --- a/plugins/ingest-geoip/src/test/resources/rest-api-spec/test/ingest_geoip/10_basic.yml +++ b/plugins/ingest-geoip/src/test/resources/rest-api-spec/test/ingest_geoip/10_basic.yml @@ -7,5 +7,5 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: ingest-geoip } - - match: { nodes.$master.ingest.processors.0.type: geoip } + - contains: { nodes.$master.plugins: { name: ingest-geoip } } + - contains: { nodes.$master.ingest.processors: { type: geoip } } diff --git a/plugins/ingest-user-agent/src/test/resources/rest-api-spec/test/ingest-useragent/10_basic.yml b/plugins/ingest-user-agent/src/test/resources/rest-api-spec/test/ingest-useragent/10_basic.yml index fee3173f39335..4cb1c9b1fba20 100644 --- a/plugins/ingest-user-agent/src/test/resources/rest-api-spec/test/ingest-useragent/10_basic.yml +++ b/plugins/ingest-user-agent/src/test/resources/rest-api-spec/test/ingest-useragent/10_basic.yml @@ -7,5 +7,5 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: ingest-user-agent } - - match: { nodes.$master.ingest.processors.0.type: user_agent } + - contains: { nodes.$master.plugins: { name: ingest-user-agent } } + - contains: { nodes.$master.ingest.processors: { type: user_agent } } diff --git a/plugins/repository-azure/src/test/resources/rest-api-spec/test/repository_azure/10_basic.yml b/plugins/repository-azure/src/test/resources/rest-api-spec/test/repository_azure/10_basic.yml index 3a754a34a8a14..199d543dda87e 100644 --- a/plugins/repository-azure/src/test/resources/rest-api-spec/test/repository_azure/10_basic.yml +++ b/plugins/repository-azure/src/test/resources/rest-api-spec/test/repository_azure/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: repository-azure } + - contains: { nodes.$master.plugins: { name: repository-azure } } diff --git a/plugins/repository-gcs/src/test/resources/rest-api-spec/test/repository_gcs/10_basic.yml b/plugins/repository-gcs/src/test/resources/rest-api-spec/test/repository_gcs/10_basic.yml index f4259771644b2..5c8fa70bb7a5f 100644 --- a/plugins/repository-gcs/src/test/resources/rest-api-spec/test/repository_gcs/10_basic.yml +++ b/plugins/repository-gcs/src/test/resources/rest-api-spec/test/repository_gcs/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: repository-gcs } + - contains: { nodes.$master.plugins: { name: repository-gcs } } diff --git a/plugins/repository-hdfs/build.gradle b/plugins/repository-hdfs/build.gradle index 304e0f4ae0e1f..8856ae1526a21 100644 --- a/plugins/repository-hdfs/build.gradle +++ b/plugins/repository-hdfs/build.gradle @@ -158,7 +158,6 @@ for (String fixtureName : ['hdfsFixture', 'haHdfsFixture', 'secureHdfsFixture', project.afterEvaluate { for (String integTestTaskName : ['integTestHa', 'integTestSecure', 'integTestSecureHa']) { ClusterConfiguration cluster = project.extensions.getByName("${integTestTaskName}Cluster") as ClusterConfiguration - cluster.distribution = 'integ-test-zip' cluster.dependsOn(project.bundlePlugin) Task restIntegTestTask = project.tasks.getByName(integTestTaskName) diff --git a/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/hdfs_repository/10_basic.yml b/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/hdfs_repository/10_basic.yml index 6fbbfc82e872d..f11e0148402cf 100644 --- a/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/hdfs_repository/10_basic.yml +++ b/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/hdfs_repository/10_basic.yml @@ -12,7 +12,7 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: repository-hdfs } + - contains: { nodes.$master.plugins: { name: repository-hdfs } } --- # # Check that we can't use file:// repositories or anything like that diff --git a/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/secure_hdfs_repository/10_basic.yml b/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/secure_hdfs_repository/10_basic.yml index 6fbbfc82e872d..f11e0148402cf 100644 --- a/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/secure_hdfs_repository/10_basic.yml +++ b/plugins/repository-hdfs/src/test/resources/rest-api-spec/test/secure_hdfs_repository/10_basic.yml @@ -12,7 +12,7 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: repository-hdfs } + - contains: { nodes.$master.plugins: { name: repository-hdfs } } --- # # Check that we can't use file:// repositories or anything like that diff --git a/plugins/repository-s3/src/test/resources/rest-api-spec/test/repository_s3/10_basic.yml b/plugins/repository-s3/src/test/resources/rest-api-spec/test/repository_s3/10_basic.yml index 7bb65a508863d..190a628f0b375 100644 --- a/plugins/repository-s3/src/test/resources/rest-api-spec/test/repository_s3/10_basic.yml +++ b/plugins/repository-s3/src/test/resources/rest-api-spec/test/repository_s3/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: repository-s3 } + - contains: { nodes.$master.plugins: { name: repository-s3 } } diff --git a/plugins/store-smb/src/test/resources/rest-api-spec/test/store_smb/10_basic.yml b/plugins/store-smb/src/test/resources/rest-api-spec/test/store_smb/10_basic.yml index a210fd4e5970d..60228c1b92356 100644 --- a/plugins/store-smb/src/test/resources/rest-api-spec/test/store_smb/10_basic.yml +++ b/plugins/store-smb/src/test/resources/rest-api-spec/test/store_smb/10_basic.yml @@ -10,4 +10,4 @@ - do: nodes.info: {} - - match: { nodes.$master.plugins.0.name: store-smb } + - contains: { nodes.$master.plugins: { name: store-smb } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ContainsAssertion.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ContainsAssertion.java new file mode 100644 index 0000000000000..9d2d91790c7c2 --- /dev/null +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ContainsAssertion.java @@ -0,0 +1,80 @@ +/* + * 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.test.rest.yaml.section; + +import org.apache.logging.log4j.Logger; +import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.common.xcontent.XContentLocation; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class ContainsAssertion extends Assertion { + public static ContainsAssertion parse(XContentParser parser) throws IOException { + XContentLocation location = parser.getTokenLocation(); + Tuple stringObjectTuple = ParserUtils.parseTuple(parser); + return new ContainsAssertion(location, stringObjectTuple.v1(), stringObjectTuple.v2()); + } + + private static final Logger logger = Loggers.getLogger(ContainsAssertion.class); + + public ContainsAssertion(XContentLocation location, String field, Object expectedValue) { + super(location, field, expectedValue); + } + + @Override + protected void doAssert(Object actualValue, Object expectedValue) { + // add support for matching objects ({a:b}) against list of objects ([ {a:b, c:d} ]) + if(expectedValue instanceof Map && actualValue instanceof List) { + logger.trace("assert that [{}] contains [{}]", actualValue, expectedValue); + Map expectedMap = (Map) expectedValue; + List actualList = (List) actualValue; + List> actualValues = actualList.stream() + .filter(each -> each instanceof Map) + .map((each -> (Map) each)) + .filter(each -> each.keySet().containsAll(expectedMap.keySet())) + .collect(Collectors.toList()); + assertThat( + getField() + " expected to be a list with at least one object that has keys: " + + expectedMap.keySet() + " but it was " + actualList, + actualValues, + is(not(empty())) + ); + assertTrue( + getField() + " expected to be a list with at least on object that matches " + expectedMap + + " but was " + actualValues, + actualValues.stream() + .anyMatch(each -> each.entrySet().containsAll(expectedMap.entrySet())) + ); + } else { + fail("'contains' only supports checking an object against a list of objects"); + } + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ExecutableSection.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ExecutableSection.java index ce5ea1c1cde06..ff02d6d16aa4a 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ExecutableSection.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ExecutableSection.java @@ -47,6 +47,7 @@ public interface ExecutableSection { new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("gte"), GreaterThanEqualToAssertion::parse), new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("lt"), LessThanAssertion::parse), new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("lte"), LessThanOrEqualToAssertion::parse), + new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("contains"), ContainsAssertion::parse), new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("length"), LengthAssertion::parse))); /** diff --git a/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/AssertionTests.java b/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/AssertionTests.java index fcef74678359e..ddf153ff44f5c 100644 --- a/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/AssertionTests.java +++ b/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/AssertionTests.java @@ -134,6 +134,22 @@ public void testParseMatchArray() throws Exception { assertThat(strings.get(1).toString(), equalTo("test_percolator_2")); } + @SuppressWarnings("unchecked") + public void testParseContains() throws Exception { + parser = createParser(YamlXContent.yamlXContent, + "{testKey: { someKey: someValue } }" + ); + + ContainsAssertion containsAssertion = ContainsAssertion.parse(parser); + assertThat(containsAssertion, notNullValue()); + assertThat(containsAssertion.getField(), equalTo("testKey")); + assertThat(containsAssertion.getExpectedValue(), instanceOf(Map.class)); + assertThat( + ((Map) containsAssertion.getExpectedValue()).get("someKey"), + equalTo("someValue") + ); + } + @SuppressWarnings("unchecked") public void testParseMatchSourceValues() throws Exception { parser = createParser(YamlXContent.yamlXContent, diff --git a/x-pack/plugin/build.gradle b/x-pack/plugin/build.gradle index ac423c4281138..3822ef1d4d584 100644 --- a/x-pack/plugin/build.gradle +++ b/x-pack/plugin/build.gradle @@ -192,3 +192,7 @@ integTestCluster { return tmpFile.exists() } } +if (integTestCluster.distribution.startsWith("oss-") == false) { + integTest.enabled = false +} + diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/10_basic.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/10_basic.yml index 8958af0ff4486..1e3fc8407998c 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/10_basic.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/10_basic.yml @@ -10,14 +10,14 @@ - do: nodes.info: {} - - match: { nodes.$master.modules.13.name: x-pack-core } - - match: { nodes.$master.modules.14.name: x-pack-deprecation } - - match: { nodes.$master.modules.15.name: x-pack-graph } - - match: { nodes.$master.modules.16.name: x-pack-logstash } - - match: { nodes.$master.modules.17.name: x-pack-ml } - - match: { nodes.$master.modules.18.name: x-pack-monitoring } - - match: { nodes.$master.modules.19.name: x-pack-rollup } - - match: { nodes.$master.modules.20.name: x-pack-security } - - match: { nodes.$master.modules.21.name: x-pack-sql } - - match: { nodes.$master.modules.22.name: x-pack-upgrade } - - match: { nodes.$master.modules.23.name: x-pack-watcher } + - contains: { nodes.$master.modules: { name: x-pack-core } } + - contains: { nodes.$master.modules: { name: x-pack-deprecation } } + - contains: { nodes.$master.modules: { name: x-pack-graph } } + - contains: { nodes.$master.modules: { name: x-pack-logstash } } + - contains: { nodes.$master.modules: { name: x-pack-ml } } + - contains: { nodes.$master.modules: { name: x-pack-monitoring } } + - contains: { nodes.$master.modules: { name: x-pack-rollup } } + - contains: { nodes.$master.modules: { name: x-pack-security } } + - contains: { nodes.$master.modules: { name: x-pack-sql } } + - contains: { nodes.$master.modules: { name: x-pack-upgrade } } + - contains: { nodes.$master.modules: { name: x-pack-watcher } } From a72dc9e8fc4eeb174ef3d6a20738523b70c2e212 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Tue, 26 Jun 2018 16:14:40 +0200 Subject: [PATCH 18/23] Watcher: Remove never executed code (#31135) The removed code snippet was never executed, as the version was never set and thus always -1, after parsing the watch. With the changes done in c9d77d20fdb8a46b614515555d5d0697b2c6e5fc this logic would not have worked correctly anyway. --- .../xpack/watcher/WatcherIndexingListener.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherIndexingListener.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherIndexingListener.java index 8e0fbcb7cb4fc..f3b77b922aa89 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherIndexingListener.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherIndexingListener.java @@ -110,16 +110,6 @@ public Engine.Index preIndex(ShardId shardId, Engine.Index operation) { return operation; } - // the watch status is -1, in case a watch has been freshly stored and this save - // watch operation does not stem from an execution - // we dont need to update the trigger service, when the watch has been updated as - // part of an execution, so we can exit early - boolean isWatchExecutionOperation = watch.status().version() != -1; - if (isWatchExecutionOperation) { - logger.debug("not updating trigger for watch [{}], watch has been updated as part of an execution", watch.id()); - return operation; - } - boolean shouldBeTriggered = shardAllocationConfiguration.shouldBeTriggered(watch.id()); if (shouldBeTriggered) { if (watch.status().state().isActive()) { From 8a6d0621804c98e61176fd771923dcbfeac8aaa0 Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Tue, 26 Jun 2018 16:24:28 +0200 Subject: [PATCH 19/23] Docs: Clarify sensitive fields watcher encryption (#31551) Clarify the scope of encrypting sensitive settings in watcher, which fields are encrypted and if users can have their own encrypted fields. --- x-pack/docs/en/watcher/encrypting-data.asciidoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/docs/en/watcher/encrypting-data.asciidoc b/x-pack/docs/en/watcher/encrypting-data.asciidoc index 166ef6f14d760..9319c9f793870 100644 --- a/x-pack/docs/en/watcher/encrypting-data.asciidoc +++ b/x-pack/docs/en/watcher/encrypting-data.asciidoc @@ -6,6 +6,12 @@ information or details about your SMTP email service. You can encrypt this data by generating a key and adding some secure settings on each node in your cluster. +Every `password` field that is used in your watch within a HTTP basic +authentication block - for example within a webhook, a HTTP input or when using +the reporting email attachment - will not be stored as plain text anymore. Also +be aware, that there is no way to configure your own fields in a watch to be +encrypted. + To encrypt sensitive data in {watcher}: . Use the {ref}/syskeygen.html[elasticsearch-syskeygen] command to create a system key file. From 823a9d34dafabcfdfc9b1ee7f87f61a9db4f7b1b Mon Sep 17 00:00:00 2001 From: Luca Cavanna Date: Tue, 26 Jun 2018 16:56:35 +0200 Subject: [PATCH 20/23] [TEST] Close additional clients created while running yaml tests (#31575) We recently introduced a mechanism that allows to specify a node selector as part of do sections (see #31471). When a node selector that is not the default one is configured, a new client will be initialized with the same properties as the default one, but with the specified node selector. This commit improves such mechanism but also closing the additional clients being created and adding equals/hashcode impl to the custom node selector as they are cached into a map. --- .../client/HasAttributeNodeSelector.java | 19 +++++++++++++++++++ .../test/rest/yaml/ClientYamlTestClient.java | 18 +++++++++++++----- .../test/rest/yaml/section/DoSection.java | 18 ++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/client/rest/src/main/java/org/elasticsearch/client/HasAttributeNodeSelector.java b/client/rest/src/main/java/org/elasticsearch/client/HasAttributeNodeSelector.java index e4bb43458648b..11232a08c3d29 100644 --- a/client/rest/src/main/java/org/elasticsearch/client/HasAttributeNodeSelector.java +++ b/client/rest/src/main/java/org/elasticsearch/client/HasAttributeNodeSelector.java @@ -22,6 +22,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; /** * A {@link NodeSelector} that selects nodes that have a particular value @@ -49,6 +50,24 @@ public void select(Iterable nodes) { } } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HasAttributeNodeSelector that = (HasAttributeNodeSelector) o; + return Objects.equals(key, that.key) && + Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } + @Override public String toString() { return key + "=" + value; diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ClientYamlTestClient.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ClientYamlTestClient.java index fdc10a1a246e7..2d6bcc8cf5665 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ClientYamlTestClient.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ClientYamlTestClient.java @@ -40,6 +40,7 @@ import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestPath; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestSpec; +import java.io.Closeable; import java.io.IOException; import java.io.UncheckedIOException; import java.net.URI; @@ -56,18 +57,18 @@ * {@link RestClient} instance used to send the REST requests. Holds the {@link ClientYamlSuiteRestSpec} used to translate api calls into * REST calls. */ -public class ClientYamlTestClient { +public class ClientYamlTestClient implements Closeable { private static final Logger logger = Loggers.getLogger(ClientYamlTestClient.class); private static final ContentType YAML_CONTENT_TYPE = ContentType.create("application/yaml"); private final ClientYamlSuiteRestSpec restSpec; - protected final Map restClients = new HashMap<>(); + private final Map restClients = new HashMap<>(); private final Version esVersion; private final Version masterVersion; private final CheckedConsumer clientBuilderConsumer; - public ClientYamlTestClient( + ClientYamlTestClient( final ClientYamlSuiteRestSpec restSpec, final RestClient restClient, final List hosts, @@ -202,10 +203,10 @@ protected RestClient getRestClient(NodeSelector nodeSelector) { RestClientBuilder builder = RestClient.builder(anyClient.getNodes().toArray(new Node[0])); try { clientBuilderConsumer.accept(builder); - } catch(IOException e) { + } catch (IOException e) { throw new UncheckedIOException(e); } - builder.setNodeSelector(nodeSelector); + builder.setNodeSelector(selector); return builder.build(); }); } @@ -247,4 +248,11 @@ private ClientYamlSuiteRestApi restApi(String apiName) { } return restApi; } + + @Override + public void close() throws IOException { + for (RestClient restClient : restClients.values()) { + restClient.close(); + } + } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java index 8697b0bedcdf5..4e46a9ec89fd1 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java @@ -449,6 +449,24 @@ public void select(Iterable nodes) { lhs.select(nodes); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ComposeNodeSelector that = (ComposeNodeSelector) o; + return Objects.equals(lhs, that.lhs) && + Objects.equals(rhs, that.rhs); + } + + @Override + public int hashCode() { + return Objects.hash(lhs, rhs); + } + @Override public String toString() { // . as in haskell's "compose" operator From db90905405297a392707c3137e19f7227462bdd8 Mon Sep 17 00:00:00 2001 From: Alpar Torok Date: Tue, 26 Jun 2018 18:16:24 +0300 Subject: [PATCH 21/23] reduce log level at gradle configuration time --- .../org/elasticsearch/gradle/test/ClusterFormationTasks.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy index 336db08a019bb..be0fb3a07c699 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy @@ -536,7 +536,7 @@ class ClusterFormationTasks { static Task configureInstallModuleTask(String name, Project project, Task setup, NodeInfo node, Project module) { if (node.config.distribution != 'integ-test-zip') { - project.logger.lifecycle("Not installing modules for $name, ${node.config.distribution} already has them") + project.logger.info("Not installing modules for $name, ${node.config.distribution} already has them") return setup } if (module.plugins.hasPlugin(PluginBuildPlugin) == false) { From 26a927a120010c33273c845d0026f6c98e489012 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Tue, 26 Jun 2018 10:15:56 -0700 Subject: [PATCH 22/23] Fix a formatting issue in the docvalue_fields documentation. (#31563) --- docs/reference/search/request/docvalue-fields.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/search/request/docvalue-fields.asciidoc b/docs/reference/search/request/docvalue-fields.asciidoc index 9d917c27ab084..fa5baf1db2262 100644 --- a/docs/reference/search/request/docvalue-fields.asciidoc +++ b/docs/reference/search/request/docvalue-fields.asciidoc @@ -37,6 +37,7 @@ causing the terms for that field to be loaded to memory (cached), which will res ==== Custom formats While most fields do not support custom formats, some of them do: + - <> fields can take any <>. - <> fields accept a https://docs.oracle.com/javase/8/docs/api/java/text/DecimalFormat.html[DecimalFormat pattern]. From 13e1cf61917285ee0f16d4c28818daeae6607525 Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Tue, 26 Jun 2018 20:04:41 +0200 Subject: [PATCH 23/23] ingest: Add ignore_missing property to foreach filter (#22147) (#31578) --- docs/reference/ingest/ingest-node.asciidoc | 7 +-- .../ingest/common/ForEachProcessor.java | 20 ++++++-- .../common/ForEachProcessorFactoryTests.java | 18 +++++++ .../ingest/common/ForEachProcessorTests.java | 48 ++++++++++++------- 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/docs/reference/ingest/ingest-node.asciidoc b/docs/reference/ingest/ingest-node.asciidoc index 009a67699e344..29ff039950925 100644 --- a/docs/reference/ingest/ingest-node.asciidoc +++ b/docs/reference/ingest/ingest-node.asciidoc @@ -1075,9 +1075,10 @@ then it aborts the execution and leaves the array unmodified. .Foreach Options [options="header"] |====== -| Name | Required | Default | Description -| `field` | yes | - | The array field -| `processor` | yes | - | The processor to execute against each field +| Name | Required | Default | Description +| `field` | yes | - | The array field +| `processor` | yes | - | The processor to execute against each field +| `ignore_missing` | no | false | If `true` and `field` does not exist or is `null`, the processor quietly exits without modifying the document |====== Assume the following document: diff --git a/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java b/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java index 2a1046acb9cdb..1c64fdb7408ef 100644 --- a/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java +++ b/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java @@ -30,6 +30,7 @@ import java.util.Set; import static org.elasticsearch.ingest.ConfigurationUtils.newConfigurationException; +import static org.elasticsearch.ingest.ConfigurationUtils.readBooleanProperty; import static org.elasticsearch.ingest.ConfigurationUtils.readMap; import static org.elasticsearch.ingest.ConfigurationUtils.readStringProperty; @@ -47,16 +48,28 @@ public final class ForEachProcessor extends AbstractProcessor { private final String field; private final Processor processor; + private final boolean ignoreMissing; - ForEachProcessor(String tag, String field, Processor processor) { + ForEachProcessor(String tag, String field, Processor processor, boolean ignoreMissing) { super(tag); this.field = field; this.processor = processor; + this.ignoreMissing = ignoreMissing; + } + + boolean isIgnoreMissing() { + return ignoreMissing; } @Override public void execute(IngestDocument ingestDocument) throws Exception { - List values = ingestDocument.getFieldValue(field, List.class); + List values = ingestDocument.getFieldValue(field, List.class, ignoreMissing); + if (values == null) { + if (ignoreMissing) { + return; + } + throw new IllegalArgumentException("field [" + field + "] is null, cannot loop over its elements."); + } List newValues = new ArrayList<>(values.size()); for (Object value : values) { Object previousValue = ingestDocument.getIngestMetadata().put("_value", value); @@ -87,6 +100,7 @@ public static final class Factory implements Processor.Factory { public ForEachProcessor create(Map factories, String tag, Map config) throws Exception { String field = readStringProperty(TYPE, tag, config, "field"); + boolean ignoreMissing = readBooleanProperty(TYPE, tag, config, "ignore_missing", false); Map> processorConfig = readMap(TYPE, tag, config, "processor"); Set>> entries = processorConfig.entrySet(); if (entries.size() != 1) { @@ -94,7 +108,7 @@ public ForEachProcessor create(Map factories, String } Map.Entry> entry = entries.iterator().next(); Processor processor = ConfigurationUtils.readProcessor(factories, entry.getKey(), entry.getValue()); - return new ForEachProcessor(tag, field, processor); + return new ForEachProcessor(tag, field, processor, ignoreMissing); } } } diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorFactoryTests.java index 49611d76f4081..f382ad8dcfb6a 100644 --- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorFactoryTests.java +++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorFactoryTests.java @@ -46,6 +46,24 @@ public void testCreate() throws Exception { assertThat(forEachProcessor, Matchers.notNullValue()); assertThat(forEachProcessor.getField(), equalTo("_field")); assertThat(forEachProcessor.getProcessor(), Matchers.sameInstance(processor)); + assertFalse(forEachProcessor.isIgnoreMissing()); + } + + public void testSetIgnoreMissing() throws Exception { + Processor processor = new TestProcessor(ingestDocument -> { }); + Map registry = new HashMap<>(); + registry.put("_name", (r, t, c) -> processor); + ForEachProcessor.Factory forEachFactory = new ForEachProcessor.Factory(); + + Map config = new HashMap<>(); + config.put("field", "_field"); + config.put("processor", Collections.singletonMap("_name", Collections.emptyMap())); + config.put("ignore_missing", true); + ForEachProcessor forEachProcessor = forEachFactory.create(registry, null, config); + assertThat(forEachProcessor, Matchers.notNullValue()); + assertThat(forEachProcessor.getField(), equalTo("_field")); + assertThat(forEachProcessor.getProcessor(), Matchers.sameInstance(processor)); + assertTrue(forEachProcessor.isIgnoreMissing()); } public void testCreateWithTooManyProcessorTypes() throws Exception { diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorTests.java index 07573a780a17a..1491bd481bd07 100644 --- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorTests.java +++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ForEachProcessorTests.java @@ -19,14 +19,6 @@ package org.elasticsearch.ingest.common; -import org.elasticsearch.ingest.CompoundProcessor; -import org.elasticsearch.ingest.IngestDocument; -import org.elasticsearch.ingest.Processor; -import org.elasticsearch.ingest.TestProcessor; -import org.elasticsearch.ingest.TestTemplateService; -import org.elasticsearch.script.TemplateScript; -import org.elasticsearch.test.ESTestCase; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -34,7 +26,15 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import org.elasticsearch.ingest.CompoundProcessor; +import org.elasticsearch.ingest.IngestDocument; +import org.elasticsearch.ingest.Processor; +import org.elasticsearch.ingest.TestProcessor; +import org.elasticsearch.ingest.TestTemplateService; +import org.elasticsearch.script.TemplateScript; +import org.elasticsearch.test.ESTestCase; +import static org.elasticsearch.ingest.IngestDocumentMatcher.assertIngestDocument; import static org.hamcrest.Matchers.equalTo; public class ForEachProcessorTests extends ESTestCase { @@ -49,7 +49,8 @@ public void testExecute() throws Exception { ); ForEachProcessor processor = new ForEachProcessor( - "_tag", "values", new UppercaseProcessor("_tag", "_ingest._value", false, "_ingest._value") + "_tag", "values", new UppercaseProcessor("_tag", "_ingest._value", false, "_ingest._value"), + false ); processor.execute(ingestDocument); @@ -69,7 +70,7 @@ public void testExecuteWithFailure() throws Exception { throw new RuntimeException("failure"); } }); - ForEachProcessor processor = new ForEachProcessor("_tag", "values", testProcessor); + ForEachProcessor processor = new ForEachProcessor("_tag", "values", testProcessor, false); try { processor.execute(ingestDocument); fail("exception expected"); @@ -89,7 +90,8 @@ public void testExecuteWithFailure() throws Exception { }); Processor onFailureProcessor = new TestProcessor(ingestDocument1 -> {}); processor = new ForEachProcessor( - "_tag", "values", new CompoundProcessor(false, Arrays.asList(testProcessor), Arrays.asList(onFailureProcessor)) + "_tag", "values", new CompoundProcessor(false, Arrays.asList(testProcessor), Arrays.asList(onFailureProcessor)), + false ); processor.execute(ingestDocument); assertThat(testProcessor.getInvokedCounter(), equalTo(3)); @@ -109,7 +111,7 @@ public void testMetaDataAvailable() throws Exception { id.setFieldValue("_ingest._value.type", id.getSourceAndMetadata().get("_type")); id.setFieldValue("_ingest._value.id", id.getSourceAndMetadata().get("_id")); }); - ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor); + ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor, false); processor.execute(ingestDocument); assertThat(innerProcessor.getInvokedCounter(), equalTo(2)); @@ -137,7 +139,7 @@ public void testRestOfTheDocumentIsAvailable() throws Exception { ForEachProcessor processor = new ForEachProcessor( "_tag", "values", new SetProcessor("_tag", new TestTemplateService.MockTemplateScript.Factory("_ingest._value.new_field"), - (model) -> model.get("other"))); + (model) -> model.get("other")), false); processor.execute(ingestDocument); assertThat(ingestDocument.getFieldValue("values.0.new_field", String.class), equalTo("value")); @@ -174,7 +176,7 @@ public String getTag() { "_index", "_type", "_id", null, null, null, Collections.singletonMap("values", values) ); - ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor); + ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor, false); processor.execute(ingestDocument); @SuppressWarnings("unchecked") List result = ingestDocument.getFieldValue("values", List.class); @@ -199,7 +201,7 @@ public void testModifyFieldsOutsideArray() throws Exception { "_tag", "values", new CompoundProcessor(false, Collections.singletonList(new UppercaseProcessor("_tag_upper", "_ingest._value", false, "_ingest._value")), Collections.singletonList(new AppendProcessor("_tag", template, (model) -> (Collections.singletonList("added")))) - )); + ), false); processor.execute(ingestDocument); List result = ingestDocument.getFieldValue("values", List.class); @@ -225,7 +227,7 @@ public void testScalarValueAllowsUnderscoreValueFieldToRemainAccessible() throws TestProcessor processor = new TestProcessor(doc -> doc.setFieldValue("_ingest._value", doc.getFieldValue("_source._value", String.class))); - ForEachProcessor forEachProcessor = new ForEachProcessor("_tag", "values", processor); + ForEachProcessor forEachProcessor = new ForEachProcessor("_tag", "values", processor, false); forEachProcessor.execute(ingestDocument); List result = ingestDocument.getFieldValue("values", List.class); @@ -258,7 +260,7 @@ public void testNestedForEach() throws Exception { doc -> doc.setFieldValue("_ingest._value", doc.getFieldValue("_ingest._value", String.class).toUpperCase(Locale.ENGLISH)) ); ForEachProcessor processor = new ForEachProcessor( - "_tag", "values1", new ForEachProcessor("_tag", "_ingest._value.values2", testProcessor)); + "_tag", "values1", new ForEachProcessor("_tag", "_ingest._value.values2", testProcessor, false), false); processor.execute(ingestDocument); List result = ingestDocument.getFieldValue("values1.0.values2", List.class); @@ -270,4 +272,16 @@ public void testNestedForEach() throws Exception { assertThat(result.get(1), equalTo("JKL")); } + public void testIgnoreMissing() throws Exception { + IngestDocument originalIngestDocument = new IngestDocument( + "_index", "_type", "_id", null, null, null, Collections.emptyMap() + ); + IngestDocument ingestDocument = new IngestDocument(originalIngestDocument); + TestProcessor testProcessor = new TestProcessor(doc -> {}); + ForEachProcessor processor = new ForEachProcessor("_tag", "_ingest._value", testProcessor, true); + processor.execute(ingestDocument); + assertIngestDocument(originalIngestDocument, ingestDocument); + assertThat(testProcessor.getInvokedCounter(), equalTo(0)); + } + }