diff --git a/plugin/src/main/java/org/elasticsearch/xpack/sql/plugin/jdbc/action/TransportJdbcAction.java b/plugin/src/main/java/org/elasticsearch/xpack/sql/plugin/jdbc/action/TransportJdbcAction.java index abb447d3d2e..281f7c42416 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/sql/plugin/jdbc/action/TransportJdbcAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/sql/plugin/jdbc/action/TransportJdbcAction.java @@ -42,6 +42,7 @@ public class TransportJdbcAction extends HandledTransportAction listener) { + // NOCOMMIT looks like this runs on the netty threadpool which might be bad. If we go async immediately it is ok, but we don't. jdbcServer.handle(request.request(), chain(listener, JdbcResponse::new)); } } \ No newline at end of file diff --git a/plugin/src/main/java/org/elasticsearch/xpack/sql/tree/NodeUtils.java b/plugin/src/main/java/org/elasticsearch/xpack/sql/tree/NodeUtils.java index 75367d8b1c8..86d47302e79 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/sql/tree/NodeUtils.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/sql/tree/NodeUtils.java @@ -146,6 +146,7 @@ public abstract class NodeUtils { Parameter[] parameters = ctr.getParameters(); for (int paramIndex = 0; paramIndex < parameters.length; paramIndex++) { Parameter param = parameters[paramIndex]; + // NOCOMMIT - oh boy. this is worth digging into. I suppose we preserve these for now but I don't think this is safe to rely on. Assert.isTrue(param.isNamePresent(), "Can't find constructor parameter names for [%s]. Is class debug information available?", clazz.toGenericString()); String paramName = param.getName(); diff --git a/sql-clients/jdbc/build.gradle b/sql-clients/jdbc/build.gradle index 1c516e8129d..963dc73115e 100644 --- a/sql-clients/jdbc/build.gradle +++ b/sql-clients/jdbc/build.gradle @@ -43,6 +43,9 @@ dependencies { testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'testArtifacts') testCompile project(':x-pack-elasticsearch:sql-clients:test-utils') + // Used by the hack to run InternalTestCluster if not running against a gradle-started cluster. + testCompile project(path: ':modules:lang-painless', configuration: 'runtime') + testRuntime "com.h2database:h2:1.4.194" testRuntime "net.sourceforge.csvjdbc:csvjdbc:1.0.31" } diff --git a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/JdbcIntegrationTestCase.java b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/JdbcIntegrationTestCase.java index e2e7e7059cc..00f13357658 100644 --- a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/JdbcIntegrationTestCase.java +++ b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/JdbcIntegrationTestCase.java @@ -8,16 +8,33 @@ package org.elasticsearch.xpack.sql.jdbc; import org.apache.http.HttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; +import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings; import org.elasticsearch.common.CheckedConsumer; +import org.elasticsearch.common.network.NetworkModule; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.painless.PainlessPlugin; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.test.InternalTestCluster; +import org.elasticsearch.test.NodeConfigurationSource; import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.transport.Netty4Plugin; +import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.sql.jdbc.jdbc.JdbcDriver; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.file.Path; import java.sql.DriverManager; +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Function; +import static java.util.Collections.emptySet; import static java.util.Collections.singletonMap; public abstract class JdbcIntegrationTestCase extends ESRestTestCase { @@ -26,6 +43,74 @@ public abstract class JdbcIntegrationTestCase extends ESRestTestCase { JdbcDriver.jdbcMajorVersion(); } + private static InternalTestCluster internalTestCluster; + + /** + * Hack to run an {@link InternalTestCluster} if this is being run + * in an environment without {@code tests.rest.cluster} set for easier + * debugging. Note that this doesn't work in the security manager is + * enabled. + */ + @BeforeClass + public static void startInternalTestClusterIfNeeded() throws IOException, InterruptedException { + if (System.getProperty("tests.rest.cluster") != null) { + // Nothing to do, using an external Elasticsearch node. + return; + } + long seed = randomLong(); + String name = InternalTestCluster.clusterName("", seed); + NodeConfigurationSource config = new NodeConfigurationSource() { + @Override + public Settings nodeSettings(int nodeOrdinal) { + Settings.Builder builder = Settings.builder() + // Enable http because the tests use it + .put(NetworkModule.HTTP_ENABLED.getKey(), true) + .put(NetworkModule.HTTP_TYPE_KEY, Netty4Plugin.NETTY_HTTP_TRANSPORT_NAME) + // Default the watermarks to absurdly low to prevent the tests + // from failing on nodes without enough disk space + .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING.getKey(), "1b") + .put(DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK_SETTING.getKey(), "1b") + // Mimic settings in build.gradle so we're closer to real + .put("xpack.security.enabled", false) + .put("xpack.monitoring.enabled", false) + .put("xpack.ml.enabled", false) + .put("xpack.watcher.enabled", false); + return builder.build(); + } + + @Override + public Path nodeConfigPath(int nodeOrdinal) { + return null; + } + + @Override + public Collection> nodePlugins() { + // Use netty4 plugin to enable rest + return Arrays.asList(Netty4Plugin.class, XPackPlugin.class, PainlessPlugin.class); + } + }; + internalTestCluster = new InternalTestCluster(seed, createTempDir(), false, true, 1, 1, name, config, 0, randomBoolean(), "", + emptySet(), Function.identity()); + internalTestCluster.beforeTest(random(), 0); + internalTestCluster.ensureAtLeastNumDataNodes(1); + InetSocketAddress httpBound = internalTestCluster.httpAddresses()[0]; + String http = httpBound.getHostString() + ":" + httpBound.getPort(); + try { + System.setProperty("tests.rest.cluster", http); + } catch (SecurityException e) { + throw new RuntimeException( + "Failed to set system property required for tests. Security manager must be disabled to use this hack.", e); + } + } + + @AfterClass + public static void shutDownInternalTestClusterIfNeeded() { + if (internalTestCluster == null) { + return; + } + internalTestCluster.close(); + } + protected JdbcTemplate j; @Before diff --git a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/compare/CompareToH2BaseTestCase.java b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/compare/CompareToH2BaseTestCase.java index bf66b7c74d9..fa38e21bec0 100644 --- a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/compare/CompareToH2BaseTestCase.java +++ b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/compare/CompareToH2BaseTestCase.java @@ -39,13 +39,6 @@ public abstract class CompareToH2BaseTestCase extends JdbcIntegrationTestCase { public final Integer lineNumber; public final Path source; - public CompareToH2BaseTestCase(String queryName, String query, Integer lineNumber, Path source) { - this.queryName = queryName; - this.query = query; - this.lineNumber = lineNumber; - this.source = source; - } - protected static List readScriptSpec(String spec) throws Exception { String url = "/" + spec + ".spec"; URL resource = CompareToH2BaseTestCase.class.getResource(url); @@ -87,6 +80,13 @@ public abstract class CompareToH2BaseTestCase extends JdbcIntegrationTestCase { return ctorArgs; } + public CompareToH2BaseTestCase(String queryName, String query, Integer lineNumber, Path source) { + this.queryName = queryName; + this.query = query; + this.lineNumber = lineNumber; + this.source = source; + } + public void testQuery() throws Throwable { /* * The syntax on the connection string is fairly particular: diff --git a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/server/JdbcHttpServer.java b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/server/JdbcHttpServer.java deleted file mode 100644 index 90329fd8e9f..00000000000 --- a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/server/JdbcHttpServer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.jdbc.integration.server; - -import org.elasticsearch.client.Client; -import org.elasticsearch.xpack.sql.jdbc.net.protocol.Response; -import org.elasticsearch.xpack.sql.test.server.ProtoHttpServer; - -public class JdbcHttpServer extends ProtoHttpServer { - - public JdbcHttpServer(Client client) { - super(client, new SqlProtoHandler(client), "/jdbc/", "sql/"); - } - - @Override - public String url() { - return "jdbc:es://" + super.url(); - } -} \ No newline at end of file diff --git a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/server/SqlProtoHandler.java b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/server/SqlProtoHandler.java deleted file mode 100644 index 098b9546406..00000000000 --- a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/server/SqlProtoHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.jdbc.integration.server; - -import com.sun.net.httpserver.HttpExchange; - -import org.elasticsearch.client.Client; -import org.elasticsearch.xpack.sql.TestUtils; -import org.elasticsearch.xpack.sql.jdbc.net.protocol.ProtoUtils; -import org.elasticsearch.xpack.sql.jdbc.net.protocol.Request; -import org.elasticsearch.xpack.sql.jdbc.net.protocol.Response; -import org.elasticsearch.xpack.sql.plugin.jdbc.server.JdbcServer; -import org.elasticsearch.xpack.sql.plugin.jdbc.server.JdbcServerProtoUtils; -import org.elasticsearch.xpack.sql.test.server.ProtoHandler; - -import java.io.DataInput; -import java.io.IOException; - -import static org.elasticsearch.action.ActionListener.wrap; - -class SqlProtoHandler extends ProtoHandler { - - private final JdbcServer server; - - SqlProtoHandler(Client client) { - super(client, ProtoUtils::readHeader, JdbcServerProtoUtils::write); - this.server = new JdbcServer(TestUtils.planExecutor(client), clusterName, () -> info.getNode().getName(), info.getVersion(), - info.getBuild()); - } - - @Override - protected void handle(HttpExchange http, DataInput in) throws IOException { - Request req = ProtoUtils.readRequest(in); - server.handle(req, wrap(resp -> sendHttpResponse(http, resp), ex -> fail(http, ex))); - } -} \ No newline at end of file diff --git a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/util/EsJdbcServer.java b/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/util/EsJdbcServer.java deleted file mode 100644 index a55c65bd8a0..00000000000 --- a/sql-clients/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/integration/util/EsJdbcServer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.jdbc.integration.util; - -import org.elasticsearch.client.Client; -import org.elasticsearch.common.CheckedSupplier; -import org.elasticsearch.xpack.sql.jdbc.integration.server.JdbcHttpServer; -import org.elasticsearch.xpack.sql.jdbc.jdbc.JdbcDriver; -import org.junit.rules.ExternalResource; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; - -import static org.junit.Assert.assertNotNull; - -public class EsJdbcServer extends ExternalResource implements CheckedSupplier { - private JdbcHttpServer server; - private String jdbcUrl; - private JdbcDriver driver; - private final Properties properties; - - public EsJdbcServer(boolean remote, boolean debug) { - properties = new Properties(); - if (debug) { - properties.setProperty("debug", "true"); - } - } - - public void start() throws Throwable { - before(); - } - - public void stop() { - after(); - } - - @Override - protected void before() throws Throwable { - server = new JdbcHttpServer(null); - driver = new JdbcDriver(); - - server.start(0); - jdbcUrl = server.url(); - } - - @Override - protected void after() { - server.stop(); - server = null; - } - - @Override - public Connection get() throws SQLException { - assertNotNull("ES JDBC Driver is null - make sure ES is properly run as a @ClassRule", driver); - return driver.connect(jdbcUrl, properties); - } - - public Client client() { - assertNotNull("ES JDBC Server is null - make sure ES is properly run as a @ClassRule", driver); - return server.client(); - } -} \ No newline at end of file