/*
* Copyright 2013 eBuddy B.V.
*
* 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.
*/
package com.ebuddy.cassandra.dao;
import static com.ebuddy.cassandra.dao.AbstractColumnFamilyTemplate.ALL;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.ebuddy.cassandra.dao.visitor.ColumnVisitor;
import me.prettyprint.cassandra.model.ExecutingKeyspace;
import me.prettyprint.cassandra.model.ExecutionResult;
import me.prettyprint.cassandra.model.KeyspaceOperationCallback;
import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.hector.api.Serializer;
import me.prettyprint.hector.api.beans.ColumnSlice;
import me.prettyprint.hector.api.beans.HColumn;
import me.prettyprint.hector.api.beans.HSuperColumn;
import me.prettyprint.hector.api.beans.Row;
import me.prettyprint.hector.api.beans.Rows;
import me.prettyprint.hector.api.beans.SuperSlice;
import me.prettyprint.hector.api.exceptions.HectorTransportException;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hector.api.mutation.Mutator;
/**
* Test for SuperColumnFamilyTemplate.
* @author Eric Zoerner <a href="mailto:ezoerner@ebuddy.com">ezoerner@ebuddy.com</a>
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class SuperColumnFamilyTemplateTest {
private final String columnFamily = "TestColumnFamily";
private final String rowKey = "testKey";
private final String superColumnName = "testSuperColumnName";
private final String columnName = "testColumnName";
private final List<String> columnNames = Arrays.asList("columnName1", "columnName2");
private final String columnValue = "testColumnValue";
private final List<String> columnValues = Arrays.asList("columnValue1", "columnValue2");
private final List<String> superColumnNames = Arrays.asList("superColumnName1", "superColumnName2");
private final List<String> rowKeys = Arrays.asList("rowKey1", "rowKey2");
@Mock
private ExecutionResult executionResult;
@Mock
private KeyspaceTemplate.HectorBatchContext txnContext;
@Mock
private Mutator<String> mutator;
private SuperColumnFamilyOperations<String,String,String,String> superColumnFamilyTestDao;
@Mock
ColumnVisitor<String, String> columnVisitor;
@BeforeMethod(alwaysRun = true)
private void setUp() {
MockitoAnnotations.initMocks(this);
ExecutingKeyspace keyspace = mock(ExecutingKeyspace.class);
when(keyspace.doExecute(any(KeyspaceOperationCallback.class))).thenReturn(executionResult);
superColumnFamilyTestDao = new SuperColumnFamilyTemplate<String,String,String,String>(keyspace,
columnFamily,
StringSerializer.get(),
StringSerializer.get(),
StringSerializer.get(),
StringSerializer.get());
when(txnContext.getMutator()).thenReturn(mutator);
}
@Test(groups = {"unit"})
public void testReadColumnValue() {
ColumnSlice columnSlice = mock(ColumnSlice.class);
HColumn column = mock(HColumn.class);
String columnValue = "testColumnValue";
when(column.getValue()).thenReturn(columnValue);
when(columnSlice.getColumns()).thenReturn(Collections.singletonList(column));
when(executionResult.get()).thenReturn(columnSlice);
//=========================
String value = superColumnFamilyTestDao.readColumnValue(rowKey, superColumnName, columnName);
//=========================
assertEquals(value, columnValue);
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testReadColumnValueAndTranslateHectorException() {
when(executionResult.get()).thenThrow(new HectorTransportException("test hector exception"));
superColumnFamilyTestDao.readColumnValue(rowKey, superColumnName, columnName);
}
@Test(groups = {"unit"})
public void testReadColumnsAsMapSpecifyingNoColumnName() {
Map<String, String> testResultMap = new HashMap<String,String>();
testResultMap.put("testPropKey1", "testPropValue1");
testResultMap.put("testPropKey2", "testPropValue2");
ColumnSlice columnSlice = mock(ColumnSlice.class);
HColumn column1 = mock(HColumn.class);
HColumn column2 = mock(HColumn.class);
setupHColumn(column1, "testPropKey1", "testPropValue1");
setupHColumn(column2, "testPropKey2" , "testPropValue2");
when(columnSlice.getColumns()).thenReturn(Arrays.asList(column1, column2));
when(executionResult.get()).thenReturn(columnSlice);
//=========================
Map actualResult = superColumnFamilyTestDao.readColumnsAsMap(rowKey, superColumnName);
//=========================
assertEquals(actualResult, testResultMap);
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testReadColumnsAsMapAndTranslateHectorException() {
when(executionResult.get()).thenThrow(new HectorTransportException("test hector exception"));
superColumnFamilyTestDao.readColumnsAsMap(rowKey, superColumnName);
}
@Test(groups={"unit"})
public void testMultiGetColumnsAsMapSpecifyingNoColumnName() {
Map<String,Map<String,String>> expectedResult = new HashMap<String,Map<String,String>>();
Map<String,String> properties = new HashMap<String, String>();
Iterator<String> itr = columnValues.iterator();
for (String columnName : columnNames) {
properties.put(columnName, itr.next());
}
for(String key : rowKeys) {
expectedResult.put(key, properties);
}
Rows<String,String,String> rows = mock(Rows.class);
when(executionResult.get()).thenReturn(rows);
ColumnSlice<String,String> columnSlice = mock(ColumnSlice.class);
Row<String,String,String> mockRow = mock(Row.class);
// hard codes number of row keys to be 2
when(mockRow.getKey()).thenReturn(rowKeys.get(0)).thenReturn(rowKeys.get(1));
when(mockRow.getColumnSlice()).thenReturn(columnSlice);
HColumn<String,String> mockColumn = mock(HColumn.class);
when(mockColumn.getName()).thenReturn(columnNames.get(0)).thenReturn(columnNames.get(1)).
thenReturn(columnNames.get(0)).thenReturn(columnNames.get(1));
when(mockColumn.getValue()).
thenReturn(columnValues.get(0)).
thenReturn(columnValues.get(1)).
thenReturn(columnValues.get(0)).
thenReturn(columnValues.get(1));
List<HColumn<String,String>> columnList = Arrays.asList(mockColumn,mockColumn);
when(columnSlice.getColumns()).thenReturn(columnList);
Iterator<Row<String,String,String>> mockRowIterator = mock(Iterator.class);
when(rows.iterator()).thenReturn(mockRowIterator);
when(mockRowIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
when(mockRowIterator.next()).thenReturn(mockRow).thenReturn(mockRow);
//=========================
Map<String,Map<String,String>> result =
superColumnFamilyTestDao.multiGetColumnsAsMap(rowKeys, superColumnName);
//=========================
assertEquals(result, expectedResult);
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testMultiGetColumnsAsMapTranslateHectorException() {
when(executionResult.get()).thenThrow(new HectorTransportException("test hector exception"));
superColumnFamilyTestDao.multiGetColumnsAsMap(rowKeys, superColumnName);
}
@Test(groups={"unit"})
public void testReadRowAsMap() {
Map<String,Map<String,String>> expectedResult = new HashMap<String,Map<String,String>>();
for (String superColumnName : superColumnNames) {
Map<String,String> properties = new HashMap<String,String>();
Iterator<String> itr = columnValues.iterator();
for (String columnName : columnNames) {
properties.put(columnName, itr.next());
}
expectedResult.put(superColumnName, properties);
}
SuperSlice superSlice = mock(SuperSlice.class);
when(executionResult.get()).thenReturn(superSlice);
HSuperColumn superColumn = mock(HSuperColumn.class);
when(superSlice.getSuperColumns()).thenReturn(Arrays.asList(superColumn, superColumn));
when(superColumn.getName()).thenReturn(superColumnNames.get(0)).thenReturn(superColumnNames.get(1));
HColumn column = mock(HColumn.class);
when(superColumn.getColumns()).thenReturn(Arrays.asList(column,column));
when(column.getName()).thenReturn(columnNames.get(0)).
thenReturn(columnNames.get(1)).
thenReturn(columnNames.get(0)).
thenReturn(columnNames.get(1));
when(column.getValue()).
thenReturn(columnValues.get(0)).
thenReturn(columnValues.get(1)).
thenReturn(columnValues.get(0)).
thenReturn(columnValues.get(1));
//=========================
Map<String,Map<String,String>> result = superColumnFamilyTestDao.readRowAsMap(rowKey);
//=========================
assertEquals(result, expectedResult);
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testReadRowAsMapTranslateHectorException() {
when(executionResult.get()).thenThrow(new HectorTransportException("test hector exception"));
superColumnFamilyTestDao.readRowAsMap(rowKey);
}
@Test(groups={"unit"})
public void testWriteColumns() {
Map<String,String> properties = new HashMap<String,String>();
Iterator<String> itr = columnValues.iterator();
for (String columnName : columnNames) {
properties.put(columnName, itr.next());
}
//=========================
superColumnFamilyTestDao.writeColumns(rowKey, superColumnName, properties, txnContext);
//=========================
List<HColumn<String,String>> columns = new ArrayList<HColumn<String,String>>();
Iterator<String> itr2 = columnValues.iterator();
for (String columnName : columnNames) {
columns.add(HFactory.createColumn(columnName,
itr2.next(),
StringSerializer.get(),
StringSerializer.get()));
}
HSuperColumn<String,String,String> superColumn = HFactory.createSuperColumn(superColumnName,
columns,
StringSerializer.get(),
StringSerializer.get(),
StringSerializer.get());
ArgumentCaptor<HSuperColumn> superColumnCaptor = ArgumentCaptor.forClass(HSuperColumn.class);
verify(mutator).addInsertion(eq(rowKey), eq(columnFamily), superColumnCaptor.capture());
HSuperColumn actualSuperColumn = superColumnCaptor.getValue();
assertTrue(areSuperColumnsEqual(actualSuperColumn, superColumn));
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testWriteColumnsTranslateHectorException() {
when(mutator.addInsertion(eq(rowKey),
eq(columnFamily),
any(HSuperColumn.class))).thenThrow(new HectorTransportException(
"test hector exception"));
Map<String,String> properties = new HashMap<String,String>();
Iterator<String> itr = columnValues.iterator();
for (String columnName : columnNames) {
properties.put(columnName, itr.next());
}
//=========================
superColumnFamilyTestDao.writeColumns(rowKey, superColumnName, properties, txnContext);
//=========================
}
@Test(groups={"unit"})
public void testWriteColumn() {
String propertyValue = columnValue;
//=========================
superColumnFamilyTestDao.writeColumn(rowKey, superColumnName, columnName, propertyValue, txnContext);
//=========================
HColumn<String,String> column = HFactory.createColumn(columnName,
columnValue,
StringSerializer.get(),
StringSerializer.get());
HSuperColumn<String,String,String> superColumn = HFactory.createSuperColumn(superColumnName,
Arrays.asList(column),
StringSerializer.get(),
StringSerializer.get(),
StringSerializer.get());
ArgumentCaptor<HSuperColumn> superColumnCaptor = ArgumentCaptor.forClass(HSuperColumn.class);
verify(mutator).addInsertion(eq(rowKey), eq(columnFamily), superColumnCaptor.capture());
HSuperColumn actualSuperColumn = superColumnCaptor.getValue();
assertTrue(areSuperColumnsEqual(actualSuperColumn, superColumn));
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testWriteColumnTranslateHectorException() {
when(mutator.addInsertion(eq(rowKey),
eq(columnFamily),
any(HSuperColumn.class))).
thenThrow(new HectorTransportException("test hector exception"));
String propertyValue = columnValue;
//=========================
superColumnFamilyTestDao.writeColumn(rowKey, superColumnName, columnName, propertyValue, txnContext);
//=========================
}
@Test(groups={"unit"})
public void testDeleteColumns() {
//=========================
superColumnFamilyTestDao.deleteColumns(rowKey, superColumnName, columnNames, txnContext);
//=========================
for (String colName : columnNames) {
verify(mutator).addSubDelete(rowKey,
columnFamily,
superColumnName,
colName,
StringSerializer.get(),
StringSerializer.get());
}
}
@Test(groups={"unit"}, expectedExceptions = HectorTransportException.class)
public void testDeleteColumnsTranslateHectorException() {
when(mutator.addSubDelete(anyString(),
anyString(),
anyString(),
anyString(),
any(Serializer.class),
any(Serializer.class))).
thenThrow(new HectorTransportException("test hector exception"));
//=========================
superColumnFamilyTestDao.deleteColumns(rowKey, superColumnName, columnNames, txnContext);
//=========================
}
@Test(groups = {"unit"})
public void testVisitColumn() {
ColumnSlice columnSlice = mock(ColumnSlice.class);
HColumn column1 = mock(HColumn.class);
HColumn column2 = mock(HColumn.class);
String propertyValue1 = setupHColumn(column1, "testPropKey1", "testPropValue1");
String propertyValue2 = setupHColumn(column2, "testPropKey2", "testPropValue1");
when(columnSlice.getColumns()).thenReturn(Arrays.asList(column1, column2));
when(executionResult.get()).thenReturn(columnSlice);
//=========================
//Map actualResult = superColumnFamilyTestDao.readColumnsAsMap(rowKey, superColumnName);
superColumnFamilyTestDao.visitColumns(rowKey, superColumnName, null, null, ALL, false, columnVisitor);
//=========================
verify(columnVisitor).visit(eq("testPropKey1"), eq(propertyValue1), any(Long.class), any(Integer.class));
verify(columnVisitor).visit(eq("testPropKey2"), eq(propertyValue2), any(Long.class), any(Integer.class));
}
private String setupHColumn(HColumn column1, String columnKey, String columnValue) {
when(column1.getName()).thenReturn(columnKey);
when(column1.getValue()).thenReturn(columnValue);
return columnValue;
}
@SuppressWarnings({"ControlFlowStatementWithoutBraces"})
private boolean areSuperColumnsEqual(HSuperColumn superColumn1, HSuperColumn superColumn2) {
if (superColumn1 == superColumn2) return true;
if (superColumn2 == null) return false;
if (superColumn1 == null) return false;
if (superColumn1.getClass() != superColumn2.getClass()) return false;
if (!ObjectUtils.equals(superColumn1.getName(), superColumn2.getName())) return false;
if (superColumn1.getColumns().size() != superColumn2.getColumns().size()) return false;
Iterator<HColumn> itr1 = superColumn1.getColumns().iterator();
Iterator<HColumn> itr2 = superColumn2.getColumns().iterator();
while(itr1.hasNext()) {
if (!areColumnsEqual(itr1.next(), itr2.next())) return false;
}
return true;
}
@SuppressWarnings({"ControlFlowStatementWithoutBraces", "SimplifiableIfStatement"})
private boolean areColumnsEqual(HColumn column1, HColumn column2) {
if (column1 == column2) return true;
if (column2 == null) return false;
if (column1 == null) return false;
if (column1.getClass() != column2.getClass()) return false;
if (!ObjectUtils.equals(column1.getName(), column2.getName())) return false;
return ObjectUtils.equals(column1.getValue(), column2.getValue());
}
}