package com.netflix.astyanax.cql.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import junit.framework.Assert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.netflix.astyanax.cql.reads.model.CqlRangeBuilder;
import com.netflix.astyanax.cql.reads.model.CqlRangeImpl;
import com.netflix.astyanax.cql.test.utils.ReadTests;
import com.netflix.astyanax.cql.test.utils.TestUtils;
import com.netflix.astyanax.cql.test.utils.TestUtils.TestTokenRange;
import com.netflix.astyanax.model.ByteBufferRange;
import com.netflix.astyanax.model.Column;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ColumnList;
import com.netflix.astyanax.model.Row;
import com.netflix.astyanax.model.Rows;
public class RowSliceRowRangeQueryTests extends ReadTests {
private static ColumnFamily<String, String> CF_COLUMN_RANGE_TEST = TestUtils.CF_COLUMN_RANGE_TEST;
@BeforeClass
public static void init() throws Exception {
initContext();
keyspace.createColumnFamily(CF_COLUMN_RANGE_TEST, null);
CF_COLUMN_RANGE_TEST.describe(keyspace);
}
@AfterClass
public static void tearDown() throws Exception {
keyspace.dropColumnFamily(CF_COLUMN_RANGE_TEST);
}
@Test
public void runAllTests() throws Exception {
boolean rowDeleted = false;
TestUtils.populateRowsForColumnRange(keyspace);
Thread.sleep(1000);
testRowKeysWithAllColumns(rowDeleted);
testRowKeysWithColumnSet(rowDeleted);
testRowKeysWithColumnRange(rowDeleted);
testRowRangeWithAllColumns(rowDeleted);
testRowRangeWithColumnSet(rowDeleted);
testRowRangeWithColumnRange(rowDeleted);
TestUtils.deleteRowsForColumnRange(keyspace);
Thread.sleep(1000);
rowDeleted = true;
testRowKeysWithAllColumns(rowDeleted);
testRowKeysWithColumnSet(rowDeleted);
testRowKeysWithColumnRange(rowDeleted);
testRowRangeWithAllColumns(rowDeleted);
testRowRangeWithColumnSet(rowDeleted);
testRowRangeWithColumnRange(rowDeleted);
}
private void testRowKeysWithAllColumns(boolean rowDeleted) throws Exception {
Set<String> rowKeys = getRandomRowKeys();
Rows<String, String> rows = keyspace.prepareQuery(CF_COLUMN_RANGE_TEST).getRowSlice(rowKeys).execute().getResult();
if (rowDeleted) {
Assert.assertTrue(rows.isEmpty());
return;
}
Assert.assertFalse(rows.isEmpty());
int rowKeysSize = rowKeys.size();
for (Row<String, String> row : rows) {
boolean isPresent = rowKeys.remove(row.getKey());
Assert.assertTrue("Extraneous row: " + row.getKey(), isPresent);
ColumnList<String> colList = row.getColumns();
Assert.assertEquals(26, colList.size());
for(int index=0; index<26; index++) {
Column<String> col = colList.getColumnByIndex(index);
Assert.assertTrue(String.valueOf((char)('a' + index)).equals(col.getName()));
Assert.assertEquals(index + 1, col.getIntegerValue());
}
}
Assert.assertEquals(rowKeysSize, rows.size());
}
private void testRowKeysWithColumnSet(boolean rowDeleted) throws Exception {
Set<String> rowKeys = getRandomRowKeys();
Set<String> columns = getRandomColumns();
Rows<String, String> rows = keyspace.prepareQuery(CF_COLUMN_RANGE_TEST)
.getRowSlice(rowKeys)
.withColumnSlice(columns)
.execute().getResult();
if (rowDeleted) {
Assert.assertTrue(rows.isEmpty());
return;
}
Assert.assertFalse(rows.isEmpty());
List<String> expected = new ArrayList<String>(columns);
Collections.sort(expected);
int rowKeysSize = rowKeys.size();
for (Row<String, String> row : rows) {
boolean isPresent = rowKeys.remove(row.getKey());
Assert.assertTrue("Extraneous row: " + row.getKey(), isPresent);
List<String> result = new ArrayList<String>();
ColumnList<String> colList = row.getColumns();
for (Column<String> col : colList) {
result.add(col.getName());
}
Collections.sort(result);
Assert.assertEquals(expected, result);
}
Assert.assertEquals(rowKeysSize, rows.size());
}
@SuppressWarnings("unchecked")
private void testRowKeysWithColumnRange(boolean rowDeleted) throws Exception {
Set<String> rowKeys = getRandomRowKeys();
// get random start and end column
CqlRangeImpl<String> columns = (CqlRangeImpl<String>) getRandomColumnRange();
Rows<String, String> rows = keyspace.prepareQuery(CF_COLUMN_RANGE_TEST)
.getRowSlice(rowKeys)
.withColumnRange(columns)
.execute().getResult();
if (rowDeleted) {
Assert.assertTrue(rows.isEmpty());
return;
}
Assert.assertFalse(rows.isEmpty());
int rowKeysSize = rowKeys.size();
for (Row<String, String> row : rows) {
boolean isPresent = rowKeys.remove(row.getKey());
Assert.assertTrue("Extraneous row: " + row.getKey(), isPresent);
int numExpectedCols = columns.getCqlEnd().charAt(0) - columns.getCqlStart().charAt(0) + 1;
ColumnList<String> colList = row.getColumns();
Assert.assertEquals(numExpectedCols, colList.size());
for (Column<String> col : colList) {
Assert.assertTrue(col.getName().compareTo(columns.getCqlStart()) >= 0);
Assert.assertTrue(col.getName().compareTo(columns.getCqlEnd()) <= 0);
}
}
Assert.assertEquals(rowKeysSize, rows.size());
}
private void testRowRangeWithAllColumns(boolean rowDeleted) throws Exception {
List<String> expectedColumns = new ArrayList<String>();
for (char ch = 'a'; ch <= 'z'; ch++) {
expectedColumns.add(String.valueOf(ch));
}
for (TestTokenRange testRange : getTestTokenRanges()) {
Rows<String, String> rows = keyspace.prepareQuery(CF_COLUMN_RANGE_TEST)
.getRowRange(null, null, testRange.startToken, testRange.endToken, -1)
.execute().getResult();
if (rowDeleted) {
Assert.assertTrue(rows.isEmpty());
continue;
}
Assert.assertFalse(rows.isEmpty());
List<String> list = new ArrayList<String>();
for (Row<String, String> row : rows) {
String key = row.getKey();
list.add(key);
ColumnList<String> columns = row.getColumns();
testRangeColumnsForRow(columns, expectedColumns);
}
Assert.assertEquals(testRange.expectedRowKeys, list);
}
}
private void testRowRangeWithColumnSet(boolean rowDeleted) throws Exception {
Set<String> randomColumns = getRandomColumns();
List<String> expectedColumns = new ArrayList<String>(randomColumns);
Collections.sort(expectedColumns);
for (TestTokenRange testRange : getTestTokenRanges()) {
Rows<String, String> rows = keyspace.prepareQuery(CF_COLUMN_RANGE_TEST)
.getRowRange(null, null, testRange.startToken, testRange.endToken, -1)
.withColumnSlice(randomColumns)
.execute().getResult();
if (rowDeleted) {
Assert.assertTrue(rows.isEmpty());
continue;
}
Assert.assertFalse(rows.isEmpty());
List<String> list = new ArrayList<String>();
for (Row<String, String> row : rows) {
String key = row.getKey();
list.add(key);
ColumnList<String> columns = row.getColumns();
testRangeColumnsForRow(columns, expectedColumns);
}
Assert.assertEquals(testRange.expectedRowKeys, list);
}
}
private void testRowRangeWithColumnRange(boolean rowDeleted) throws Exception {
CqlRangeImpl<String> columnRange = (CqlRangeImpl<String>) getRandomColumnRange();
for (TestTokenRange testRange : getTestTokenRanges()) {
Rows<String, String> rows = keyspace.prepareQuery(CF_COLUMN_RANGE_TEST)
.getRowRange(null, null, testRange.startToken, testRange.endToken, -1)
.withColumnRange(columnRange)
.execute().getResult();
if (rowDeleted) {
Assert.assertTrue(rows.isEmpty());
continue;
}
Assert.assertFalse(rows.isEmpty());
int numExpectedCols = columnRange.getCqlEnd().charAt(0) - columnRange.getCqlStart().charAt(0) + 1;
List<String> list = new ArrayList<String>();
for (Row<String, String> row : rows) {
String key = row.getKey();
list.add(key);
ColumnList<String> colList = row.getColumns();
Assert.assertEquals(numExpectedCols, colList.size());
for (Column<String> col : colList) {
Assert.assertTrue(col.getName().compareTo(columnRange.getCqlStart()) >= 0);
Assert.assertTrue(col.getName().compareTo(columnRange.getCqlEnd()) <= 0);
}
}
Assert.assertEquals(testRange.expectedRowKeys, list);
}
}
private Set<String> getRandomRowKeys() {
Random random = new Random();
int numRowKeys = random.nextInt(26) + 1; // avoid 0 rows
Set<String> set = new HashSet<String>();
for (int i=0; i<numRowKeys; i++) {
int no = random.nextInt(26);
char ch = (char) ('A' + no);
set.add(String.valueOf(ch));
}
System.out.println("Set: " + set);
return set;
}
private Set<String> getRandomColumns() {
Random random = new Random();
int numRowKeys = random.nextInt(26) + 1; // avoid 0 rows
Set<String> set = new HashSet<String>();
for (int i=0; i<numRowKeys; i++) {
int no = random.nextInt(26);
char ch = (char) ('a' + no);
set.add(String.valueOf(ch));
}
return set;
}
private ByteBufferRange getRandomColumnRange() {
Random random = new Random();
Integer n1 = random.nextInt(26);
Integer n2 = random.nextInt(26);
String c1 = String.valueOf((char)('a' + n1));
String c2 = String.valueOf((char)('a' + n2));
if (n1 < n2) {
return new CqlRangeBuilder<String>().setStart(c1).setEnd(c2).build();
} else {
return new CqlRangeBuilder<String>().setStart(c2).setEnd(c1).build();
}
}
private List<TestTokenRange> getTestTokenRanges() {
return TestUtils.getTestTokenRanges();
}
private void testRangeColumnsForRow(ColumnList<String> columns, List<String> expected) {
Iterator<Column<String>> iter1 = columns.iterator();
Iterator<String> iter2 = expected.iterator();
while (iter2.hasNext()) {
Column<String> column = iter1.next();
String expectedName = iter2.next();
Assert.assertEquals(expectedName, column.getName());
int expectedValue = expectedName.charAt(0) - 'a' + 1;
Assert.assertEquals(expectedValue, column.getIntegerValue());
}
}
}