SQL: Add more error integration tests (elastic/x-pack-elasticsearch#3134)

We didn't have many integration tests for errors other than the security
errors. This adds some and sets up a way we can make sure we are
consistent across the REST, JDBC, and CLI.

relates elastic/x-pack-elasticsearch#3033

Original commit: elastic/x-pack-elasticsearch@debbb2ec46
This commit is contained in:
Nik Everett 2017-11-28 11:54:51 -05:00 committed by GitHub
parent 193f22b97f
commit 18e88122eb
4 changed files with 102 additions and 12 deletions

View File

@ -0,0 +1,18 @@
/*
* 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.qa.sql;
/**
* Interface implemented once per SQL access method to ensure that we
* test the same minimal set of error cases. Note that this does not
* include security related failures, those are tracked in another test.
*/
public interface ErrorsTestCase {
void testSelectInvalidSql() throws Exception;
void testSelectFromMissingIndex() throws Exception;
void testSelectMissingField() throws Exception;
void testSelectMissingFunction() throws Exception;
}

View File

@ -5,12 +5,35 @@
*/ */
package org.elasticsearch.xpack.qa.sql.cli; package org.elasticsearch.xpack.qa.sql.cli;
import java.io.IOException;
/** /**
* Tests for error messages. * Tests for error messages.
*/ */
public abstract class ErrorsTestCase extends CliIntegrationTestCase { public abstract class ErrorsTestCase extends CliIntegrationTestCase implements org.elasticsearch.xpack.qa.sql.ErrorsTestCase {
public void testSelectFromMissingTable() throws Exception { @Override
public void testSelectInvalidSql() throws Exception {
assertEquals("[1;31mBad request [[22;3;33mFound 1 problem(s)", command("SELECT * FRO"));
assertEquals("line 1:8: Cannot determine columns for *[1;23;31m][0m", readLine());
}
@Override
public void testSelectFromMissingIndex() throws IOException {
assertEquals("[1;31mBad request [[22;3;33mFound 1 problem(s)", command("SELECT * FROM test")); assertEquals("[1;31mBad request [[22;3;33mFound 1 problem(s)", command("SELECT * FROM test"));
assertEquals("line 1:15: Unknown index [test][1;23;31m][0m", readLine()); assertEquals("line 1:15: Unknown index [test][1;23;31m][0m", readLine());
} }
@Override
public void testSelectMissingField() throws IOException {
index("test", body -> body.field("test", "test"));
assertEquals("[1;31mBad request [[22;3;33mFound 1 problem(s)", command("SELECT missing FROM test"));
assertEquals("line 1:8: Unknown column [missing][1;23;31m][0m", readLine());
}
@Override
public void testSelectMissingFunction() throws Exception {
index("test", body -> body.field("foo", 1));
assertEquals("[1;31mBad request [[22;3;33mFound 1 problem(s)", command("SELECT missing(foo) FROM test"));
assertEquals("line 1:8: Unknown function [missing][1;23;31m][0m", readLine());
}
} }

View File

@ -11,11 +11,38 @@ import java.sql.SQLException;
/** /**
* Tests for exceptions and their messages. * Tests for exceptions and their messages.
*/ */
public class ErrorsTestCase extends JdbcIntegrationTestCase { public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elasticsearch.xpack.qa.sql.ErrorsTestCase {
public void testSelectFromMissingTable() throws Exception { @Override
public void testSelectInvalidSql() throws Exception {
try (Connection c = esJdbc()) { try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * from test").executeQuery()); SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FRO").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:8: Cannot determine columns for *", e.getMessage());
}
}
@Override
public void testSelectFromMissingIndex() throws SQLException {
try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:15: Unknown index [test]", e.getMessage()); assertEquals("Found 1 problem(s)\nline 1:15: Unknown index [test]", e.getMessage());
} }
} }
@Override
public void testSelectMissingField() throws Exception {
index("test", body -> body.field("test", "test"));
try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT missing FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:8: Unknown column [missing]", e.getMessage());
}
}
@Override
public void testSelectMissingFunction() throws Exception {
index("test", body -> body.field("foo", 1));
try (Connection c = esJdbc()) {
SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT missing(foo) FROM test").executeQuery());
assertEquals("Found 1 problem(s)\nline 1:8: Unknown function [missing]", e.getMessage());
}
}
} }

View File

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.xpack.qa.sql.rest; package org.elasticsearch.xpack.qa.sql.rest;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
@ -15,6 +16,7 @@ import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.NotEqualMessageBuilder; import org.elasticsearch.test.NotEqualMessageBuilder;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.qa.sql.ErrorsTestCase;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import java.io.IOException; import java.io.IOException;
@ -25,6 +27,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@ -36,7 +39,7 @@ import static org.hamcrest.Matchers.containsString;
* Integration test for the rest sql action. The 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. * user rather than to the JDBC driver or CLI.
*/ */
public abstract class RestSqlTestCase extends ESRestTestCase { public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTestCase {
/** /**
* Builds that map that is returned in the header for each column. * Builds that map that is returned in the header for each column.
*/ */
@ -124,11 +127,18 @@ public abstract class RestSqlTestCase extends ESRestTestCase {
new StringEntity("{\"query\":\"SELECT DAY_OF_YEAR(test), COUNT(*) FROM test\"}", ContentType.APPLICATION_JSON))); new StringEntity("{\"query\":\"SELECT DAY_OF_YEAR(test), COUNT(*) FROM test\"}", ContentType.APPLICATION_JSON)));
} }
public void missingIndex() throws IOException { @Override
expectBadRequest(() -> runSql("SELECT foo FROM missing"), containsString("1:17: index [missing] does not exist")); public void testSelectInvalidSql() throws Exception {
expectBadRequest(() -> runSql("SELECT * FRO"), containsString("1:8: Cannot determine columns for *"));
} }
public void testMissingField() throws IOException { @Override
public void testSelectFromMissingIndex() throws IOException {
expectBadRequest(() -> runSql("SELECT * FROM missing"), containsString("1:15: Unknown index [missing]"));
}
@Override
public void testSelectMissingField() throws IOException {
StringBuilder bulk = new StringBuilder(); StringBuilder bulk = new StringBuilder();
bulk.append("{\"index\":{\"_id\":\"1\"}}\n"); bulk.append("{\"index\":{\"_id\":\"1\"}}\n");
bulk.append("{\"test\":\"test\"}\n"); bulk.append("{\"test\":\"test\"}\n");
@ -138,6 +148,17 @@ public abstract class RestSqlTestCase extends ESRestTestCase {
expectBadRequest(() -> runSql("SELECT foo FROM test"), containsString("1:8: Unknown column [foo]")); expectBadRequest(() -> runSql("SELECT foo FROM test"), containsString("1:8: Unknown column [foo]"));
} }
@Override
public void testSelectMissingFunction() throws Exception {
StringBuilder bulk = new StringBuilder();
bulk.append("{\"index\":{\"_id\":\"1\"}}\n");
bulk.append("{\"foo\":1}\n");
client().performRequest("POST", "/test/test/_bulk", singletonMap("refresh", "true"),
new StringEntity(bulk.toString(), ContentType.APPLICATION_JSON));
expectBadRequest(() -> runSql("SELECT missing(foo) FROM test"), containsString("1:8: Unknown function [missing]"));
}
private void expectBadRequest(ThrowingRunnable code, Matcher<String> errorMessageMatcher) { private void expectBadRequest(ThrowingRunnable code, Matcher<String> errorMessageMatcher) {
ResponseException e = expectThrows(ResponseException.class, code); ResponseException e = expectThrows(ResponseException.class, code);
assertEquals(400, e.getResponse().getStatusLine().getStatusCode()); assertEquals(400, e.getResponse().getStatusLine().getStatusCode());
@ -157,9 +178,10 @@ public abstract class RestSqlTestCase extends ESRestTestCase {
} }
private Map<String, Object> runSql(String suffix, HttpEntity sql) throws IOException { private Map<String, Object> runSql(String suffix, HttpEntity sql) throws IOException {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new TreeMap<>();
params.put("error_trace", "true"); params.put("error_trace", "true"); // Helps with debugging in case something crazy happens on the server.
params.put("format", "json"); params.put("pretty", "true"); // Improves error reporting readability
params.put("format", "json"); // JSON is easier to parse then a table
Response response = client().performRequest("POST", "/_sql" + suffix, params, sql); Response response = client().performRequest("POST", "/_sql" + suffix, params, sql);
try (InputStream content = response.getEntity().getContent()) { try (InputStream content = response.getEntity().getContent()) {
return XContentHelper.convertToMap(JsonXContent.jsonXContent, content, false); return XContentHelper.convertToMap(JsonXContent.jsonXContent, content, false);