/*
* 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.hadoop.hive.accumulo;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.mock.MockInstance;
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
import org.apache.hadoop.hive.accumulo.columns.ColumnEncoding;
import org.apache.hadoop.hive.accumulo.serde.AccumuloSerDeParameters;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.hive.metastore.api.SerDeInfo;
import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.hadoop.hive.ql.plan.TableDesc;
import org.apache.hadoop.hive.serde.serdeConstants;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.mockito.Mockito;
/**
*
*/
public class TestAccumuloStorageHandler {
protected AccumuloStorageHandler storageHandler;
@Rule
public TestName test = new TestName();
@Before
public void setup() {
storageHandler = new AccumuloStorageHandler();
}
@Test
public void testTablePropertiesPassedToOutputJobProperties() {
TableDesc tableDesc = Mockito.mock(TableDesc.class);
Properties props = new Properties();
Map<String,String> jobProperties = new HashMap<String,String>();
props.setProperty(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq1,cf:cq2,cf:cq3");
props.setProperty(serdeConstants.LIST_COLUMN_TYPES, "string:int:string");
props.setProperty(serdeConstants.LIST_COLUMNS, "name,age,email");
props.setProperty(AccumuloSerDeParameters.TABLE_NAME, "table");
props.setProperty(AccumuloSerDeParameters.VISIBILITY_LABEL_KEY, "foo");
Mockito.when(tableDesc.getProperties()).thenReturn(props);
storageHandler.configureOutputJobProperties(tableDesc, jobProperties);
Assert.assertEquals(3, jobProperties.size());
Assert.assertTrue("Job properties did not contain column mappings",
jobProperties.containsKey(AccumuloSerDeParameters.COLUMN_MAPPINGS));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.COLUMN_MAPPINGS),
jobProperties.get(AccumuloSerDeParameters.COLUMN_MAPPINGS));
Assert.assertTrue("Job properties did not contain accumulo table name",
jobProperties.containsKey(AccumuloSerDeParameters.TABLE_NAME));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.TABLE_NAME),
jobProperties.get(AccumuloSerDeParameters.TABLE_NAME));
Assert.assertTrue("Job properties did not contain visibility label",
jobProperties.containsKey(AccumuloSerDeParameters.VISIBILITY_LABEL_KEY));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.VISIBILITY_LABEL_KEY),
jobProperties.get(AccumuloSerDeParameters.VISIBILITY_LABEL_KEY));
}
@Test
public void testTablePropertiesPassedToInputJobProperties() {
TableDesc tableDesc = Mockito.mock(TableDesc.class);
Properties props = new Properties();
Map<String,String> jobProperties = new HashMap<String,String>();
props.setProperty(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq1,cf:cq2,cf:cq3");
props.setProperty(AccumuloSerDeParameters.TABLE_NAME, "table");
props.setProperty(AccumuloSerDeParameters.ITERATOR_PUSHDOWN_KEY, "true");
props
.setProperty(AccumuloSerDeParameters.DEFAULT_STORAGE_TYPE, ColumnEncoding.BINARY.getName());
props.setProperty(AccumuloSerDeParameters.AUTHORIZATIONS_KEY, "foo,bar");
Mockito.when(tableDesc.getProperties()).thenReturn(props);
storageHandler.configureInputJobProperties(tableDesc, jobProperties);
Assert.assertEquals(5, jobProperties.size());
Assert.assertTrue(jobProperties.containsKey(AccumuloSerDeParameters.COLUMN_MAPPINGS));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.COLUMN_MAPPINGS),
jobProperties.get(AccumuloSerDeParameters.COLUMN_MAPPINGS));
Assert.assertTrue(jobProperties.containsKey(AccumuloSerDeParameters.TABLE_NAME));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.TABLE_NAME),
jobProperties.get(AccumuloSerDeParameters.TABLE_NAME));
Assert.assertTrue(jobProperties.containsKey(AccumuloSerDeParameters.ITERATOR_PUSHDOWN_KEY));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.ITERATOR_PUSHDOWN_KEY),
jobProperties.get(AccumuloSerDeParameters.ITERATOR_PUSHDOWN_KEY));
Assert.assertTrue(jobProperties.containsKey(AccumuloSerDeParameters.DEFAULT_STORAGE_TYPE));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.DEFAULT_STORAGE_TYPE),
jobProperties.get(AccumuloSerDeParameters.DEFAULT_STORAGE_TYPE));
Assert.assertTrue(jobProperties.containsKey(AccumuloSerDeParameters.AUTHORIZATIONS_KEY));
Assert.assertEquals(props.getProperty(AccumuloSerDeParameters.AUTHORIZATIONS_KEY),
jobProperties.get(AccumuloSerDeParameters.AUTHORIZATIONS_KEY));
}
@Test(expected = IllegalArgumentException.class)
public void testNonBooleanIteratorPushdownValue() {
TableDesc tableDesc = Mockito.mock(TableDesc.class);
Properties props = new Properties();
Map<String,String> jobProperties = new HashMap<String,String>();
props.setProperty(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq1,cf:cq2,cf:cq3");
props.setProperty(AccumuloSerDeParameters.TABLE_NAME, "table");
props.setProperty(AccumuloSerDeParameters.ITERATOR_PUSHDOWN_KEY, "foo");
Mockito.when(tableDesc.getProperties()).thenReturn(props);
storageHandler.configureInputJobProperties(tableDesc, jobProperties);
}
@Test(expected = IllegalArgumentException.class)
public void testEmptyIteratorPushdownValue() {
TableDesc tableDesc = Mockito.mock(TableDesc.class);
Properties props = new Properties();
Map<String,String> jobProperties = new HashMap<String,String>();
props.setProperty(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq1,cf:cq2,cf:cq3");
props.setProperty(AccumuloSerDeParameters.TABLE_NAME, "table");
props.setProperty(AccumuloSerDeParameters.ITERATOR_PUSHDOWN_KEY, "");
Mockito.when(tableDesc.getProperties()).thenReturn(props);
storageHandler.configureInputJobProperties(tableDesc, jobProperties);
}
@Test
public void testTableJobPropertiesCallsInputAndOutputMethods() {
AccumuloStorageHandler mockStorageHandler = Mockito.mock(AccumuloStorageHandler.class);
TableDesc tableDesc = Mockito.mock(TableDesc.class);
Map<String,String> jobProperties = new HashMap<String,String>();
Mockito.doCallRealMethod().when(mockStorageHandler)
.configureTableJobProperties(tableDesc, jobProperties);
// configureTableJobProperties shouldn't be getting called by Hive, but, if it somehow does,
// we should just set all of the configurations for input and output.
mockStorageHandler.configureTableJobProperties(tableDesc, jobProperties);
Mockito.verify(mockStorageHandler).configureInputJobProperties(tableDesc, jobProperties);
Mockito.verify(mockStorageHandler).configureOutputJobProperties(tableDesc, jobProperties);
}
@Test
public void testPreCreateTable() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
String tableName = "table";
// Define the SerDe Parameters
Map<String,String> params = new HashMap<String,String>();
params.put(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq");
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
Table table = Mockito.mock(Table.class);
SerDeInfo serDeInfo = Mockito.mock(SerDeInfo.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).preCreateTable(table);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the mocked StorageDescriptor
Mockito.when(table.getSd()).thenReturn(sd);
// No location expected with AccumuloStorageHandler
Mockito.when(sd.getLocation()).thenReturn(null);
// Return mocked SerDeInfo
Mockito.when(sd.getSerdeInfo()).thenReturn(serDeInfo);
// Custom parameters
Mockito.when(serDeInfo.getParameters()).thenReturn(params);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.preCreateTable(table);
Assert.assertTrue("Table does not exist when we expect it to",
conn.tableOperations().exists(tableName));
}
@Test(expected = MetaException.class)
public void testMissingColumnMappingFails() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
String tableName = "table";
// Empty parameters are sent, no COLUMN_MAPPING
Map<String,String> params = new HashMap<String,String>();
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
Table table = Mockito.mock(Table.class);
SerDeInfo serDeInfo = Mockito.mock(SerDeInfo.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).preCreateTable(table);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the mocked StorageDescriptor
Mockito.when(table.getSd()).thenReturn(sd);
// No location expected with AccumuloStorageHandler
Mockito.when(sd.getLocation()).thenReturn(null);
// Return mocked SerDeInfo
Mockito.when(sd.getSerdeInfo()).thenReturn(serDeInfo);
// Custom parameters
Mockito.when(serDeInfo.getParameters()).thenReturn(params);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.preCreateTable(table);
}
@Test(expected = MetaException.class)
public void testNonNullLocation() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
String tableName = "table";
// Empty parameters are sent, no COLUMN_MAPPING
Map<String,String> params = new HashMap<String,String>();
params.put(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq");
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
Table table = Mockito.mock(Table.class);
SerDeInfo serDeInfo = Mockito.mock(SerDeInfo.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).preCreateTable(table);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the mocked StorageDescriptor
Mockito.when(table.getSd()).thenReturn(sd);
// No location expected with AccumuloStorageHandler
Mockito.when(sd.getLocation()).thenReturn("foobar");
// Return mocked SerDeInfo
Mockito.when(sd.getSerdeInfo()).thenReturn(serDeInfo);
// Custom parameters
Mockito.when(serDeInfo.getParameters()).thenReturn(params);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.preCreateTable(table);
}
@Test(expected = MetaException.class)
public void testExternalNonExistentTableFails() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
String tableName = "table";
// Define the SerDe Parameters
Map<String,String> params = new HashMap<String,String>();
params.put(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq");
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
Table table = Mockito.mock(Table.class);
SerDeInfo serDeInfo = Mockito.mock(SerDeInfo.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).preCreateTable(table);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Is an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(true);
// Return the mocked StorageDescriptor
Mockito.when(table.getSd()).thenReturn(sd);
// No location expected with AccumuloStorageHandler
Mockito.when(sd.getLocation()).thenReturn(null);
// Return mocked SerDeInfo
Mockito.when(sd.getSerdeInfo()).thenReturn(serDeInfo);
// Custom parameters
Mockito.when(serDeInfo.getParameters()).thenReturn(params);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.preCreateTable(table);
}
@Test(expected = MetaException.class)
public void testNonExternalExistentTable() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
String tableName = "table";
// Create the table
conn.tableOperations().create(tableName);
// Define the SerDe Parameters
Map<String,String> params = new HashMap<String,String>();
params.put(AccumuloSerDeParameters.COLUMN_MAPPINGS, "cf:cq");
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
Table table = Mockito.mock(Table.class);
SerDeInfo serDeInfo = Mockito.mock(SerDeInfo.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).preCreateTable(table);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Is not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the mocked StorageDescriptor
Mockito.when(table.getSd()).thenReturn(sd);
// No location expected with AccumuloStorageHandler
Mockito.when(sd.getLocation()).thenReturn(null);
// Return mocked SerDeInfo
Mockito.when(sd.getSerdeInfo()).thenReturn(serDeInfo);
// Custom parameters
Mockito.when(serDeInfo.getParameters()).thenReturn(params);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.preCreateTable(table);
}
@Test()
public void testRollbackCreateTableOnNonExistentTable() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
String tableName = "table";
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
Table table = Mockito.mock(Table.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).rollbackCreateTable(table);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Is not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.rollbackCreateTable(table);
}
@Test()
public void testRollbackCreateTableDeletesExistentTable() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
String tableName = "table";
// Create the table
conn.tableOperations().create(tableName);
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
Table table = Mockito.mock(Table.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).rollbackCreateTable(table);
Mockito.doCallRealMethod().when(storageHandler).commitDropTable(table, true);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Is not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.rollbackCreateTable(table);
Assert.assertFalse(conn.tableOperations().exists(tableName));
}
@Test()
public void testRollbackCreateTableDoesntDeleteExternalExistentTable() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
String tableName = "table";
// Create the table
conn.tableOperations().create(tableName);
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
Table table = Mockito.mock(Table.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).rollbackCreateTable(table);
Mockito.doCallRealMethod().when(storageHandler).commitDropTable(table, true);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Is not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(true);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.rollbackCreateTable(table);
Assert.assertTrue(conn.tableOperations().exists(tableName));
}
@Test
public void testDropTableWithoutDeleteLeavesTableIntact() throws Exception {
MockInstance inst = new MockInstance(test.getMethodName());
Connector conn = inst.getConnector("root", new PasswordToken(""));
AccumuloStorageHandler storageHandler = Mockito.mock(AccumuloStorageHandler.class);
String tableName = "table";
// Create the table
conn.tableOperations().create(tableName);
AccumuloConnectionParameters connectionParams = Mockito
.mock(AccumuloConnectionParameters.class);
Table table = Mockito.mock(Table.class);
// Call the real preCreateTable method
Mockito.doCallRealMethod().when(storageHandler).commitDropTable(table, false);
// Return our known table name
Mockito.when(storageHandler.getTableName(table)).thenReturn(tableName);
// Is not an EXTERNAL table
Mockito.when(storageHandler.isExternalTable(table)).thenReturn(false);
// Return the MockInstance's Connector
Mockito.when(connectionParams.getConnector()).thenReturn(conn);
storageHandler.connectionParams = connectionParams;
storageHandler.rollbackCreateTable(table);
Assert.assertTrue(conn.tableOperations().exists(tableName));
}
}