Add hack to run internal test cluster if needed

Runs an internal test cluster if the test is not started with
an external rest test cluster.

Original commit: elastic/x-pack-elasticsearch@ce3d6f64e2
This commit is contained in:
Nik Everett 2017-06-29 12:07:39 -04:00
parent 9858d2ea3c
commit acfc8d1bc5
8 changed files with 97 additions and 134 deletions

View File

@ -42,6 +42,7 @@ public class TransportJdbcAction extends HandledTransportAction<JdbcRequest, Jdb
@Override
protected void doExecute(JdbcRequest request, ActionListener<JdbcResponse> 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));
}
}

View File

@ -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();

View File

@ -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"
}

View File

@ -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<Class<? extends Plugin>> 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

View File

@ -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<Object[]> 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:

View File

@ -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<Response> {
public JdbcHttpServer(Client client) {
super(client, new SqlProtoHandler(client), "/jdbc/", "sql/");
}
@Override
public String url() {
return "jdbc:es://" + super.url();
}
}

View File

@ -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<Response> {
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)));
}
}

View File

@ -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<Connection, SQLException> {
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();
}
}