blob: ad2d50b710c69e9546346b8e6155fde37d021cc3 [file] [log] [blame]
/**
* 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.tajo.cli.tsql;
import com.google.common.io.NullOutputStream;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.PosixParser;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.tajo.ConfigKey;
import org.apache.tajo.SessionVars;
import org.apache.tajo.TajoTestingCluster;
import org.apache.tajo.TpchTestBase;
import org.apache.tajo.catalog.CatalogUtil;
import org.apache.tajo.catalog.TableDesc;
import org.apache.tajo.client.ClientParameters;
import org.apache.tajo.client.QueryStatus;
import org.apache.tajo.client.TajoClient;
import org.apache.tajo.conf.TajoConf;
import org.apache.tajo.rpc.RpcConstants;
import org.apache.tajo.storage.StorageUtil;
import org.apache.tajo.storage.TablespaceManager;
import org.apache.tajo.util.FileUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import java.io.*;
import java.net.URL;
import java.util.Properties;
import static org.junit.Assert.*;
public class TestTajoCli {
protected static final TpchTestBase testBase;
protected static final TajoTestingCluster cluster;
/** the base path of result directories */
protected static final Path resultBasePath;
static {
testBase = TpchTestBase.getInstance();
cluster = testBase.getTestingCluster();
URL resultBaseURL = ClassLoader.getSystemResource("results");
resultBasePath = new Path(resultBaseURL.toString());
}
private TajoCli tajoCli;
private Path currentResultPath;
private ByteArrayOutputStream out;
@Rule
public TestName name = new TestName();
public TestTajoCli() {
String className = getClass().getSimpleName();
currentResultPath = new Path(resultBasePath, className);
}
@Before
public void setUp() throws Exception {
out = new ByteArrayOutputStream();
Properties connParams = new Properties();
connParams.setProperty(RpcConstants.CLIENT_RETRY_NUM, "3");
tajoCli = new TajoCli(cluster.getConfiguration(), new String[]{}, connParams, System.in, out);
}
@After
public void tearDown() throws IOException {
out.close();
if (tajoCli != null) {
tajoCli.close();
}
}
private static void setVar(TajoCli cli, ConfigKey key, String val) throws Exception {
cli.executeMetaCommand("\\set " + key.keyname() + " " + val);
}
private static void assertSessionVar(TajoCli cli, String key, String expectedVal) {
assertEquals(cli.getContext().getCliSideVar(key), expectedVal);
}
private void assertOutputResult(String actual) throws Exception {
assertOutputResult(name.getMethodName() + ".result", actual);
}
private void assertOutputResult(String expectedResultFile, String actual) throws Exception {
assertOutputResult(expectedResultFile, actual, null, null);
}
private void assertOutputResult(String expectedResultFile, String actual, String[] paramKeys, String[] paramValues)
throws Exception {
FileSystem fs = currentResultPath.getFileSystem(testBase.getTestingCluster().getConfiguration());
Path resultFile = StorageUtil.concatPath(currentResultPath, expectedResultFile);
assertTrue(resultFile.toString() + " existence check", fs.exists(resultFile));
String expectedResult = FileUtil.readTextFile(new File(resultFile.toUri()));
if (paramKeys != null) {
for (int i = 0; i < paramKeys.length; i++) {
if (i < paramValues.length) {
expectedResult = expectedResult.replace(paramKeys[i], paramValues[i]);
}
}
}
assertEquals(expectedResult.trim(), actual.trim());
}
@Test
public void testParseParam() throws Exception {
String[] args = new String[]{"-f", "test.sql", "--param", "test1=10", "--param", "test2=20"};
CommandLineParser parser = new PosixParser();
CommandLine cmd = parser.parse(TajoCli.options, args);
String fileName = cmd.getOptionValue("f");
assertNotNull(fileName);
assertEquals(args[1], fileName);
String[] paramValues = cmd.getOptionValues("param");
assertNotNull(paramValues);
assertEquals(2, paramValues.length);
assertEquals("test1=10", paramValues[0]);
assertEquals("test2=20", paramValues[1]);
}
@Test
public void testParseConf() throws Exception {
String[] args = new String[]{"--conf", "tajo.cli.print.pause=false",
"--conf", "tajo.executor.join.inner.in-memory-table-num=256"};
CommandLineParser parser = new PosixParser();
CommandLine cmd = parser.parse(TajoCli.options, args);
String[] confValues = cmd.getOptionValues("conf");
assertNotNull(confValues);
assertEquals(2, confValues.length);
assertEquals("tajo.cli.print.pause=false", confValues[0]);
assertEquals("tajo.executor.join.inner.in-memory-table-num=256", confValues[1]);
TajoConf tajoConf = TpchTestBase.getInstance().getTestingCluster().getConfiguration();
TajoCli testCli = new TajoCli(tajoConf, args, null, System.in, System.out);
try {
assertEquals("false", testCli.getContext().get(SessionVars.CLI_PAGING_ENABLED));
assertEquals("256", testCli.getContext().getConf().get("tajo.executor.join.inner.in-memory-table-num"));
} finally {
testCli.close();
}
}
@Test
public void testReplaceParam() throws Exception {
String sql = "select * from lineitem where l_tax > ${tax} and l_returnflag > '${returnflag}'";
String[] params = new String[]{"tax=10", "returnflag=A"};
String expected = "select * from lineitem where l_tax > 10 and l_returnflag > 'A'";
assertEquals(expected, TajoCli.replaceParam(sql, params));
}
@Test
public void testLocalQueryWithoutFrom() throws Exception {
String sql = "select 'abc', '123'; select substr('123456', 1,3);";
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
tajoCli.executeScript(sql);
String consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
}
@Test
public void testConnectDatabase() throws Exception {
String databaseName;
if (cluster.isHiveCatalogStoreRunning()) {
databaseName = "TEST_CONNECTION_DATABASE".toLowerCase();
} else {
databaseName = "TEST_CONNECTION_DATABASE";
}
String sql = "create database \"" + databaseName + "\";";
tajoCli.executeScript(sql);
tajoCli.executeMetaCommand("\\c " + databaseName);
assertEquals(databaseName, tajoCli.getContext().getCurrentDatabase());
tajoCli.executeMetaCommand("\\c default");
assertEquals("default", tajoCli.getContext().getCurrentDatabase());
tajoCli.executeMetaCommand("\\c \"" + databaseName + "\"");
assertEquals(databaseName, tajoCli.getContext().getCurrentDatabase());
}
private void verifyDescTable(String sql, String tableName, String resultFileName) throws Exception {
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
tajoCli.executeScript(sql);
tajoCli.executeMetaCommand("\\d " + tableName);
tajoCli.executeMetaCommand("\\d \"" + tableName + "\"");
String consoleResult = new String(out.toByteArray());
if (!cluster.isHiveCatalogStoreRunning()) {
assertOutputResult(resultFileName, consoleResult, new String[]{"${table.path}"},
new String[]{TablespaceManager.getDefault().getTableUri("default", tableName).toString()});
}
}
@Test
public void testDescTable() throws Exception {
String tableName;
if (cluster.isHiveCatalogStoreRunning()) {
tableName = "TEST_DESC_TABLE".toLowerCase();
} else {
tableName = "TEST_DESC_TABLE";
}
String sql = "create table \"" + tableName + "\" (col1 int4, col2 int4);";
verifyDescTable(sql, tableName, "testDescTable.result");
}
@Test
public void testDescTableForNestedSchema() throws Exception {
String tableName;
if (cluster.isHiveCatalogStoreRunning()) {
tableName = "TEST_DESC_TABLE_NESTED".toLowerCase();
} else {
tableName = "TEST_DESC_TABLE_NESTED";
}
String sql = "create table \"" + tableName + "\" (col1 int4, col2 int4, col3 record (col4 record (col5 text)));";
verifyDescTable(sql, tableName, "testDescTableForNestedSchema.result");
}
@Test
public void testSelectResultWithNullFalse() throws Exception {
String sql =
"select\n" +
" c_custkey,\n" +
" orders.o_orderkey,\n" +
" orders.o_orderstatus \n" +
"from\n" +
" orders full outer join customer on c_custkey = o_orderkey\n" +
"order by\n" +
" c_custkey,\n" +
" orders.o_orderkey;\n";
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
tajoCli.executeScript(sql);
String consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
}
private void verifySelectResultWithNullTrue() throws Exception {
String sql =
"select\n" +
" c_custkey,\n" +
" orders.o_orderkey,\n" +
" orders.o_orderstatus \n" +
"from\n" +
" orders full outer join customer on c_custkey = o_orderkey\n" +
"order by\n" +
" c_custkey,\n" +
" orders.o_orderkey;\n";
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
assertSessionVar(tajoCli, SessionVars.CLI_NULL_CHAR.keyname(), "testnull");
tajoCli.executeScript(sql);
String consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
}
@Test
public void testSelectResultWithNullTrueDeprecated() throws Exception {
setVar(tajoCli, TajoConf.ConfVars.$CLI_NULL_CHAR, "testnull");
verifySelectResultWithNullTrue();
}
@Test
public void testSelectResultWithNullTrue() throws Exception {
setVar(tajoCli, SessionVars.CLI_NULL_CHAR, "testnull");
verifySelectResultWithNullTrue();
}
private void verifyStopWhenError() throws Exception {
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
assertSessionVar(tajoCli, SessionVars.ON_ERROR_STOP.keyname(), "true");
tajoCli.executeScript("select count(*) from lineitem; " +
"select count(*) from lineitem2; " +
"select count(*) from orders");
String consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
}
@Test
public void testGetConf() throws Exception {
TajoConf tajoConf = TpchTestBase.getInstance().getTestingCluster().getConfiguration();
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
ByteArrayOutputStream out = new ByteArrayOutputStream();
TajoCli tajoCli = new TajoCli(tajoConf, new String[]{}, null, System.in, out);
try {
tajoCli.executeMetaCommand("\\getconf tajo.rootdir");
String consoleResult = new String(out.toByteArray());
assertEquals(consoleResult, tajoCli.getContext().getConf().getVar(TajoConf.ConfVars.ROOT_DIR) + "\n");
} finally {
tajoCli.close();
}
}
@Test
public void testShowMasters() throws Exception {
TajoConf tajoConf = TpchTestBase.getInstance().getTestingCluster().getConfiguration();
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
ByteArrayOutputStream out = new ByteArrayOutputStream();
TajoCli tajoCli = new TajoCli(tajoConf, new String[]{}, null, System.in, out);
tajoCli.executeMetaCommand("\\admin -showmasters");
String consoleResult = new String(out.toByteArray());
String masterAddress = tajoCli.getContext().getConf().getVar(TajoConf.ConfVars.TAJO_MASTER_UMBILICAL_RPC_ADDRESS);
String host = masterAddress.split(":")[0];
tajoCli.close();
assertEquals(consoleResult, host + "\n");
}
@Test
public void testStopWhenErrorDeprecated() throws Exception {
tajoCli.executeMetaCommand("\\set tajo.cli.error.stop true");
verifyStopWhenError();
}
@Test
public void testStopWhenError() throws Exception {
tajoCli.executeMetaCommand("\\set ON_ERROR_STOP true");
verifyStopWhenError();
}
@Test
public void testRunWhenError() throws Exception {
Thread t = new Thread() {
public void run() {
try {
PipedOutputStream po = new PipedOutputStream();
InputStream is = new PipedInputStream(po);
ByteArrayOutputStream out = new ByteArrayOutputStream();
TajoConf tajoConf = new TajoConf();
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
Properties connParams = new Properties();
connParams.setProperty(ClientParameters.RETRY, "3");
TajoCli tc = new TajoCli(tajoConf, new String[]{}, connParams, is, out);
tc.executeMetaCommand("\\set ON_ERROR_STOP false");
assertSessionVar(tc, SessionVars.ON_ERROR_STOP.keyname(), "false");
po.write(new String("asdf;\nqwe;\nzxcv;\n").getBytes());
tc.runShell();
} catch (Exception e) {
throw new RuntimeException("Cannot run thread in testRunWhenError", e);
}
}
};
t.start();
Thread.sleep(1000);
if(!t.isAlive()) {
fail("TSQL should be alive");
} else {
t.interrupt();
t.join();
}
}
@Test
public void testHelpSessionVars() throws Exception {
tajoCli.executeMetaCommand("\\help set");
assertOutputResult(new String(out.toByteArray()));
}
@Test
public void testTimeZoneSessionVars1() throws Exception {
tajoCli.executeMetaCommand("\\set TIMEZONE GMT+1");
tajoCli.executeMetaCommand("\\set");
String output = new String(out.toByteArray());
assertTrue(output.contains("'TIMEZONE'='GMT+1'"));
}
@Test
public void testTimeZoneSessionVars2() throws Exception {
tajoCli.executeScript("SET TIME ZONE 'GMT+2'");
tajoCli.executeMetaCommand("\\set");
String output = new String(out.toByteArray());
assertTrue(output.contains("'TIMEZONE'='GMT+2'"));
}
@Test
public void testTimeZoneTest1() throws Exception {
String tableName = "test1";
tajoCli.executeMetaCommand("\\set TIMEZONE GMT+0");
tajoCli.executeScript("create table " + tableName + " (col1 TIMESTAMP)");
tajoCli.executeScript("insert into " + tableName + " select to_timestamp(0)");
tajoCli.executeScript("select * from " + tableName);
String consoleResult = new String(out.toByteArray());
tajoCli.executeScript("DROP TABLE " + tableName + " PURGE");
assertTrue(consoleResult.contains("1970-01-01 00:00:00"));
}
@Test
public void testTimeZoneTest2() throws Exception {
String tableName = "test1";
tajoCli.executeMetaCommand("\\set TIMEZONE GMT+1");
tajoCli.executeScript("create table " + tableName + " (col1 TIMESTAMP)");
tajoCli.executeScript("insert into " + tableName + " select to_timestamp(0)");
tajoCli.executeScript("select * from " + tableName);
String consoleResult = new String(out.toByteArray());
tajoCli.executeScript("DROP TABLE " + tableName + " PURGE");
assertTrue(consoleResult.contains("1970-01-01 00:00:00"));
}
@Test(timeout = 3000)
public void testNonForwardQueryPause() throws Exception {
final String sql = "select * from default.lineitem";
TajoCli cli = null;
try {
TableDesc tableDesc = cluster.getMaster().getCatalog().getTableDesc("default", "lineitem");
assertNotNull(tableDesc);
assertEquals(0L, tableDesc.getStats().getNumRows().longValue());
InputStream testInput = new ByteArrayInputStream(new byte[]{(byte) DefaultTajoCliOutputFormatter.QUIT_COMMAND});
cli = new TajoCli(cluster.getConfiguration(), new String[]{}, null, testInput, out);
setVar(cli, SessionVars.CLI_PAGE_ROWS, "2");
setVar(cli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
cli.executeScript(sql);
String consoleResult;
consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
} finally {
cli.close();
}
}
@Test
public void testResultRowNumWhenSelectingOnPartitionedTable() throws Exception {
try (TajoCli cli2 = new TajoCli(cluster.getConfiguration(), new String[]{}, null, System.in,
new NullOutputStream())) {
cli2.executeScript("create table region_part (r_regionkey int8, r_name text) " +
"partition by column (r_comment text) as select * from region");
setVar(tajoCli, SessionVars.CLI_FORMATTER_CLASS, TajoCliOutputTestFormatter.class.getName());
tajoCli.executeScript("select r_comment from region_part where r_comment = 'hs use ironic, even requests. s'");
String consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
} finally {
tajoCli.executeScript("drop table region_part purge");
}
}
// TODO: This should be removed at TAJO-1891
@Test
public void testAddPartitionNotimplementedException() throws Exception {
String tableName = CatalogUtil.normalizeIdentifier("testAddPartitionNotimplementedException");
tajoCli.executeScript("create table " + tableName + " (col1 int4, col2 int4) partition by column(key float8)");
tajoCli.executeScript("alter table " + tableName + " add partition (key2 = 0.1)");
String consoleResult;
consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
}
// TODO: This should be added at TAJO-1891
public void testAlterTableAddDropPartition() throws Exception {
String tableName = CatalogUtil.normalizeIdentifier("testAlterTableAddPartition");
tajoCli.executeScript("create table " + tableName + " (col1 int4, col2 int4) partition by column(key float8)");
tajoCli.executeScript("alter table " + tableName + " add partition (key2 = 0.1)");
tajoCli.executeScript("alter table " + tableName + " add partition (key = 0.1)");
tajoCli.executeScript("alter table " + tableName + " drop partition (key = 0.1)");
tajoCli.executeScript("alter table " + tableName + " drop partition (key = 0.1)");
tajoCli.executeScript("drop table " + tableName);
tajoCli.executeScript("create table " + tableName
+ " (col1 int4, col2 int4) partition by column(col3 float8, col4 int4)");
TajoClient client = testBase.getTestingCluster().newTajoClient();
TableDesc tableDesc = client.getTableDesc(tableName);
String partitionLocation = tableDesc.getUri().toString() + "/col5=0.1/col6=10";
tajoCli.executeScript("alter table " + tableName + " add partition (col3 = 0.1, col4 = 10)"
+ " location '" + partitionLocation + "'");
Path partitionPath = new Path(partitionLocation);
FileSystem fs = testBase.getTestingCluster().getDefaultFileSystem();
assertTrue(fs.exists(partitionPath));
tajoCli.executeScript("alter table " + tableName + " drop partition (col3 = 0.1, col4 = 10)");
String consoleResult = new String(out.toByteArray());
assertOutputResult(consoleResult);
}
public static class TajoCliOutputTestFormatter extends DefaultTajoCliOutputFormatter {
@Override
protected String getResponseTimeReadable(float responseTime) {
return "";
}
@Override
public void printProgress(PrintWriter sout, QueryStatus status) {
//nothing to do
}
}
}