package com.thinkbiganalytics.ingest;
/*-
* #%L
* thinkbig-nifi-core-processors
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed 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.
* #L%
*/
import com.google.common.collect.ImmutableSet;
import com.klarna.hiverunner.HiveShell;
import com.klarna.hiverunner.StandaloneHiveRunner;
import com.klarna.hiverunner.annotations.HiveProperties;
import com.klarna.hiverunner.annotations.HiveRunnerSetup;
import com.klarna.hiverunner.annotations.HiveSQL;
import com.klarna.hiverunner.config.HiveRunnerConfig;
import com.thinkbiganalytics.util.ColumnSpec;
import com.thinkbiganalytics.util.TableRegisterConfiguration;
import com.thinkbiganalytics.util.TableType;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@RunWith(StandaloneHiveRunner.class)
public class TableRegisterSupportTest {
/**
* Explicit test class configuration of the HiveRunner runtime. See {@link HiveRunnerConfig} for further details.
*/
@HiveRunnerSetup
public final HiveRunnerConfig CONFIG = new HiveRunnerConfig() {{
setHiveExecutionEngine("mr");
}};
final Connection connection = Mockito.mock(Connection.class);
/**
* Cater for all the parameters in the script that we want to test. Note that the "hadoop.tmp.dir" is one of the dirs defined by the test harness
*/
@HiveProperties
public Map<String, String> hiveProperties = MapUtils.putAll(new HashMap<String, String>(), new String[]{
"MY.HDFS.DIR", "${hadoop.tmp.dir}",
"my.schema", "bar",
});
/**
* Define the script files under test. The files will be loaded in the given order. <p/> The HiveRunner instantiate and inject the HiveShell
*/
@HiveSQL(files = {
"hive-test-support/create_table.sql"
}, encoding = "UTF-8")
private HiveShell hiveShell;
@Test
public void testShowLocation() {
List<Object[]> values = hiveShell.executeStatement("show table extended like foo");
for (Object[] o : values) {
String value = o[0].toString();
if (value.startsWith("location:")) {
System.out.println(value.substring(9));
}
}
}
@Test
public void testSplit() {
// Extract schema vs table
String[] schemaPart = "foo.bar".split("\\.");
assertEquals(schemaPart.length, 2);
String schema = schemaPart[0];
String targetTable = schemaPart[1];
assertNotNull(schema);
assertNotNull(targetTable);
}
@Test
public void testTableCreate() {
ColumnSpec[] specs = ColumnSpec.createFromString("id|bigint|my comment\nname|string\ncompany|string|some description\nzip|string\nphone|string\nemail|string\ncountry|string\nhired|date");
ColumnSpec[] parts = ColumnSpec.createFromString("year|int\ncountry|string");
TableRegisterSupport support = new TableRegisterSupport(connection);
TableType[] tableTypes = new TableType[]{TableType.FEED, TableType.INVALID, TableType.VALID, TableType.MASTER};
for (TableType tableType : tableTypes) {
String
ddl =
support.createDDL("bar", "employee", specs, parts, "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'", "stored as orc", "tblproperties (\"orc.compress\"=\"SNAPPY\")",
tableType);
// Hack to make a legal file root
ddl = ddl.replace("LOCATION '", "LOCATION '${hiveconf:MY.HDFS.DIR}");
hiveShell.execute(ddl);
}
}
@Test
public void testTableCreateS3() {
ColumnSpec[] specs = ColumnSpec.createFromString("id|bigint|my comment\nname|string\ncompany|string|some description\nzip|string\nphone|string\nemail|string\ncountry|string\nhired|date");
ColumnSpec[] parts = ColumnSpec.createFromString("year|int\ncountry|string");
TableRegisterConfiguration conf = new TableRegisterConfiguration("s3a://testBucket/model.db/", "s3a://testBucket/model.db/", "s3a://testBucket/app/warehouse/");
TableRegisterSupport support = new TableRegisterSupport(connection, conf);
TableType[] tableTypes = new TableType[]{TableType.FEED, TableType.INVALID, TableType.VALID, TableType.MASTER};
for (TableType tableType : tableTypes) {
String ddl =
support.createDDL("bar", "employee", specs, parts, "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'", "stored as orc", "tblproperties (\"orc.compress\"=\"SNAPPY\")",
tableType);
String location = StringUtils.substringBetween(ddl, "LOCATION '", "'");
if (tableType == TableType.MASTER) {
assertEquals("Master location does not match", "s3a://testBucket/app/warehouse/bar/employee", location);
} else {
assertEquals("Locations do not match", "s3a://testBucket/model.db/bar/employee/" + tableType.toString().toLowerCase(), location);
}
}
}
/**
* Verify dropping a table.
*/
@Test
public void testDropTable() throws Exception {
// Mock SQL objects
final Statement statement = Mockito.mock(Statement.class);
Mockito.when(statement.execute(Mockito.anyString())).then(invocation -> {
final String sql = (String) invocation.getArguments()[0];
if (sql.equals("DROP TABLE IF EXISTS `invalid`")) {
throw new SQLException();
}
return true;
});
Mockito.when(connection.createStatement()).thenReturn(statement);
// Test dropping table with success
final TableRegisterSupport support = new TableRegisterSupport(connection);
Assert.assertTrue(support.dropTable("`feed`"));
Mockito.verify(statement).execute("DROP TABLE IF EXISTS `feed`");
// Test dropping table with exception
Assert.assertFalse(support.dropTable("`invalid`"));
}
/**
* Verify exception if the connection is null.
*/
@Test(expected = NullPointerException.class)
public void testDropTableWithNullConnection() {
new TableRegisterSupport(null).dropTable("invalid");
}
/**
* Verify dropping multiple tables.
*/
@Test
public void testDropTables() throws Exception {
// Mock SQL objects
final Statement statement = Mockito.mock(Statement.class);
Mockito.when(statement.execute(Mockito.anyString())).then(invocation -> {
final String sql = (String) invocation.getArguments()[0];
if (sql.startsWith("DROP TABLE IF EXISTS `invalid`")) {
throw new SQLException();
}
return true;
});
final Connection connection = Mockito.mock(Connection.class);
Mockito.when(connection.createStatement()).thenReturn(statement);
// Test dropping tables with success
TableRegisterSupport support = new TableRegisterSupport(connection);
Assert.assertTrue(support.dropTables("cat", "feed", EnumSet.of(TableType.MASTER, TableType.VALID, TableType.INVALID), ImmutableSet.of("backup.feed")));
Mockito.verify(statement).execute("DROP TABLE IF EXISTS `cat`.`feed`");
Mockito.verify(statement).execute("DROP TABLE IF EXISTS `cat`.`feed_valid`");
Mockito.verify(statement).execute("DROP TABLE IF EXISTS `cat`.`feed_invalid`");
Mockito.verify(statement).execute("DROP TABLE IF EXISTS backup.feed");
// Test dropping tables with exception
Assert.assertFalse(support.dropTables("invalid", "feed", EnumSet.allOf(TableType.class), ImmutableSet.of()));
Assert.assertFalse(support.dropTables("cat", "feed", ImmutableSet.of(), ImmutableSet.of("`invalid`")));
}
}