diff --git a/dev-tools/ci b/dev-tools/ci index 189abfe2f83..15ef5dcf6a0 100755 --- a/dev-tools/ci +++ b/dev-tools/ci @@ -53,13 +53,15 @@ case $key in "-psql" "check" ":x-pack-elasticsearch:plugin:precommit" - ":x-pack-elasticsearch:qa:sql-multinode:check" - ":x-pack-elasticsearch:qa:sql-no-security:check" - ":x-pack-elasticsearch:qa:sql-security:check" + ":x-pack-elasticsearch:qa:sql:check" + ":x-pack-elasticsearch:qa:sql:multinode:check" + ":x-pack-elasticsearch:qa:sql:no-security:check" + ":x-pack-elasticsearch:qa:sql:security:check" "-xforbiddenPatterns" "-x:x-pack-elasticsearch:plugin:forbiddenPatterns" - "-x:x-pack-elasticsearch:qa:sql-no-security:forbiddenPatterns" - "-x:x-pack-elasticsearch:qa:sql-security:forbiddenPatterns" + "-x:x-pack-elasticsearch:qa:sql:forbiddenPatterns" + "-x:x-pack-elasticsearch:qa:sql:no-security:forbiddenPatterns" + "-x:x-pack-elasticsearch:qa:sql:security:forbiddenPatterns" ) ;; jdk9) diff --git a/qa/sql-multinode/build.gradle b/qa/sql-multinode/build.gradle deleted file mode 100644 index f202cf482f2..00000000000 --- a/qa/sql-multinode/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -import org.elasticsearch.gradle.test.RunTask - -apply plugin: 'elasticsearch.standalone-rest-test' -apply plugin: 'elasticsearch.rest-test' - -dependencies { - testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'runtime') - testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'testArtifacts') - testCompile project(path: ':modules:reindex') -} - -// NOCOMMIT we should try this on multiple nodes - -integTestCluster { - distribution = 'zip' // NOCOMMIT make double sure we want all the modules - numNodes = 2 - plugin ':x-pack-elasticsearch:plugin' - setting 'xpack.ml.enabled', 'false' - setting 'xpack.monitoring.enabled', 'false' - setting 'xpack.security.enabled', 'false' -} diff --git a/qa/sql-no-security/build.gradle b/qa/sql-no-security/build.gradle deleted file mode 100644 index c180eb1b299..00000000000 --- a/qa/sql-no-security/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -import org.elasticsearch.gradle.test.RunTask - -apply plugin: 'elasticsearch.standalone-rest-test' -apply plugin: 'elasticsearch.rest-test' - -integTestCluster { - distribution = 'zip' // NOCOMMIT make double sure we want all the modules - plugin project(':x-pack-elasticsearch:plugin').path - /* Get a "clean" test without the other x-pack features here and check them - * all together later on. */ - setting 'xpack.security.enabled', 'false' - setting 'xpack.monitoring.enabled', 'false' - setting 'xpack.ml.enabled', 'false' - setting 'xpack.watcher.enabled', 'false' - setting 'script.max_compilations_per_minute', '1000' -} - -task run(type: RunTask) { - distribution = 'zip' // NOCOMMIT make double sure we want all the modules - plugin project(':x-pack-elasticsearch:plugin').path - /* Get a "clean" test without the other x-pack features here and check them - * all together later on. */ - setting 'xpack.security.enabled', 'false' - setting 'xpack.monitoring.enabled', 'false' - setting 'xpack.ml.enabled', 'false' - setting 'xpack.watcher.enabled', 'false' - setting 'script.max_compilations_per_minute', '1000' -} diff --git a/qa/sql/build.gradle b/qa/sql/build.gradle new file mode 100644 index 00000000000..60558bc2611 --- /dev/null +++ b/qa/sql/build.gradle @@ -0,0 +1,52 @@ +import org.elasticsearch.gradle.precommit.PrecommitTasks +import org.elasticsearch.gradle.test.RunTask + +description = 'Integration tests for SQL' +apply plugin: 'elasticsearch.build' + +dependencies { + compile project(path: ':x-pack-elasticsearch:plugin', configuration: 'runtime') + compile project(path: ':x-pack-elasticsearch:plugin', configuration: 'testArtifacts') + compile "org.elasticsearch.test:framework:${versions.elasticsearch}" +} + +// the main files are actually test files, so use the appropriate forbidden api sigs +forbiddenApisMain { + signaturesURLs = [PrecommitTasks.getResource('/forbidden/es-all-signatures.txt'), + PrecommitTasks.getResource('/forbidden/es-test-signatures.txt')] +} + +// just test utilities +test.enabled = false + +dependencyLicenses.enabled = false + +subprojects { + apply plugin: 'elasticsearch.standalone-rest-test' + apply plugin: 'elasticsearch.rest-test' + + dependencies { + testCompile project(path: ':x-pack-elasticsearch:qa:sql') + testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'runtime') + testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'testArtifacts') + testCompile "org.elasticsearch.test:framework:${versions.elasticsearch}" + } + + integTestCluster { + distribution = 'zip' + plugin project(':x-pack-elasticsearch:plugin').path + setting 'xpack.monitoring.enabled', 'false' + setting 'xpack.ml.enabled', 'false' + setting 'xpack.watcher.enabled', 'false' + setting 'script.max_compilations_per_minute', '1000' + } + + task run(type: RunTask) { + distribution = 'zip' + plugin project(':x-pack-elasticsearch:plugin').path + setting 'xpack.monitoring.enabled', 'false' + setting 'xpack.ml.enabled', 'false' + setting 'xpack.watcher.enabled', 'false' + setting 'script.max_compilations_per_minute', '1000' + } +} diff --git a/qa/sql/multinode/build.gradle b/qa/sql/multinode/build.gradle new file mode 100644 index 00000000000..fa294f63335 --- /dev/null +++ b/qa/sql/multinode/build.gradle @@ -0,0 +1,4 @@ +integTestCluster { + numNodes = 2 + setting 'xpack.security.enabled', 'false' +} diff --git a/qa/sql/multinode/src/test/java/org/elasticsearch/xpack/sql/multinode/RestSqlIT.java b/qa/sql/multinode/src/test/java/org/elasticsearch/xpack/sql/multinode/RestSqlIT.java new file mode 100644 index 00000000000..9681d23a0f4 --- /dev/null +++ b/qa/sql/multinode/src/test/java/org/elasticsearch/xpack/sql/multinode/RestSqlIT.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.sql.multinode; + +import org.elasticsearch.xpack.sql.RestSqlTestCase; + +/** + * Integration test for the rest sql action. The one that speaks json directly to a + * user rather than to the JDBC driver or CLI. + */ +public class RestSqlIT extends RestSqlTestCase { +} diff --git a/qa/sql-multinode/src/test/java/org/elasticsearch/xpack/sql/SqlMultinodeIT.java b/qa/sql/multinode/src/test/java/org/elasticsearch/xpack/sql/multinode/SqlMultinodeIT.java similarity index 93% rename from qa/sql-multinode/src/test/java/org/elasticsearch/xpack/sql/SqlMultinodeIT.java rename to qa/sql/multinode/src/test/java/org/elasticsearch/xpack/sql/multinode/SqlMultinodeIT.java index 25a557acf27..4b0fa9e7a40 100644 --- a/qa/sql-multinode/src/test/java/org/elasticsearch/xpack/sql/SqlMultinodeIT.java +++ b/qa/sql/multinode/src/test/java/org/elasticsearch/xpack/sql/multinode/SqlMultinodeIT.java @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.xpack.sql; +package org.elasticsearch.xpack.sql.multinode; import org.apache.http.HttpHost; import org.apache.http.entity.ContentType; @@ -26,7 +26,7 @@ import java.util.Map; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; -import static java.util.Collections.unmodifiableMap; +import static org.elasticsearch.xpack.sql.RestSqlTestCase.columnInfo; public class SqlMultinodeIT extends ESRestTestCase { /** @@ -110,12 +110,4 @@ public class SqlMultinodeIT extends ESRestTestCase { fail("Response does not match:\n" + message.toString()); } } - - private Map columnInfo(String name, String type) { - Map column = new HashMap<>(); - column.put("name", name); - column.put("type", type); - return unmodifiableMap(column); - } - } diff --git a/qa/sql/no-security/build.gradle b/qa/sql/no-security/build.gradle new file mode 100644 index 00000000000..e1351ae803b --- /dev/null +++ b/qa/sql/no-security/build.gradle @@ -0,0 +1,7 @@ +integTestCluster { + setting 'xpack.security.enabled', 'false' +} + +run { + setting 'xpack.security.enabled', 'false' +} diff --git a/qa/sql/no-security/src/test/java/org/elasticsearch/xpack/sql/nosecurity/RestSqlIT.java b/qa/sql/no-security/src/test/java/org/elasticsearch/xpack/sql/nosecurity/RestSqlIT.java new file mode 100644 index 00000000000..2b3587c9172 --- /dev/null +++ b/qa/sql/no-security/src/test/java/org/elasticsearch/xpack/sql/nosecurity/RestSqlIT.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.sql.nosecurity; + +import org.elasticsearch.xpack.sql.RestSqlTestCase; + +/** + * Integration test for the rest sql action. The one that speaks json directly to a + * user rather than to the JDBC driver or CLI. + */ +public class RestSqlIT extends RestSqlTestCase { +} diff --git a/qa/sql-security/build.gradle b/qa/sql/security/build.gradle similarity index 70% rename from qa/sql-security/build.gradle rename to qa/sql/security/build.gradle index 627b3415ac5..b02dfeeebd5 100644 --- a/qa/sql-security/build.gradle +++ b/qa/sql/security/build.gradle @@ -1,32 +1,20 @@ -import org.elasticsearch.gradle.test.RunTask - -apply plugin: 'elasticsearch.standalone-rest-test' -apply plugin: 'elasticsearch.rest-test' - -dependencies { - testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'runtime') - testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'testArtifacts') - testCompile project(path: ':modules:reindex') -} - -// NOCOMMIT we should try this on multiple nodes - integTestCluster { - plugin ':x-pack-elasticsearch:plugin' - setting 'xpack.ml.enabled', 'false' - setting 'xpack.monitoring.enabled', 'false' - // Enabled audit logging so we can test it + // Setup auditing so we can use it in some tests setting 'xpack.security.audit.enabled', 'true' - setting 'xpack.security.audit.outputs', 'index' + setting 'xpack.security.audit.outputs', '[logfile, index]' // Only log the events we need so we don't have as much to sort through setting 'xpack.security.audit.index.events.include', '[access_denied, access_granted]' // Try and speed up audit logging without overwelming it setting 'xpack.security.audit.index.flush_interval', '250ms' setting 'xpack.security.audit.index.settings.index.number_of_shards', '1' setting 'xpack.security.audit.index.settings.index.refresh_interval', '250ms' + // Setup roles used by tests extraConfigFile 'x-pack/roles.yml', 'roles.yml' + /* Setup the one admin user that we run the tests as. + * Tests use "run as" to get different users. */ setupCommand 'setupUser#test_admin', 'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'x-pack-test-password', '-r', 'superuser' + // Override the wait condition to work properly with security waitCondition = { node, ant -> File tmpFile = new File(node.cwd, 'wait.success') ant.get(src: "http://${node.httpUri()}/_cluster/health?wait_for_nodes=>=${numNodes}&wait_for_status=yellow", @@ -39,23 +27,23 @@ integTestCluster { } } -task run(type: RunTask) { - distribution = 'zip' // NOCOMMIT make double sure we want all the modules - plugin ':x-pack-elasticsearch:plugin' - setting 'xpack.ml.enabled', 'false' - setting 'xpack.monitoring.enabled', 'false' +run { // Enabled audit logging so we can test it setting 'xpack.security.audit.enabled', 'true' - setting 'xpack.security.audit.outputs', 'index' + setting 'xpack.security.audit.outputs', '[logfile, index]' // Only log the events we need so we don't have as much to sort through setting 'xpack.security.audit.index.events.include', '[access_denied, access_granted]' // Try and speed up the logging process without overwelming it setting 'xpack.security.audit.index.flush_interval', '250ms' setting 'xpack.security.audit.index.settings.index.number_of_shards', '1' setting 'xpack.security.audit.index.settings.index.refresh_interval', '250ms' + // Setup roles used by tests extraConfigFile 'x-pack/roles.yml', 'roles.yml' + /* Setup the one admin user that we run the tests as. + * Tests use "run as" to get different users. */ setupCommand 'setupUser#test_admin', 'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'x-pack-test-password', '-r', 'superuser' + // Override the wait condition to work properly with security waitCondition = { node, ant -> File tmpFile = new File(node.cwd, 'wait.success') ant.get(src: "http://${node.httpUri()}/_cluster/health?wait_for_nodes=>=${numNodes}&wait_for_status=yellow", diff --git a/qa/sql-security/roles.yml b/qa/sql/security/roles.yml similarity index 100% rename from qa/sql-security/roles.yml rename to qa/sql/security/roles.yml diff --git a/qa/sql/security/src/test/java/org/elasticsearch/xpack/sql/security/RestSqlIT.java b/qa/sql/security/src/test/java/org/elasticsearch/xpack/sql/security/RestSqlIT.java new file mode 100644 index 00000000000..5217992a709 --- /dev/null +++ b/qa/sql/security/src/test/java/org/elasticsearch/xpack/sql/security/RestSqlIT.java @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.sql.security; + +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.xpack.sql.RestSqlTestCase; + +import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; + +/** + * Integration test for the rest sql action. The one that speaks json directly to a + * user rather than to the JDBC driver or CLI. + */ +public class RestSqlIT extends RestSqlTestCase { + /** + * All tests run as a an administrative user but use + * es-security-runas-user to become a less privileged user when needed. + */ + @Override + protected Settings restClientSettings() { + String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray())); + return Settings.builder() + .put(ThreadContext.PREFIX + ".Authorization", token) + .build(); + } +} diff --git a/qa/sql-security/src/test/java/org/elasticsearch/xpack/sql/SqlSecurityIT.java b/qa/sql/security/src/test/java/org/elasticsearch/xpack/sql/security/SqlSecurityIT.java similarity index 80% rename from qa/sql-security/src/test/java/org/elasticsearch/xpack/sql/SqlSecurityIT.java rename to qa/sql/security/src/test/java/org/elasticsearch/xpack/sql/security/SqlSecurityIT.java index 1d31319bbe7..1cd0ab0b4ca 100644 --- a/qa/sql-security/src/test/java/org/elasticsearch/xpack/sql/SqlSecurityIT.java +++ b/qa/sql/security/src/test/java/org/elasticsearch/xpack/sql/security/SqlSecurityIT.java @@ -3,12 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -package org.elasticsearch.xpack.sql; +package org.elasticsearch.xpack.sql.security; import org.apache.http.Header; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHeader; +import org.apache.logging.log4j.util.Strings; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.common.CheckedFunction; @@ -31,18 +32,21 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; -import static java.util.Collections.unmodifiableMap; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; +import static org.elasticsearch.xpack.sql.RestSqlTestCase.columnInfo; import static org.hamcrest.Matchers.containsString; public class SqlSecurityIT extends ESRestTestCase { - private static boolean createdTestData = false; + private static boolean oneTimeSetup = false; private static boolean auditFailure = false; /** @@ -66,8 +70,8 @@ public class SqlSecurityIT extends ESRestTestCase { } @Before - public void createTestData() throws IOException { - if (createdTestData) { + public void oneTimeSetup() throws Exception { + if (oneTimeSetup) { /* Since we don't wipe the cluster between tests we only need to * write the test data once. */ return; @@ -79,14 +83,43 @@ public class SqlSecurityIT extends ESRestTestCase { bulk.append("{\"a\": 4, \"b\": 5, \"c\": 6}\n"); client().performRequest("PUT", "/test/test/_bulk", singletonMap("refresh", "true"), new StringEntity(bulk.toString(), ContentType.APPLICATION_JSON)); + /* Wait for the audit log to go quiet and then clear it to protect + * us from log events coming from other tests. */ + cleanAuditLog(); + oneTimeSetup = true; } + /** + * Wait for any running bulk tasks to complete because those + * are likely audit log events and will cause the tests to + * hang at best and at worst. Then remove all audit logs. + */ @After - public void clearAuditLog() throws Exception { + public void cleanAuditLog() throws Exception { + assertBusy(() -> { + Set bulks = new HashSet<>(); + Map nodes = (Map) entityAsMap(adminClient().performRequest("GET", "_tasks")).get("nodes"); + for (Map.Entry node : nodes.entrySet()) { + Map nodeInfo = (Map) node.getValue(); + Map nodeTasks = (Map) nodeInfo.get("tasks"); + for (Map.Entry taskAndName : nodeTasks.entrySet()) { + Map task = (Map) taskAndName.getValue(); + String action = task.get("action").toString(); + if ("indices:data/write/bulk".equals(action) || "indices:data/write/bulk[s]".equals(action)) { + bulks.add(task.toString()); + } + } + } + if (false == bulks.isEmpty()) { + String bulksString = Strings.join(bulks, '\n'); + logger.info("Waiting on bulk writes to finish:\n{}", bulksString); + fail("Waiting on bulk writes to finish:\n" + bulksString); + } + }, 1, TimeUnit.MINUTES); try { clearAuditEvents(); } catch (ResponseException e) { - // 404 here just means we had no indexes + // 404 here just means we don't have any audit log index which shouldn't fail if (e.getResponse().getStatusLine().getStatusCode() != 404) { throw e; } @@ -268,13 +301,15 @@ public class SqlSecurityIT extends ESRestTestCase { search.endObject(); Map audit; try { - audit = toMap(client().performRequest("POST", "/.security_audit_log-*/_search", - singletonMap("filter_path", "hits.hits._source"), new StringEntity(search.string(), ContentType.APPLICATION_JSON))); + audit = toMap(client().performRequest("POST", "/.security_audit_log-*/_search?size=1000", + emptyMap(), new StringEntity(search.string(), ContentType.APPLICATION_JSON))); } catch (ResponseException e) { throw new AssertionError("ES failed to respond. Wrapping in assertion so we retry. Hopefully this is transient.", e); } Map hitsOuter = (Map) audit.get("hits"); - assertNotNull("expected some hits", hitsOuter); + if (hitsOuter == null) { + fail("expected some hit but got:\n" + audit); + } List hits = (List) hitsOuter.get("hits"); verifier: for (CheckedFunction, Boolean, Exception> eventChecker : eventCheckers) { for (Object hit : hits) { @@ -283,11 +318,25 @@ public class SqlSecurityIT extends ESRestTestCase { continue verifier; } } - fail("didn't find audit event we were looking for. found [" + hits + "]"); + fail("didn't find audit event we were looking for. found " + hits); } - }); + }, 1, TimeUnit.MINUTES); } catch (AssertionError e) { auditFailure = true; + logger.warn("Failed to find an audit log. Skipping remaining tests in this class after this the missing audit" + + "logs could turn up later."); + Map audit = toMap( + client().performRequest("POST", "/.security_audit_log-*/_search?size=50&sort=@timestamp:desc")); + Map hitsOuter = (Map) audit.get("hits"); + List hits = hitsOuter == null ? null : (List) hitsOuter.get("hits"); + if (hits == null || hits.isEmpty()) { + logger.warn("Didn't find any audit logs. Here is the whole response:\n{}", audit); + } else { + logger.warn("Here are the last 500 indexed audit logs:"); + for (Object hit : hits) { + logger.warn(hit.toString()); + } + } throw e; } } @@ -299,6 +348,7 @@ public class SqlSecurityIT extends ESRestTestCase { adminClient().performRequest("POST", "/.security_audit_log-*/_delete_by_query", emptyMap(), new StringEntity("{\"query\":{\"match_all\":{}}}", ContentType.APPLICATION_JSON)); } catch (ResponseException e) { + logger.info("Conflict while clearing audit logs"); if (e.getResponse().getStatusLine().getStatusCode() == 409) { throw new AssertionError("Conflict while clearing audit log. Wrapping in assertion so we retry.", e); } @@ -310,12 +360,4 @@ public class SqlSecurityIT extends ESRestTestCase { throw e; } } - - private Map columnInfo(String name, String type) { - Map column = new HashMap<>(); - column.put("name", name); - column.put("type", type); - return unmodifiableMap(column); - } - } diff --git a/qa/sql-no-security/src/test/java/org/elasticsearch/xpack/sql/RestSqlIT.java b/qa/sql/src/main/java/org/elasticsearch/xpack/sql/RestSqlTestCase.java similarity index 96% rename from qa/sql-no-security/src/test/java/org/elasticsearch/xpack/sql/RestSqlIT.java rename to qa/sql/src/main/java/org/elasticsearch/xpack/sql/RestSqlTestCase.java index b291faf051d..59b13d7e74b 100644 --- a/qa/sql-no-security/src/test/java/org/elasticsearch/xpack/sql/RestSqlIT.java +++ b/qa/sql/src/main/java/org/elasticsearch/xpack/sql/RestSqlTestCase.java @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ package org.elasticsearch.xpack.sql; - import org.apache.http.HttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; @@ -31,10 +30,20 @@ import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.containsString; /** - * Integration test for the rest sql action. That one that speaks json directly to a + * Integration test for the rest sql action. The one that speaks json directly to a * user rather than to the JDBC driver or CLI. */ -public class RestSqlIT extends ESRestTestCase { +public abstract class RestSqlTestCase extends ESRestTestCase { + /** + * Builds that map that is returned in the header for each column. + */ + public static Map columnInfo(String name, String type) { + Map column = new HashMap<>(); + column.put("name", name); + column.put("type", type); + return unmodifiableMap(column); + } + public void testBasicQuery() throws IOException { StringBuilder bulk = new StringBuilder(); bulk.append("{\"index\":{\"_id\":\"1\"}}\n"); @@ -165,11 +174,4 @@ public class RestSqlIT extends ESRestTestCase { fail("Response does not match:\n" + message.toString()); } } - - private Map columnInfo(String name, String type) { - Map column = new HashMap<>(); - column.put("name", name); - column.put("type", type); - return unmodifiableMap(column); - } }