/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.cassandra;
import static com.datastax.driver.core.ProtocolOptions.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS;
import static com.google.common.collect.FluentIterable.from;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_CLUSTER_NAME;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_COMPRESSION_PROTOCOL;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_CREDENTIALS_PASSWORD;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_CREDENTIALS_USERNAME;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_HOSTS;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_PORT;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.CASSANDRA_PROTOCOL_VERSION;
import static org.apache.zeppelin.cassandra.CassandraInterpreter.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.when;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
import info.archinnov.achilles.junit.AchillesResource;
import info.archinnov.achilles.junit.AchillesResourceBuilder;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import scala.io.Source;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
@RunWith(MockitoJUnitRunner.class)
public class CassandraInterpreterTest {
private static final String ARTISTS_TABLE = "zeppelin.artists";
@ClassRule
public static AchillesResource resource = AchillesResourceBuilder
.noEntityPackages()
.withKeyspaceName("zeppelin")
.withScript("prepare_schema.cql")
.withScript("prepare_data.cql")
.build();
private static Session session = resource.getNativeSession();
private static CassandraInterpreter interpreter;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private InterpreterContext intrContext;
@BeforeClass
public static void setUp() {
Properties properties = new Properties();
final Cluster cluster = resource.getNativeSession().getCluster();
properties.setProperty(CASSANDRA_CLUSTER_NAME, cluster.getClusterName());
properties.setProperty(CASSANDRA_COMPRESSION_PROTOCOL, "NONE");
properties.setProperty(CASSANDRA_CREDENTIALS_USERNAME, "none");
properties.setProperty(CASSANDRA_CREDENTIALS_PASSWORD, "none");
properties.setProperty(CASSANDRA_PROTOCOL_VERSION, "3");
properties.setProperty(CASSANDRA_LOAD_BALANCING_POLICY, "DEFAULT");
properties.setProperty(CASSANDRA_RETRY_POLICY, "DEFAULT");
properties.setProperty(CASSANDRA_RECONNECTION_POLICY, "DEFAULT");
properties.setProperty(CASSANDRA_SPECULATIVE_EXECUTION_POLICY, "DEFAULT");
properties.setProperty(CASSANDRA_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS,
DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS + "");
properties.setProperty(CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_LOCAL, "100");
properties.setProperty(CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_REMOTE, "100");
properties.setProperty(CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_LOCAL, "2");
properties.setProperty(CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_REMOTE, "1");
properties.setProperty(CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_LOCAL, "8");
properties.setProperty(CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_REMOTE, "2");
properties.setProperty(CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_LOCAL, "1024");
properties.setProperty(CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_REMOTE, "256");
properties.setProperty(CASSANDRA_POOLING_IDLE_TIMEOUT_SECONDS, "120");
properties.setProperty(CASSANDRA_POOLING_POOL_TIMEOUT_MILLIS, "5000");
properties.setProperty(CASSANDRA_POOLING_HEARTBEAT_INTERVAL_SECONDS, "30");
properties.setProperty(CASSANDRA_QUERY_DEFAULT_CONSISTENCY, "ONE");
properties.setProperty(CASSANDRA_QUERY_DEFAULT_SERIAL_CONSISTENCY, "SERIAL");
properties.setProperty(CASSANDRA_QUERY_DEFAULT_FETCH_SIZE, "5000");
properties.setProperty(CASSANDRA_SOCKET_CONNECTION_TIMEOUT_MILLIS, "5000");
properties.setProperty(CASSANDRA_SOCKET_READ_TIMEOUT_MILLIS, "12000");
properties.setProperty(CASSANDRA_SOCKET_TCP_NO_DELAY, "true");
properties.setProperty(CASSANDRA_HOSTS, from(cluster.getMetadata().getAllHosts()).first().get().getAddress().getHostAddress());
properties.setProperty(CASSANDRA_PORT, cluster.getConfiguration().getProtocolOptions().getPort()+"");
interpreter = new CassandraInterpreter(properties);
interpreter.open();
}
@AfterClass
public static void tearDown() {
interpreter.close();
}
@Before
public void prepareContext() {
when(intrContext.getParagraphTitle()).thenReturn("Paragraph1");
}
@Test
public void should_create_cluster_and_session_upon_call_to_open() throws Exception {
assertThat(interpreter.cluster).isNotNull();
assertThat(interpreter.cluster.getClusterName()).isEqualTo(resource.getNativeSession().getCluster().getClusterName());
assertThat(interpreter.session).isNotNull();
assertThat(interpreter.helper).isNotNull();
}
@Test
public void should_interpret_simple_select() throws Exception {
//Given
//When
final InterpreterResult actual = interpreter.interpret("SELECT * FROM " + ARTISTS_TABLE + " LIMIT 10;", intrContext);
//Then
assertThat(actual).isNotNull();
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("name\tborn\tcountry\tdied\tgender\tstyles\ttype\n" +
"Bogdan Raczynski\t1977-01-01\tPoland\tnull\tMale\t[Dance, Electro]\tPerson\n" +
"Krishna Das\t1947-05-31\tUSA\tnull\tMale\t[Unknown]\tPerson\n" +
"Sheryl Crow\t1962-02-11\tUSA\tnull\tFemale\t[Classic, Rock, Country, Blues, Pop, Folk]\tPerson\n" +
"Doof\t1968-08-31\tUnited Kingdom\tnull\tnull\t[Unknown]\tPerson\n" +
"House of Large Sizes\t1986-01-01\tUSA\t2003\tnull\t[Unknown]\tGroup\n" +
"Fanfarlo\t2006-01-01\tUnited Kingdom\tnull\tnull\t[Rock, Indie, Pop, Classic]\tGroup\n" +
"Jeff Beck\t1944-06-24\tUnited Kingdom\tnull\tMale\t[Rock, Pop, Classic]\tPerson\n" +
"Los Paranoias\tnull\tUnknown\tnull\tnull\t[Unknown]\tnull\n" +
"…And You Will Know Us by the Trail of Dead\t1994-01-01\tUSA\tnull\tnull\t[Rock, Pop, Classic]\tGroup\n");
}
@Test
public void should_interpret_select_statement() throws Exception {
//Given
//When
final InterpreterResult actual = interpreter.interpret("SELECT * FROM " + ARTISTS_TABLE + " LIMIT 2;", intrContext);
//Then
assertThat(actual).isNotNull();
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("name\tborn\tcountry\tdied\tgender\tstyles\ttype\n" +
"Bogdan Raczynski\t1977-01-01\tPoland\tnull\tMale\t[Dance, Electro]\tPerson\n" +
"Krishna Das\t1947-05-31\tUSA\tnull\tMale\t[Unknown]\tPerson\n");
}
@Test
public void should_interpret_multiple_statements_with_single_line_logged_batch() throws Exception {
//Given
String statements = "CREATE TABLE IF NOT EXISTS zeppelin.albums(\n" +
" title text PRIMARY KEY,\n" +
" artist text,\n" +
" year int\n" +
");\n" +
"BEGIN BATCH"+
" INSERT INTO zeppelin.albums(title,artist,year) VALUES('The Impossible Dream EP','Carter the Unstoppable Sex Machine',1992);"+
" INSERT INTO zeppelin.albums(title,artist,year) VALUES('The Way You Are','Tears for Fears',1983);"+
" INSERT INTO zeppelin.albums(title,artist,year) VALUES('Primitive','Soulfly',2003);"+
"APPLY BATCH;\n"+
"SELECT * FROM zeppelin.albums;";
//When
final InterpreterResult actual = interpreter.interpret(statements, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("title\tartist\tyear\n" +
"The Impossible Dream EP\tCarter the Unstoppable Sex Machine\t1992\n" +
"The Way You Are\tTears for Fears\t1983\n" +
"Primitive\tSoulfly\t2003\n");
}
@Test
public void should_throw_statement_not_having_semi_colon() throws Exception {
//Given
String statement = "SELECT * zeppelin.albums";
//When
final InterpreterResult actual = interpreter.interpret(statement, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message())
.contains("Error parsing input:\n" +
"\t'SELECT * zeppelin.albums'\n" +
"Did you forget to add ; (semi-colon) at the end of each CQL statement ?");
}
@Test
public void should_validate_statement() throws Exception {
//Given
String statement = "SELECT * zeppelin.albums;";
//When
final InterpreterResult actual = interpreter.interpret(statement, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message()).contains("line 1:9 missing K_FROM at 'zeppelin' (SELECT * [zeppelin]....)");
}
@Test
public void should_execute_statement_with_consistency_option() throws Exception {
//Given
String statement = "@consistency=THREE\n" +
"SELECT * FROM zeppelin.artists LIMIT 1;";
//When
final InterpreterResult actual = interpreter.interpret(statement, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message())
.contains("Not enough replica available for query at consistency THREE (3 required but only 1 alive)");
}
@Test
public void should_execute_statement_with_serial_consistency_option() throws Exception {
//Given
String statement = "@serialConsistency=SERIAL\n" +
"SELECT * FROM zeppelin.artists LIMIT 1;";
//When
final InterpreterResult actual = interpreter.interpret(statement, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
}
@Test
public void should_execute_statement_with_timestamp_option() throws Exception {
//Given
String statement1 = "INSERT INTO zeppelin.ts(key,val) VALUES('k','v1');";
String statement2 = "@timestamp=15\n" +
"INSERT INTO zeppelin.ts(key,val) VALUES('k','v2');";
// Insert v1 with current timestamp
interpreter.interpret(statement1, intrContext);
Thread.sleep(1);
//When
// Insert v2 with past timestamp
interpreter.interpret(statement2, intrContext);
final String actual = session.execute("SELECT * FROM zeppelin.ts LIMIT 1").one().getString("val");
//Then
assertThat(actual).isEqualTo("v1");
}
@Test
public void should_execute_statement_with_retry_policy() throws Exception {
//Given
String statement = "@retryPolicy=" + interpreter.LOGGING_DOWNGRADING_RETRY + "\n" +
"@consistency=THREE\n" +
"SELECT * FROM zeppelin.artists LIMIT 1;";
//When
final InterpreterResult actual = interpreter.interpret(statement, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
}
@Test
public void should_execute_prepared_and_bound_statements() throws Exception {
//Given
String queries = "@prepare[ps]=INSERT INTO zeppelin.prepared(key,val) VALUES(?,?)\n" +
"@prepare[select]=SELECT * FROM zeppelin.prepared WHERE key=:key\n" +
"@bind[ps]='myKey','myValue'\n" +
"@bind[select]='myKey'";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("key\tval\n" +
"myKey\tmyValue\n");
}
@Test
public void should_execute_bound_statement() throws Exception {
//Given
String queries = "@prepare[users_insert]=INSERT INTO zeppelin.users" +
"(login,firstname,lastname,addresses,location)" +
"VALUES(:login,:fn,:ln,:addresses,:loc)\n" +
"@bind[users_insert]='jdoe','John','DOE'," +
"{street_number: 3, street_name: 'Beverly Hills Bld', zip_code: 90209," +
" country: 'USA', extra_info: ['Right on the hills','Next to the post box']," +
" phone_numbers: {'home': 2016778524, 'office': 2015790847}}," +
"('USA', 90209, 'Beverly Hills')\n" +
"SELECT * FROM zeppelin.users WHERE login='jdoe';";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo(
"login\taddresses\tage\tdeceased\tfirstname\tlast_update\tlastname\tlocation\n" +
"jdoe\t" +
"{street_number:3, street_name:'Beverly Hills Bld', zip_code:90209," +
" country:'USA', extra_info:['Right on the hills', 'Next to the post box'], " +
"phone_numbers:{'office':2015790847, 'home':2016778524}}\tnull\t" +
"null\t" +
"John\t" +
"null\t" +
"DOE\t" +
"('USA', 90209, 'Beverly Hills')\n");
}
@Test
public void should_exception_when_executing_unknown_bound_statement() throws Exception {
//Given
String queries = "@bind[select_users]='jdoe'";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message())
.isEqualTo("The statement 'select_users' can not be bound to values. " +
"Are you sure you did prepare it with @prepare[select_users] ?");
}
@Test
public void should_extract_variable_from_statement() throws Exception {
//Given
when(intrContext.getGui().input("login", "hsue")).thenReturn("hsue");
when(intrContext.getGui().input("age", "27")).thenReturn("27");
String queries = "@prepare[test_insert_with_variable]=" +
"INSERT INTO zeppelin.users(login,firstname,lastname,age) VALUES(?,?,?,?)\n" +
"@bind[test_insert_with_variable]='{{login=hsue}}','Helen','SUE',{{age=27}}\n" +
"SELECT firstname,lastname,age FROM zeppelin.users WHERE login='hsue';";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("firstname\tlastname\tage\n" +
"Helen\tSUE\t27\n");
}
@Test
public void should_just_prepare_statement() throws Exception {
//Given
String queries = "@prepare[just_prepare]=SELECT name,country,styles FROM zeppelin.artists LIMIT 3";
final String expected = reformatHtml(
readTestResource("/scalate/NoResult.html"));
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_execute_bound_statement_with_no_bound_value() throws Exception {
//Given
String queries = "@prepare[select_no_bound_value]=SELECT name,country,styles FROM zeppelin.artists LIMIT 3\n" +
"@bind[select_no_bound_value]";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("name\tcountry\tstyles\n" +
"Bogdan Raczynski\tPoland\t[Dance, Electro]\n" +
"Krishna Das\tUSA\t[Unknown]\n" +
"Sheryl Crow\tUSA\t[Classic, Rock, Country, Blues, Pop, Folk]\n");
}
@Test
public void should_parse_date_value() throws Exception {
//Given
String queries = "@prepare[parse_date]=INSERT INTO zeppelin.users(login,last_update) VALUES(?,?)\n" +
"@bind[parse_date]='last_update','2015-07-30 12:00:01'\n" +
"SELECT last_update FROM zeppelin.users WHERE login='last_update';";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).contains("last_update\n" +
"Thu Jul 30 12:00:01");
}
@Test
public void should_bind_null_value() throws Exception {
//Given
String queries = "@prepare[bind_null]=INSERT INTO zeppelin.users(login,firstname,lastname) VALUES(?,?,?)\n" +
"@bind[bind_null]='bind_null',null,'NULL'\n" +
"SELECT firstname,lastname FROM zeppelin.users WHERE login='bind_null';";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("firstname\tlastname\n" +
"null\tNULL\n");
}
@Test
public void should_bind_boolean_value() throws Exception {
//Given
String queries = "@prepare[bind_boolean]=INSERT INTO zeppelin.users(login,deceased) VALUES(?,?)\n" +
"@bind[bind_boolean]='bind_bool',false\n" +
"SELECT login,deceased FROM zeppelin.users WHERE login='bind_bool';";
//When
final InterpreterResult actual = interpreter.interpret(queries, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(actual.message()).isEqualTo("login\tdeceased\n" +
"bind_bool\tfalse\n");
}
@Test
public void should_fail_when_executing_a_removed_prepared_statement() throws Exception {
//Given
String prepare_first = "@prepare[to_be_removed]=INSERT INTO zeppelin.users(login,deceased) VALUES(?,?)";
interpreter.interpret(prepare_first, intrContext);
String remove_prepared = "@remove_prepare[to_be_removed]\n" +
"@bind[to_be_removed]='bind_bool'";
//When
final InterpreterResult actual = interpreter.interpret(remove_prepared, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message()).isEqualTo("The statement 'to_be_removed' can not be bound to values. " +
"Are you sure you did prepare it with @prepare[to_be_removed] ?");
}
@Test
public void should_display_statistics_for_non_select_statement() throws Exception {
//Given
String query = "USE zeppelin;\nCREATE TABLE IF NOT EXISTS no_select(id int PRIMARY KEY);";
final String rawResult = reformatHtml(readTestResource("/scalate/NoResultWithExecutionInfo.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
final Cluster cluster = session.getCluster();
final int port = cluster.getConfiguration().getProtocolOptions().getPort();
final String address = cluster.getMetadata().getAllHosts().iterator().next()
.getAddress().getHostAddress()
.replaceAll("/", "").replaceAll("\\[", "").replaceAll("\\]","");
//Then
final String expected = rawResult.replaceAll("TRIED_HOSTS", address+":"+port)
.replaceAll("QUERIED_HOSTS", address +":"+port);
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_error_and_display_stack_trace() throws Exception {
//Given
String query = "@consistency=THREE\n" +
"SELECT * FROM zeppelin.users LIMIT 3;";
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message()).contains("All host(s) tried for query failed");
}
@Test
public void should_describe_cluster() throws Exception {
//Given
String query = "DESCRIBE CLUSTER;";
final String expected = reformatHtml(
readTestResource("/scalate/DescribeCluster.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_describe_keyspaces() throws Exception {
//Given
String query = "DESCRIBE KEYSPACES;";
final String expected = reformatHtml(
readTestResource("/scalate/DescribeKeyspaces.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_describe_keyspace() throws Exception {
//Given
String query = "DESCRIBE KEYSPACE live_data;";
final String expected = reformatHtml(
readTestResource("/scalate/DescribeKeyspace_live_data.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_describe_table() throws Exception {
//Given
String query = "DESCRIBE TABLE live_data.complex_table;";
final String expected = reformatHtml(
readTestResource("/scalate/DescribeTable_live_data_complex_table.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_describe_udt() throws Exception {
//Given
String query = "DESCRIBE TYPE live_data.address;";
final String expected = reformatHtml(
readTestResource("/scalate/DescribeType_live_data_address.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_describe_udt_withing_logged_in_keyspace() throws Exception {
//Given
String query = "USE live_data;\n" +
"DESCRIBE TYPE address;";
final String expected = reformatHtml(
readTestResource("/scalate/DescribeType_live_data_address_within_current_keyspace.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
@Test
public void should_error_describing_non_existing_table() throws Exception {
//Given
String query = "USE system;\n" +
"DESCRIBE TABLE complex_table;";
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message()).contains("Cannot find table system.complex_table");
}
@Test
public void should_error_describing_non_existing_udt() throws Exception {
//Given
String query = "USE system;\n" +
"DESCRIBE TYPE address;";
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.ERROR);
assertThat(actual.message()).contains("Cannot find type system.address");
}
@Test
public void should_show_help() throws Exception {
//Given
String query = "HELP;";
final String expected = reformatHtml(readTestResource("/scalate/Help.html"));
//When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
//Then
assertThat(actual.code()).isEqualTo(Code.SUCCESS);
assertThat(reformatHtml(actual.message())).isEqualTo(expected);
}
private static String reformatHtml(String rawHtml) {
return rawHtml
.replaceAll("\\s*\n\\s*","")
.replaceAll(">\\s+<", "><")
.replaceAll("(?s)data-target=\"#[a-f0-9-]+(?:_asCQL)?\"", "")
.replaceAll("(?s)id=\"[a-f0-9-]+(?:_asCQL)?\"", "")
.trim();
}
private static String readTestResource(String testResource) {
StringBuilder builder = new StringBuilder();
InputStream stream = testResource.getClass().getResourceAsStream(testResource);
try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
String line;
while ((line = br.readLine()) != null) {
builder.append(line).append("\n");
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return builder.toString();
}
}