Port some of CLI's demos to tests

Original commit: elastic/x-pack-elasticsearch@5827c08268
This commit is contained in:
Nik Everett 2017-07-03 14:49:43 -04:00
parent 3eb1258b0d
commit 56803bdd1b
10 changed files with 561 additions and 51 deletions

View File

@ -1,3 +1,5 @@
import org.elasticsearch.gradle.test.RunTask
apply plugin: 'elasticsearch.build'
apply plugin: 'application'
@ -8,10 +10,12 @@ dependencies {
compile project(':x-pack-elasticsearch:sql:net-client')
compile project(':x-pack-elasticsearch:sql:cli-proto')
testCompile project(":x-pack-elasticsearch:transport-client")
testCompile project(":x-pack-elasticsearch:transport-client") // NOCOMMIT probably can remove this
testCompile project(path: ':x-pack-elasticsearch:plugin', configuration: 'testArtifacts')
testCompile project(':x-pack-elasticsearch:sql:test-utils')
testCompile project(':x-pack-elasticsearch:sql:server')
// Used by the hack to run InternalTestCluster if not running against a gradle-started cluster.
testCompile project(path: ':modules:lang-painless', configuration: 'runtime')
runtime "org.fusesource.jansi:jansi:1.16"
runtime "org.elasticsearch:jna:4.4.0-1"
@ -37,10 +41,6 @@ jar {
mainClassName = "org.elasticsearch.sql.console.SqlConsole"
run {
classpath = sourceSets.test.runtimeClasspath
}
// Needed so we can launch graphviz if it is installed
project.compactProfile = 'full'
@ -102,3 +102,29 @@ thirdPartyAudit.excludes = [
'org.fusesource.jansi.internal.WindowsSupport',
'org.mozilla.universalchardet.UniversalDetector'
]
apply plugin: 'elasticsearch.rest-test'
integTest.mustRunAfter 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'
}
task runServer(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'
run.dependsOn this
}

View File

@ -5,12 +5,6 @@
*/
package org.elasticsearch.xpack.sql.cli;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.Properties;
import org.elasticsearch.xpack.sql.cli.net.client.CliHttpClient;
import org.elasticsearch.xpack.sql.net.client.util.IOUtils;
import org.jline.keymap.BindingReader;
@ -24,6 +18,12 @@ import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.InfoCmp.Capability;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.Properties;
import static org.jline.utils.AttributedStyle.BOLD;
import static org.jline.utils.AttributedStyle.BRIGHT;
import static org.jline.utils.AttributedStyle.DEFAULT;
@ -31,6 +31,17 @@ import static org.jline.utils.AttributedStyle.RED;
import static org.jline.utils.AttributedStyle.YELLOW;
public class Cli {
public static void main(String... args) throws Exception {
try (Terminal term = TerminalBuilder.builder().build()) {
try {
Cli console = new Cli(new CliConfiguration("localhost:9200/_cli", new Properties()), term);
console.run();
} catch (FatalException e) {
new PrintWriter(term.output()).println(e.getMessage());
System.exit(1);
}
}
}
private final Terminal term;
private final BindingReader bindingReader;
@ -38,24 +49,16 @@ public class Cli {
private final CliConfiguration cfg;
private final CliHttpClient cliClient;
public static void main(String... args) throws Exception {
try (Terminal term = TerminalBuilder.builder().build()) {
Cli console = new Cli(term);
console.run();
}
}
private Cli(Terminal terminal) {
Cli(CliConfiguration cfg, Terminal terminal) {
term = terminal;
bindingReader = new BindingReader(term.reader());
keys = new Keys(term);
cfg = new CliConfiguration("localhost:9200/_cli", new Properties());
this.cfg = cfg;
cliClient = new CliHttpClient(cfg);
}
private void run() throws Exception {
void run() throws IOException {
PrintWriter out = term.writer();
LineReader reader = LineReaderBuilder.builder()
@ -131,6 +134,7 @@ public class Cli {
executeCommand(line, out);
}
} catch (RuntimeException ex) {
ex.printStackTrace();
AttributedStringBuilder asb = new AttributedStringBuilder();
asb.append("Communication error [", BOLD.foreground(RED));
asb.append(ex.getMessage(), DEFAULT.boldOff().italic().foreground(YELLOW));
@ -145,13 +149,14 @@ public class Cli {
}
private static String logo() {
try (InputStream io = Cli.class.getResourceAsStream("logo.txt")) {
if (io != null) {
return IOUtils.asBytes(io).toString();
try (InputStream io = Cli.class.getResourceAsStream("/logo.txt")) {
if (io == null) {
throw new FatalException("Could not find logo!");
}
} catch (IOException io) {
return IOUtils.asBytes(io).toString();
} catch (IOException e) {
throw new FatalException("Could not load logo!", e);
}
return "Could not load logo...";
}
private void printLogo(PrintWriter out) {
@ -187,4 +192,14 @@ public class Cli {
protected void executeCommand(String line, PrintWriter out) throws IOException {
out.print(ResponseToString.toAnsi(cliClient.command(line, null)).toAnsi(term));
}
static class FatalException extends RuntimeException {
public FatalException(String message, Throwable cause) {
super(message, cause);
}
public FatalException(String message) {
super(message);
}
}
}

View File

@ -37,9 +37,7 @@ public class CliConfiguration extends ConnectionConfiguration {
// remove space
u = u.trim();
String hostAndPort = u;
int index = u.indexOf("://");
if (index > 0) {
u = u.substring(index + 3);
@ -58,7 +56,7 @@ public class CliConfiguration extends ConnectionConfiguration {
}
// look for port
index = hostAndPort.indexOf(":");
index = hostAndPort.lastIndexOf(":");
if (index > 0) {
if (index + 1 >= hostAndPort.length()) {
throw new IllegalArgumentException("Invalid port specified");

View File

@ -13,6 +13,8 @@ import org.elasticsearch.xpack.sql.net.client.util.Bytes;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
class HttpClient {
@ -31,7 +33,13 @@ class HttpClient {
}
boolean head(String path) {
return JreHttpUrlConnection.http(url(path), cfg, JreHttpUrlConnection::head);
try {
return AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
return JreHttpUrlConnection.http(url(path), cfg, JreHttpUrlConnection::head);
});
} catch (ClientException ex) {
throw new RuntimeException("Transport failure", ex);
}
}
Bytes put(DataOutputConsumer os) {
@ -39,9 +47,15 @@ class HttpClient {
}
Bytes put(String path, DataOutputConsumer os) {
return JreHttpUrlConnection.http(url(path), cfg, con -> {
return con.put(os);
});
try {
return AccessController.doPrivileged((PrivilegedAction<Bytes>) () -> {
return JreHttpUrlConnection.http(url(path), cfg, con -> {
return con.put(os);
});
});
} catch (ClientException ex) {
throw new RuntimeException("Transport failure", ex);
}
}
void close() {}

View File

@ -0,0 +1,223 @@
/*
* 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.cli;
import com.carrotsearch.randomizedtesting.ThreadFilter;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
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.cli.CliIntegrationTestCase.CliThreadLeakFilter;
import org.elasticsearch.xpack.sql.net.client.SuppressForbidden;
import org.jline.terminal.Attributes;
import org.jline.terminal.Attributes.LocalFlag;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import org.jline.utils.NonBlockingReader;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.function.Function;
import static java.util.Collections.emptySet;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.not;
@ThreadLeakFilters(filters = CliThreadLeakFilter.class)
public class CliIntegrationTestCase extends ESRestTestCase {
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
@SuppressForbidden(reason="it is a hack anyway")
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 PrintWriter out;
protected BufferedReader in;
@Before
public void startCli() throws IOException {
PipedInputStream terminalIn = new PipedInputStream();
out = new PrintWriter(new PipedOutputStream(terminalIn), true);
PipedOutputStream terminalOut = new PipedOutputStream();
in = new BufferedReader(new InputStreamReader(new PipedInputStream(terminalOut)));
Terminal terminal = TerminalBuilder.builder()
.system(false)
.jansi(false)
.jna(false)
.type("dumb")
.encoding("UTF-8")
.streams(terminalIn, terminalOut)
.build();
// Work around https://github.com/jline/jline3/issues/145
Attributes attrs = terminal.getAttributes();
attrs.setLocalFlag(LocalFlag.ISIG, false);
terminal.setAttributes(attrs);
terminal.echo(false);
Cli cli = new Cli(new CliConfiguration(System.getProperty("tests.rest.cluster") + "/_cli", new Properties()), terminal);
Thread cliThread = new Thread(() -> {
try {
cli.run();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
cliThread.start();
// Throw out the logo so tests don't have to!
while (false == in.readLine().contains("SQL"));
// Throw out the empty line before all the good stuff
assertEquals("", in.readLine());
}
@After
public void shutdownCli() throws IOException, InterruptedException {
try {
// Try and quit
out.println("quit;");
List<String> nonQuit = new ArrayList<>();
String line;
while (false == (line = in.readLine()).equals("sql> quit;")) {
nonQuit.add(line);
}
assertThat("unconsumed lines", nonQuit, empty());
assertEquals("", in.readLine());
assertEquals("Bye!", in.readLine());
assertFalse(in.ready());
} finally {
// but close the streams anyway so the tests shut down cleanly
out.close();
in.close();
}
}
protected void index(String index, CheckedConsumer<XContentBuilder, IOException> body) throws IOException {
XContentBuilder builder = JsonXContent.contentBuilder().startObject();
body.accept(builder);
builder.endObject();
HttpEntity doc = new StringEntity(builder.string(), ContentType.APPLICATION_JSON);
client().performRequest("PUT", "/" + index + "/doc/1", singletonMap("refresh", "true"), doc);
}
/**
* Send a command and assert the echo.
*/
protected void command(String command) throws IOException {
assertThat("; automatically added", command, not(endsWith(";")));
out.println(command + ";");
assertEquals("sql> " + command + ";", in.readLine());
assertEquals("", in.readLine());
}
/**
* The {@link NonBlockingReader} just will not die. It looks harmless enough.
* Hopefully it is ok to let it be.
*/
public static class CliThreadLeakFilter implements ThreadFilter {
@Override
public boolean reject(Thread t) {
for (StackTraceElement ste : t.getStackTrace()) {
if (ste.getClassName().equals(NonBlockingReader.class.getName()) && ste.getMethodName().equals("run")) {
return true;
}
}
return false;
}
}
}

View File

@ -0,0 +1,147 @@
/*
* 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.cli;
import java.io.IOException;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.startsWith;
public class ExplainIT extends CliIntegrationTestCase {
public void testExplainBasic() throws IOException {
index("test", body -> body.field("test_field", "test_value"));
command("EXPLAIN (PLAN PARSED) SELECT * FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("With[{}]"));
assertThat(in.readLine(), startsWith("\\_Project[[?*]]"));
assertThat(in.readLine(), startsWith(" \\_UnresolvedRelation[[index=test, type=doc],null]"));
assertEquals("", in.readLine());
command("EXPLAIN " + (randomBoolean() ? "" : "(PLAN ANALYZED) ") + "SELECT * FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("Project[[test_field{r}#"));
assertThat(in.readLine(), startsWith("\\_SubQueryAlias[doc]"));
assertThat(in.readLine(), startsWith(" \\_CatalogTable[index=test,type=doc][test_field{r}#"));
assertEquals("", in.readLine());
command("EXPLAIN (PLAN OPTIMIZED) SELECT * FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("Project[[test_field{r}#"));
assertThat(in.readLine(), startsWith("\\_CatalogTable[index=test,type=doc][test_field{r}#"));
assertEquals("", in.readLine());
// TODO in this case we should probably remove the source filtering entirely. Right? It costs but we don't need it.
command("EXPLAIN (PLAN EXECUTABLE) SELECT * FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("EsQueryExec[test/doc,{"));
assertThat(in.readLine(), startsWith(" \"_source\" : {"));
assertThat(in.readLine(), startsWith(" \"includes\" : ["));
assertThat(in.readLine(), startsWith(" \"test_field\""));
assertThat(in.readLine(), startsWith(" ],"));
assertThat(in.readLine(), startsWith(" \"excludes\" : [ ]"));
assertThat(in.readLine(), startsWith(" }"));
assertThat(in.readLine(), startsWith("}]"));
assertEquals("", in.readLine());
}
public void testExplainWithWhere() throws IOException {
index("test", body -> body.field("test_field", "test_value1").field("i", 1));
index("test", body -> body.field("test_field", "test_value2").field("i", 2));
command("EXPLAIN (PLAN PARSED) SELECT * FROM test.doc WHERE i = 2");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("With[{}]"));
assertThat(in.readLine(), startsWith("\\_Project[[?*]]"));
assertThat(in.readLine(), startsWith(" \\_Filter[?i = 2]"));
assertThat(in.readLine(), startsWith(" \\_UnresolvedRelation[[index=test, type=doc],null]"));
assertEquals("", in.readLine());
command("EXPLAIN " + (randomBoolean() ? "" : "(PLAN ANALYZED) ") + "SELECT * FROM test.doc WHERE i = 2");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("Project[[i{r}#"));
assertThat(in.readLine(), startsWith("\\_Filter[i{r}#"));
assertThat(in.readLine(), startsWith(" \\_SubQueryAlias[doc]"));
assertThat(in.readLine(), startsWith(" \\_CatalogTable[index=test,type=doc][i{r}#"));
assertEquals("", in.readLine());
command("EXPLAIN (PLAN OPTIMIZED) SELECT * FROM test.doc WHERE i = 2");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("Project[[i{r}#"));
assertThat(in.readLine(), startsWith("\\_Filter[i{r}#"));
assertThat(in.readLine(), startsWith(" \\_CatalogTable[index=test,type=doc][i{r}#"));
assertEquals("", in.readLine());
command("EXPLAIN (PLAN EXECUTABLE) SELECT * FROM test.doc WHERE i = 2");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("EsQueryExec[test/doc,{"));
assertThat(in.readLine(), startsWith(" \"query\" : {"));
assertThat(in.readLine(), startsWith(" \"term\" : {"));
assertThat(in.readLine(), startsWith(" \"i\" : {"));
assertThat(in.readLine(), startsWith(" \"value\" : 2,"));
assertThat(in.readLine(), startsWith(" \"boost\" : 1.0"));
assertThat(in.readLine(), startsWith(" }"));
assertThat(in.readLine(), startsWith(" }"));
assertThat(in.readLine(), startsWith(" },"));
assertThat(in.readLine(), startsWith(" \"_source\" : {"));
assertThat(in.readLine(), startsWith(" \"includes\" : ["));
assertThat(in.readLine(), startsWith(" \"test_field\""));
assertThat(in.readLine(), startsWith(" ],"));
assertThat(in.readLine(), startsWith(" \"excludes\" : [ ]"));
assertThat(in.readLine(), startsWith(" },"));
assertThat(in.readLine(), startsWith(" \"docvalue_fields\" : ["));
assertThat(in.readLine(), startsWith(" \"i\""));
assertThat(in.readLine(), startsWith(" ]"));
assertThat(in.readLine(), startsWith("}]"));
assertEquals("", in.readLine());
}
public void testExplainWithCount() throws IOException {
index("test", body -> body.field("test_field", "test_value1").field("i", 1));
index("test", body -> body.field("test_field", "test_value2").field("i", 2));
command("EXPLAIN (PLAN PARSED) SELECT COUNT(*) FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("With[{}]"));
assertThat(in.readLine(), startsWith("\\_Project[[?COUNT(?*)]]"));
assertThat(in.readLine(), startsWith(" \\_UnresolvedRelation[[index=test, type=doc],null]"));
assertEquals("", in.readLine());
command("EXPLAIN " + (randomBoolean() ? "" : "(PLAN ANALYZED) ") + "SELECT COUNT(*) FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("Aggregate[[],[COUNT(1)#"));
assertThat(in.readLine(), startsWith("\\_SubQueryAlias[doc]"));
assertThat(in.readLine(), startsWith(" \\_CatalogTable[index=test,type=doc][i{r}#"));
assertEquals("", in.readLine());
command("EXPLAIN (PLAN OPTIMIZED) SELECT COUNT(*) FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("Aggregate[[],[COUNT(1)#"));
assertThat(in.readLine(), startsWith("\\_CatalogTable[index=test,type=doc][i{r}#"));
assertEquals("", in.readLine());
command("EXPLAIN (PLAN EXECUTABLE) SELECT COUNT(*) FROM test.doc");
assertThat(in.readLine(), containsString("plan"));
assertThat(in.readLine(), startsWith("----------"));
assertThat(in.readLine(), startsWith("EsQueryExec[test/doc,{"));
assertThat(in.readLine(), startsWith(" \"size\" : 0,"));
assertThat(in.readLine(), startsWith(" \"_source\" : false,"));
assertThat(in.readLine(), startsWith(" \"stored_fields\" : \"_none_\""));
assertThat(in.readLine(), startsWith("}]"));
assertEquals("", in.readLine());
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.cli;
import org.elasticsearch.test.hamcrest.RegexMatcher;
import java.io.IOException;
import static org.hamcrest.Matchers.containsString;
public class SelectIT extends CliIntegrationTestCase {
public void testSelect() throws IOException {
index("test", body -> body.field("test_field", "test_value"));
command("SELECT * FROM test.doc");
assertThat(in.readLine(), containsString("test_field"));
assertThat(in.readLine(), containsString("----------"));
assertThat(in.readLine(), containsString("test_value"));
assertEquals("", in.readLine());
}
public void testSelectWithWhere() throws IOException {
index("test", body -> body.field("test_field", "test_value1").field("i", 1));
index("test", body -> body.field("test_field", "test_value2").field("i", 2));
command("SELECT * FROM test.doc WHERE i = 2");
assertThat(in.readLine(), RegexMatcher.matches("\\s*i\\s*\\|\\s*test_field\\s*"));
assertThat(in.readLine(), containsString("----------"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*2\\s*\\|\\s*test_value2\\s*"));
assertEquals("", in.readLine());
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.cli;
import org.elasticsearch.test.hamcrest.RegexMatcher;
import java.io.IOException;
import java.util.regex.Pattern;
import static org.hamcrest.Matchers.containsString;
public class ShowIT extends CliIntegrationTestCase {
public void testShowTables() throws IOException {
index("test1", body -> body.field("test_field", "test_value"));
index("test2", body -> body.field("test_field", "test_value"));
command("SHOW TABLES");
assertThat(in.readLine(), RegexMatcher.matches("\\s*index\\s*\\|\\s*type\\s*"));
assertThat(in.readLine(), containsString("----------"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*test[12]\\s*\\|\\s*doc\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*test[12]\\s*\\|\\s*doc\\s*"));
assertEquals("", in.readLine());
}
public void testShowFunctions() throws IOException {
command("SHOW FUNCTIONS");
assertThat(in.readLine(), RegexMatcher.matches("\\s*name\\s*\\|\\s*type\\s*"));
assertThat(in.readLine(), containsString("----------"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*AVG\\s*\\|\\s*AGGREGATE\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*COUNT\\s*\\|\\s*AGGREGATE\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*MAX\\s*\\|\\s*AGGREGATE\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*MIN\\s*\\|\\s*AGGREGATE\\s*"));
String line = in.readLine();
Pattern aggregateFunction = Pattern.compile("\\s*[A-Z0-9_~]+\\s*\\|\\s*AGGREGATE\\s*");
while (aggregateFunction.matcher(line).matches()) {
line = in.readLine();
}
Pattern scalarFunction = Pattern.compile("\\s*[A-Z0-9_~]+\\s*\\|\\s*SCALAR\\s*");
while (scalarFunction.matcher(line).matches()) {
line = in.readLine();
}
assertEquals("", line);
command("SHOW FUNCTIONS LIKE 'L%'");
assertThat(in.readLine(), RegexMatcher.matches("\\s*name\\s*\\|\\s*type\\s*"));
assertThat(in.readLine(), containsString("----------"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*LOG\\s*\\|\\s*SCALAR\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*LOG10\\s*\\|\\s*SCALAR\\s*"));
assertEquals("", in.readLine());
command("SHOW FUNCTIONS LIKE '%DAY%'");
assertThat(in.readLine(), RegexMatcher.matches("\\s*name\\s*\\|\\s*type\\s*"));
assertThat(in.readLine(), containsString("----------"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*DAY_OF_MONTH\\s*\\|\\s*SCALAR\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*DAY\\s*\\|\\s*SCALAR\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*DAY_OF_WEEK\\s*\\|\\s*SCALAR\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*DAY_OF_YEAR\\s*\\|\\s*SCALAR\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*HOUR_OF_DAY\\s*\\|\\s*SCALAR\\s*"));
assertThat(in.readLine(), RegexMatcher.matches("\\s*MINUTE_OF_DAY\\s*\\|\\s*SCALAR\\s*"));
assertEquals("", in.readLine());
}
}

View File

@ -30,7 +30,7 @@ import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
public class ProtoTests extends ESTestCase {
// NOCOMMIT probably should be an integration test that runs against a running copy of ES with SQL installed
// NOCOMMIT port remaining demos
private static Client esClient;
private static CliHttpServer server;
@ -71,6 +71,7 @@ public class ProtoTests extends ESTestCase {
}
public void testInfoAction() throws Exception {
// NOCOMMIT port to CliIntegrationTestCase
InfoResponse esInfo = (InfoResponse) client.serverInfo();
assertThat(esInfo, notNullValue());
assertThat(esInfo.cluster, is("elasticsearch"));
@ -81,23 +82,12 @@ public class ProtoTests extends ESTestCase {
//assertThat(esInfo.minorVersion(), is(0));
}
public void testBasicQuery() throws Exception {
CommandResponse command = (CommandResponse) client.command("SHOW TABLES", null);
System.out.println(command.data);
}
public void testDemoQuery() throws Exception {
CommandResponse command = (CommandResponse) client.command("SELECT first_name f, last_name l, YEAR(dep.from_date) start FROM emp.emp WHERE dep.dept_name = 'Production' AND tenure > 30 ORDER BY start", null);
System.out.println(command.data);
}
public void testDemo() throws Exception {
// add math functions
// add statistical function + explanation on optimization
List<String> commands = Arrays.asList(
"SHOW TABLES",
"DESCRIBE emp.emp",
"SELECT * FROM emp.emp",
"SELECT * FROM emp.emp LIMIT 5",
@ -106,18 +96,14 @@ public class ProtoTests extends ESTestCase {
"SELECT * FROM emp.emp WHERE MATCH(first_name, 'Mary')",
"SELECT * FROM emp.emp WHERE MATCH('first_name,last_name', 'Morton', 'type=best_fields;default_operator=OR')",
"SELECT * FROM emp.emp WHERE QUERY('Elvis Alain')",
"SHOW FUNCTIONS",
"SHOW FUNCTIONS LIKE 'L%'",
"SELECT LOG(salary) FROM emp.emp",
"SELECT salary s, LOG(salary) m FROM emp.emp LIMIT 5",
"SELECT salary s, EXP(LOG(salary)) m FROM emp.emp LIMIT 5",
"SELECT salary s, ROUND(EXP(LOG(salary))) m FROM emp.emp LIMIT 5",
"SELECT salary s, ROUND(EXP(LOG(salary))) m FROM emp.emp ORDER BY ROUND(LOG(emp_no)) LIMIT 5",
"SHOW FUNCTIONS LIKE '%DAY%'",
"SELECT year(birth_date) year, last_name l, first_name f FROM emp.emp WHERE year(birth_date) <=1960 AND tenure < 25 ORDER BY year LIMIT 5",
"SELECT COUNT(*) FROM emp.emp",
"SELECT COUNT(*) FROM emp.emp WHERE emp_no >= 10010",
"EXPLAIN (PLAN EXECUTABLE) SELECT COUNT(*) FROM emp.emp",
"SELECT tenure, COUNT(*) count, MIN(salary) min, AVG(salary) avg, MAX(salary) max FROM emp.emp GROUP BY tenure",
"SELECT YEAR(birth_date) born, COUNT(*) count, MIN(salary) min, AVG(salary) avg, MAX(salary) max FROM emp.emp GROUP BY born",
"SELECT tenure, gender, COUNT(tenure) count, AVG(salary) avg FROM emp.emp GROUP BY tenure, gender HAVING avg > 50000",

View File

@ -0,0 +1,4 @@
grant {
// Policy is required for tests to connect to testing Elasticsearch instance.
permission java.net.SocketPermission "*", "connect,resolve";
};