Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.scalar.db.api.DistributedStorageMultipleClusteringKeyScanIntegrationTestBase Maven / Gradle / Ivy
package com.scalar.db.api;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ListMultimap;
import com.scalar.db.api.Scan.Ordering;
import com.scalar.db.api.Scan.Ordering.Order;
import com.scalar.db.exception.storage.ExecutionException;
import com.scalar.db.io.DataType;
import com.scalar.db.io.Key;
import com.scalar.db.io.Value;
import com.scalar.db.service.StorageFactory;
import com.scalar.db.util.TestUtils;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class DistributedStorageMultipleClusteringKeyScanIntegrationTestBase {
private static final Logger logger =
LoggerFactory.getLogger(DistributedStorageMultipleClusteringKeyScanIntegrationTestBase.class);
private enum OrderingType {
BOTH_SPECIFIED,
ONLY_FIRST_SPECIFIED,
BOTH_SPECIFIED_AND_REVERSED,
ONLY_FIRST_SPECIFIED_AND_REVERSED,
NOTHING
}
private static final String TEST_NAME = "storage_mul_ckey";
private static final String NAMESPACE_BASE_NAME = "int_test_" + TEST_NAME + "_";
private static final String PARTITION_KEY = "pkey";
private static final String FIRST_CLUSTERING_KEY = "ckey1";
private static final String SECOND_CLUSTERING_KEY = "ckey2";
private static final String COL_NAME = "col";
private static final int FIRST_CLUSTERING_KEY_NUM = 5;
private static final int SECOND_CLUSTERING_KEY_NUM = 20;
private static final int THREAD_NUM = 10;
private DistributedStorageAdmin admin;
private DistributedStorage storage;
private String namespaceBaseName;
// Key: firstClusteringKeyType, Value: secondClusteringKeyType
private ListMultimap clusteringKeyTypes;
private long seed;
private ThreadLocal random;
private ExecutorService executorService;
@BeforeAll
public void beforeAll() throws Exception {
initialize(TEST_NAME);
StorageFactory factory = StorageFactory.create(getProperties(TEST_NAME));
admin = factory.getAdmin();
namespaceBaseName = getNamespaceBaseName();
clusteringKeyTypes = getClusteringKeyTypes();
executorService = Executors.newFixedThreadPool(getThreadNum());
createTables();
storage = factory.getStorage();
seed = System.currentTimeMillis();
System.out.println(
"The seed used in the multiple clustering key scan integration test is " + seed);
random = ThreadLocal.withInitial(Random::new);
}
protected void initialize(String testName) throws Exception {}
protected abstract Properties getProperties(String testName);
protected String getNamespaceBaseName() {
return NAMESPACE_BASE_NAME;
}
protected ListMultimap getClusteringKeyTypes() {
ListMultimap clusteringKeyTypes = ArrayListMultimap.create();
for (DataType firstClusteringKeyType : DataType.values()) {
for (DataType secondClusteringKeyType : DataType.values()) {
clusteringKeyTypes.put(firstClusteringKeyType, secondClusteringKeyType);
}
}
return clusteringKeyTypes;
}
protected int getThreadNum() {
return THREAD_NUM;
}
protected boolean isParallelDdlSupported() {
return true;
}
private void createTables() throws java.util.concurrent.ExecutionException, InterruptedException {
List> testCallables = new ArrayList<>();
Map options = getCreationOptions();
for (DataType firstClusteringKeyType : clusteringKeyTypes.keySet()) {
Callable testCallable =
() -> {
admin.createNamespace(getNamespaceName(firstClusteringKeyType), true, options);
for (DataType secondClusteringKeyType :
clusteringKeyTypes.get(firstClusteringKeyType)) {
for (Order firstClusteringOrder : Order.values()) {
for (Order secondClusteringOrder : Order.values()) {
createTable(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
options);
}
}
}
return null;
};
testCallables.add(testCallable);
}
// We firstly execute the first one and then the rest. This is because the first table creation
// creates the metadata table, and this process can't be handled in multiple threads/processes
// at the same time.
executeDdls(testCallables.subList(0, 1));
executeDdls(testCallables.subList(1, testCallables.size()));
}
protected Map getCreationOptions() {
return Collections.emptyMap();
}
private void createTable(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
Map options)
throws ExecutionException {
admin.createTable(
getNamespaceName(firstClusteringKeyType),
getTableName(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder),
TableMetadata.newBuilder()
.addColumn(PARTITION_KEY, DataType.INT)
.addColumn(FIRST_CLUSTERING_KEY, firstClusteringKeyType)
.addColumn(SECOND_CLUSTERING_KEY, secondClusteringKeyType)
.addColumn(COL_NAME, DataType.INT)
.addPartitionKey(PARTITION_KEY)
.addClusteringKey(FIRST_CLUSTERING_KEY, firstClusteringOrder)
.addClusteringKey(SECOND_CLUSTERING_KEY, secondClusteringOrder)
.build(),
true,
options);
}
@AfterAll
public void afterAll() throws Exception {
try {
dropTables();
} catch (Exception e) {
logger.warn("Failed to drop tables", e);
}
try {
if (admin != null) {
admin.close();
}
} catch (Exception e) {
logger.warn("Failed to close admin", e);
}
try {
if (storage != null) {
storage.close();
}
} catch (Exception e) {
logger.warn("Failed to close storage", e);
}
try {
if (executorService != null) {
executorService.shutdown();
}
} catch (Exception e) {
logger.warn("Failed to shutdown executor service", e);
}
}
private void dropTables() throws java.util.concurrent.ExecutionException, InterruptedException {
List> testCallables = new ArrayList<>();
for (DataType firstClusteringKeyType : clusteringKeyTypes.keySet()) {
Callable testCallable =
() -> {
for (DataType secondClusteringKeyType :
clusteringKeyTypes.get(firstClusteringKeyType)) {
for (Order firstClusteringOrder : Order.values()) {
for (Order secondClusteringOrder : Order.values()) {
admin.dropTable(
getNamespaceName(firstClusteringKeyType),
getTableName(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder));
}
}
}
admin.dropNamespace(getNamespaceName(firstClusteringKeyType));
return null;
};
testCallables.add(testCallable);
}
// We firstly execute the callables without the last one. And then we execute the last one. This
// is because the last table deletion deletes the metadata table, and this process can't be
// handled in multiple threads/processes at the same time.
executeDdls(testCallables.subList(0, testCallables.size() - 1));
executeDdls(testCallables.subList(testCallables.size() - 1, testCallables.size()));
}
private void truncateTable(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder)
throws ExecutionException {
admin.truncateTable(
getNamespaceName(firstClusteringKeyType),
getTableName(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder));
}
private String getTableName(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder) {
return String.join(
"_",
firstClusteringKeyType.toString(),
firstClusteringOrder.toString(),
secondClusteringKeyType.toString(),
secondClusteringOrder.toString());
}
private String getNamespaceName(DataType firstClusteringKeyType) {
return namespaceBaseName + firstClusteringKeyType;
}
@Test
public void scan_WithoutClusteringKeyRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithoutClusteringKeyRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
orderingType,
withLimit);
}
}
});
}
private void scan_WithoutClusteringKeyRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
List expected =
getExpected(clusteringKeys, null, null, null, null, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
null,
null,
null,
null,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
null,
null,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
startInclusive,
endInclusive,
orderingType,
withLimit);
}
}
}
}
});
}
private void scan_WithFirstClusteringKeyRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean startInclusive,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey startClusteringKey;
ClusteringKey endClusteringKey;
if (firstClusteringKeyType == DataType.BOOLEAN) {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(0, DataType.INT)).first);
endClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(1, DataType.INT)).first);
} else {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(1, DataType.INT)).first);
endClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(3, DataType.INT)).first);
}
List expected =
getExpected(
clusteringKeys,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
startInclusive,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyRangeWithSameValues_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyRangeWithSameValues_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
startInclusive,
endInclusive,
orderingType,
withLimit);
}
}
}
}
});
}
private void scan_WithFirstClusteringKeyRangeWithSameValues_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean startInclusive,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey startAndEndClusteringKey;
if (firstClusteringKeyType == DataType.BOOLEAN) {
startAndEndClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(0, DataType.INT)).first);
} else {
startAndEndClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(2, DataType.INT)).first);
}
List expected =
getExpected(
clusteringKeys,
startAndEndClusteringKey,
startInclusive,
startAndEndClusteringKey,
endInclusive,
orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
startAndEndClusteringKey,
startInclusive,
startAndEndClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
startInclusive,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyRangeWithMinAndMaxValue_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyRangeWithMinAndMaxValue_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
startInclusive,
endInclusive,
orderingType,
withLimit);
}
}
}
}
});
}
private void scan_WithFirstClusteringKeyRangeWithMinAndMaxValue_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean startInclusive,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey startClusteringKey =
new ClusteringKey(getMinValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType));
ClusteringKey endClusteringKey =
new ClusteringKey(getMaxValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType));
List expected =
getExpected(
clusteringKeys,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
startInclusive,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyStartRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyStartRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
startInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithFirstClusteringKeyStartRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean startInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey startClusteringKey;
if (firstClusteringKeyType == DataType.BOOLEAN) {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(0, DataType.INT)).first);
} else {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(1, DataType.INT)).first);
}
List expected =
getExpected(clusteringKeys, startClusteringKey, startInclusive, null, null, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
startClusteringKey,
startInclusive,
null,
null,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
startInclusive,
null,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyStartRangeWithMinValue_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyStartRangeWithMinValue_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
startInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithFirstClusteringKeyStartRangeWithMinValue_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean startInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey startClusteringKey =
new ClusteringKey(getMinValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType));
List expected =
getExpected(clusteringKeys, startClusteringKey, startInclusive, null, null, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
startClusteringKey,
startInclusive,
null,
null,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
startInclusive,
null,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyEndRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyEndRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
endInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithFirstClusteringKeyEndRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey endClusteringKey;
if (firstClusteringKeyType == DataType.BOOLEAN) {
endClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(1, DataType.INT)).first);
} else {
endClusteringKey =
new ClusteringKey(clusteringKeys.get(getFirstClusteringKeyIndex(3, DataType.INT)).first);
}
List expected =
getExpected(clusteringKeys, null, null, endClusteringKey, endInclusive, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
null,
null,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
null,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithFirstClusteringKeyEndRangeWithMaxValue_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys, firstClusteringKeyType, firstClusteringKeyOrder) -> {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithFirstClusteringKeyEndRangeWithMaxValue_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
endInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithFirstClusteringKeyEndRangeWithMaxValue_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
ClusteringKey endClusteringKey =
new ClusteringKey(getMaxValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType));
List expected =
getExpected(clusteringKeys, null, null, endClusteringKey, endInclusive, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
DataType.INT,
Order.ASC,
null,
null,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
null,
null,
null,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
startInclusive,
endInclusive,
orderingType,
withLimit);
}
}
}
}
});
}
private void scan_WithSecondClusteringKeyRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean startInclusive,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
if (firstClusteringKeyType == DataType.BOOLEAN) {
Value> firstClusteringKeyValue = clusteringKeys.get(0).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
} else {
Value> firstClusteringKeyValue =
clusteringKeys.get(getFirstClusteringKeyIndex(2, secondClusteringKeyType)).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
}
ClusteringKey startClusteringKey;
ClusteringKey endClusteringKey;
if (secondClusteringKeyType == DataType.BOOLEAN) {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(0).first, clusteringKeys.get(0).second);
endClusteringKey =
new ClusteringKey(clusteringKeys.get(1).first, clusteringKeys.get(1).second);
} else {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(4).first, clusteringKeys.get(4).second);
endClusteringKey =
new ClusteringKey(clusteringKeys.get(14).first, clusteringKeys.get(14).second);
}
List expected =
getExpected(
clusteringKeys,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startInclusive,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyRangeWithSameValues_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyRangeWithSameValues_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
startInclusive,
endInclusive,
orderingType,
withLimit);
}
}
}
}
});
}
private void scan_WithSecondClusteringKeyRangeWithSameValues_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean startInclusive,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
if (firstClusteringKeyType == DataType.BOOLEAN) {
Value> firstClusteringKeyValue = clusteringKeys.get(0).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
} else {
Value> firstClusteringKeyValue =
clusteringKeys.get(getFirstClusteringKeyIndex(2, secondClusteringKeyType)).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
}
ClusteringKey startAndEndClusteringKey;
if (secondClusteringKeyType == DataType.BOOLEAN) {
startAndEndClusteringKey =
new ClusteringKey(clusteringKeys.get(0).first, clusteringKeys.get(0).second);
} else {
startAndEndClusteringKey =
new ClusteringKey(clusteringKeys.get(9).first, clusteringKeys.get(9).second);
}
List expected =
getExpected(
clusteringKeys,
startAndEndClusteringKey,
startInclusive,
startAndEndClusteringKey,
endInclusive,
orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startAndEndClusteringKey,
startInclusive,
startAndEndClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startInclusive,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyRangeWithMinAndMaxValues_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean useMinValueForFirstClusteringKeyValue : Arrays.asList(true, false)) {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyRangeWithMinAndMaxValues_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
useMinValueForFirstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringKeyOrder,
startInclusive,
endInclusive,
orderingType,
withLimit);
}
}
}
}
}
});
}
private void scan_WithSecondClusteringKeyRangeWithMinAndMaxValues_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
boolean useMinValueForFirstClusteringKeyValue,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean startInclusive,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
Value> firstClusteringKeyValue =
useMinValueForFirstClusteringKeyValue
? getMinValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType)
: getMaxValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType);
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
ClusteringKey startClusteringKey =
new ClusteringKey(
firstClusteringKeyValue, getMinValue(SECOND_CLUSTERING_KEY, secondClusteringKeyType));
ClusteringKey endClusteringKey =
new ClusteringKey(
firstClusteringKeyValue, getMaxValue(SECOND_CLUSTERING_KEY, secondClusteringKeyType));
List expected =
getExpected(
clusteringKeys,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startClusteringKey,
startInclusive,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startInclusive,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyStartRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyStartRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
startInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithSecondClusteringKeyStartRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean startInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
if (firstClusteringKeyType == DataType.BOOLEAN) {
Value> firstClusteringKeyValue = clusteringKeys.get(0).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
} else {
Value> firstClusteringKeyValue =
clusteringKeys.get(getFirstClusteringKeyIndex(2, secondClusteringKeyType)).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
}
ClusteringKey startClusteringKey;
if (secondClusteringKeyType == DataType.BOOLEAN) {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(0).first, clusteringKeys.get(0).second);
} else {
startClusteringKey =
new ClusteringKey(clusteringKeys.get(4).first, clusteringKeys.get(4).second);
}
List expected =
getExpected(clusteringKeys, startClusteringKey, startInclusive, null, null, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startClusteringKey,
startInclusive,
null,
null,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startInclusive,
null,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyStartRangeWithMinValue_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean startInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyStartRangeWithMinValue_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
startInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithSecondClusteringKeyStartRangeWithMinValue_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean startInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
Value> firstClusteringKeyValue = getMinValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType);
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
ClusteringKey startClusteringKey =
new ClusteringKey(
firstClusteringKeyValue, getMinValue(SECOND_CLUSTERING_KEY, secondClusteringKeyType));
List expected =
getExpected(clusteringKeys, startClusteringKey, startInclusive, null, null, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startClusteringKey,
startInclusive,
null,
null,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
startInclusive,
null,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyEndRange_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyEndRange_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
endInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithSecondClusteringKeyEndRange_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
if (firstClusteringKeyType == DataType.BOOLEAN) {
Value> firstClusteringKeyValue = clusteringKeys.get(0).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
} else {
Value> firstClusteringKeyValue =
clusteringKeys.get(getFirstClusteringKeyIndex(2, secondClusteringKeyType)).first;
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
}
ClusteringKey endClusteringKey;
if (secondClusteringKeyType == DataType.BOOLEAN) {
endClusteringKey =
new ClusteringKey(clusteringKeys.get(1).first, clusteringKeys.get(1).second);
} else {
endClusteringKey =
new ClusteringKey(clusteringKeys.get(14).first, clusteringKeys.get(14).second);
}
List expected =
getExpected(clusteringKeys, null, null, endClusteringKey, endInclusive, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
null,
null,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
null,
endInclusive,
orderingType,
withLimit));
}
@Test
public void scan_WithSecondClusteringKeyEndRangeWithMaxValue_ShouldReturnProperResult()
throws java.util.concurrent.ExecutionException, InterruptedException {
executeInParallel(
(clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder) -> {
for (boolean endInclusive : Arrays.asList(true, false)) {
for (OrderingType orderingType : OrderingType.values()) {
for (boolean withLimit : Arrays.asList(false, true)) {
scan_WithSecondClusteringKeyEndRangeWithMaxValue_ShouldReturnProperResult(
clusteringKeys,
firstClusteringKeyType,
firstClusteringKeyOrder,
secondClusteringKeyType,
secondClusteringKeyOrder,
endInclusive,
orderingType,
withLimit);
}
}
}
});
}
private void scan_WithSecondClusteringKeyEndRangeWithMaxValue_ShouldReturnProperResult(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
boolean endInclusive,
OrderingType orderingType,
boolean withLimit)
throws ExecutionException, IOException {
// Arrange
Value> firstClusteringKeyValue = getMaxValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType);
clusteringKeys =
clusteringKeys.stream()
.filter(c -> c.first.equals(firstClusteringKeyValue))
.collect(Collectors.toList());
ClusteringKey endClusteringKey =
new ClusteringKey(
firstClusteringKeyValue, getMaxValue(SECOND_CLUSTERING_KEY, secondClusteringKeyType));
List expected =
getExpected(clusteringKeys, null, null, endClusteringKey, endInclusive, orderingType);
int limit = getLimit(withLimit, expected);
if (limit > 0) {
expected = expected.subList(0, limit);
}
Scan scan =
getScan(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
null,
null,
endClusteringKey,
endInclusive,
orderingType,
limit);
// Act
List actual = scanAll(scan);
// Assert
assertScanResult(
actual,
expected,
description(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder,
null,
endInclusive,
orderingType,
withLimit));
}
private List prepareRecords(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder)
throws ExecutionException {
List ret = new ArrayList<>();
List puts = new ArrayList<>();
if (firstClusteringKeyType == DataType.BOOLEAN) {
TestUtils.booleanValues(FIRST_CLUSTERING_KEY)
.forEach(
firstClusteringKeyValue ->
prepareRecords(
firstClusteringKeyType,
firstClusteringOrder,
firstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringOrder,
puts,
ret));
} else {
Set> valueSet = new HashSet<>();
// Add min and max first clustering key values
Arrays.asList(
getMinValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType),
getMaxValue(FIRST_CLUSTERING_KEY, firstClusteringKeyType))
.forEach(
firstClusteringKeyValue -> {
valueSet.add(firstClusteringKeyValue);
prepareRecords(
firstClusteringKeyType,
firstClusteringOrder,
firstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringOrder,
puts,
ret);
});
IntStream.range(0, FIRST_CLUSTERING_KEY_NUM - 2)
.forEach(
i -> {
Value> firstClusteringKeyValue;
while (true) {
firstClusteringKeyValue = getFirstClusteringKeyValue(firstClusteringKeyType);
// reject duplication
if (!valueSet.contains(firstClusteringKeyValue)) {
valueSet.add(firstClusteringKeyValue);
break;
}
}
prepareRecords(
firstClusteringKeyType,
firstClusteringOrder,
firstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringOrder,
puts,
ret);
});
}
try {
List buffer = new ArrayList<>();
for (Put put : puts) {
buffer.add(put);
if (buffer.size() == 20) {
storage.mutate(buffer);
buffer.clear();
}
}
if (!buffer.isEmpty()) {
storage.mutate(buffer);
}
} catch (ExecutionException e) {
throw new ExecutionException("Put data to database failed", e);
}
ret.sort(getClusteringKeyComparator(firstClusteringOrder, secondClusteringOrder));
return ret;
}
private void prepareRecords(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
Value> firstClusteringKeyValue,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
List puts,
List ret) {
if (secondClusteringKeyType == DataType.BOOLEAN) {
TestUtils.booleanValues(SECOND_CLUSTERING_KEY)
.forEach(
secondClusteringKeyValue -> {
ret.add(new ClusteringKey(firstClusteringKeyValue, secondClusteringKeyValue));
puts.add(
preparePut(
firstClusteringKeyType,
firstClusteringOrder,
firstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringOrder,
secondClusteringKeyValue));
});
} else {
Set> valueSet = new HashSet<>();
// min and max second clustering key values
Arrays.asList(
getMinValue(SECOND_CLUSTERING_KEY, secondClusteringKeyType),
getMaxValue(SECOND_CLUSTERING_KEY, secondClusteringKeyType))
.forEach(
secondClusteringKeyValue -> {
ret.add(new ClusteringKey(firstClusteringKeyValue, secondClusteringKeyValue));
puts.add(
preparePut(
firstClusteringKeyType,
firstClusteringOrder,
firstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringOrder,
secondClusteringKeyValue));
valueSet.add(secondClusteringKeyValue);
});
for (int i = 0; i < SECOND_CLUSTERING_KEY_NUM - 2; i++) {
Value> secondClusteringKeyValue;
while (true) {
secondClusteringKeyValue =
getRandomValue(random.get(), SECOND_CLUSTERING_KEY, secondClusteringKeyType);
// reject duplication
if (!valueSet.contains(secondClusteringKeyValue)) {
valueSet.add(secondClusteringKeyValue);
break;
}
}
ret.add(new ClusteringKey(firstClusteringKeyValue, secondClusteringKeyValue));
puts.add(
preparePut(
firstClusteringKeyType,
firstClusteringOrder,
firstClusteringKeyValue,
secondClusteringKeyType,
secondClusteringOrder,
secondClusteringKeyValue));
}
}
}
private Put preparePut(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
Value> firstClusteringKeyValue,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
Value> secondClusteringKeyValue) {
return new Put(getPartitionKey(), new Key(firstClusteringKeyValue, secondClusteringKeyValue))
.withValue(COL_NAME, 1)
.forNamespace(getNamespaceName(firstClusteringKeyType))
.forTable(
getTableName(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder));
}
private int getFirstClusteringKeyIndex(int i, DataType secondClusteringKeyType) {
return i * (secondClusteringKeyType == DataType.BOOLEAN ? 2 : SECOND_CLUSTERING_KEY_NUM);
}
private String description(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
@Nullable DataType secondClusteringKeyType,
@Nullable Order secondClusteringOrder,
@Nullable Boolean startInclusive,
@Nullable Boolean endInclusive,
OrderingType orderingType,
boolean withLimit) {
StringBuilder builder = new StringBuilder();
builder.append(
String.format(
"failed with firstClusteringKeyType: %s, firstClusteringOrder: %s",
firstClusteringKeyType, firstClusteringOrder));
if (secondClusteringKeyType != null) {
builder.append(String.format(", secondClusteringKeyType: %s", secondClusteringKeyType));
}
if (secondClusteringOrder != null) {
builder.append(String.format(", secondClusteringOrder: %s", secondClusteringOrder));
}
if (startInclusive != null) {
builder.append(String.format(", startInclusive: %s", startInclusive));
}
if (endInclusive != null) {
builder.append(String.format(", endInclusive: %s", endInclusive));
}
builder.append(String.format(", orderingType: %s, withLimit: %b", orderingType, withLimit));
return builder.toString();
}
private Key getPartitionKey() {
return new Key(PARTITION_KEY, 1);
}
private Value> getFirstClusteringKeyValue(DataType dataType) {
return getRandomValue(random.get(), FIRST_CLUSTERING_KEY, dataType);
}
protected Value> getRandomValue(Random random, String columnName, DataType dataType) {
return TestUtils.getRandomValue(random, columnName, dataType);
}
protected Value> getMinValue(String columnName, DataType dataType) {
return TestUtils.getMinValue(columnName, dataType);
}
protected Value> getMaxValue(String columnName, DataType dataType) {
return TestUtils.getMaxValue(columnName, dataType);
}
private List scanAll(Scan scan) throws ExecutionException, IOException {
try (Scanner scanner = storage.scan(scan)) {
return scanner.all();
}
}
private List getExpected(
List clusteringKeys,
@Nullable ClusteringKey startClusteringKey,
@Nullable Boolean startInclusive,
@Nullable ClusteringKey endClusteringKey,
@Nullable Boolean endInclusive,
OrderingType orderingType) {
List ret = new ArrayList<>();
for (ClusteringKey clusteringKey : clusteringKeys) {
if (startClusteringKey != null && startInclusive != null) {
int compare = clusteringKey.compareTo(startClusteringKey);
if (!(startInclusive ? compare >= 0 : compare > 0)) {
continue;
}
}
if (endClusteringKey != null && endInclusive != null) {
int compare = clusteringKey.compareTo(endClusteringKey);
if (!(endInclusive ? compare <= 0 : compare < 0)) {
continue;
}
}
ret.add(clusteringKey);
}
if (orderingType == OrderingType.BOTH_SPECIFIED_AND_REVERSED
|| orderingType == OrderingType.ONLY_FIRST_SPECIFIED_AND_REVERSED) {
Collections.reverse(ret);
}
return ret;
}
private int getLimit(boolean withLimit, List expected) {
int limit = 0;
if (withLimit && !expected.isEmpty()) {
if (expected.size() == 1) {
limit = 1;
} else {
limit = random.get().nextInt(expected.size() - 1) + 1;
}
}
return limit;
}
private Scan getScan(
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder,
@Nullable ClusteringKey startClusteringKey,
@Nullable Boolean startInclusive,
@Nullable ClusteringKey endClusteringKey,
@Nullable Boolean endInclusive,
OrderingType orderingType,
int limit) {
Scan scan =
new Scan(getPartitionKey())
.forNamespace(getNamespaceName(firstClusteringKeyType))
.forTable(
getTableName(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder));
if (startClusteringKey != null && startInclusive != null) {
Key key;
if (startClusteringKey.second != null) {
key = new Key(startClusteringKey.first, startClusteringKey.second);
} else {
key = new Key(startClusteringKey.first);
}
scan.withStart(key, startInclusive);
}
if (endClusteringKey != null && endInclusive != null) {
Key key;
if (endClusteringKey.second != null) {
key = new Key(endClusteringKey.first, endClusteringKey.second);
} else {
key = new Key(endClusteringKey.first);
}
scan.withEnd(key, endInclusive);
}
switch (orderingType) {
case BOTH_SPECIFIED:
scan.withOrdering(new Ordering(FIRST_CLUSTERING_KEY, firstClusteringOrder))
.withOrdering(new Ordering(SECOND_CLUSTERING_KEY, secondClusteringOrder));
break;
case ONLY_FIRST_SPECIFIED:
scan.withOrdering(new Ordering(FIRST_CLUSTERING_KEY, firstClusteringOrder));
break;
case BOTH_SPECIFIED_AND_REVERSED:
scan.withOrdering(
new Ordering(FIRST_CLUSTERING_KEY, TestUtils.reverseOrder(firstClusteringOrder)))
.withOrdering(
new Ordering(SECOND_CLUSTERING_KEY, TestUtils.reverseOrder(secondClusteringOrder)));
break;
case ONLY_FIRST_SPECIFIED_AND_REVERSED:
scan.withOrdering(
new Ordering(FIRST_CLUSTERING_KEY, TestUtils.reverseOrder(firstClusteringOrder)));
break;
case NOTHING:
break;
default:
throw new AssertionError();
}
if (limit > 0) {
scan.withLimit(limit);
}
return scan;
}
private void assertScanResult(
List actualResults, List expected, String description) {
List actual = new ArrayList<>();
for (Result actualResult : actualResults) {
assertThat(actualResult.getValue(FIRST_CLUSTERING_KEY).isPresent()).isTrue();
assertThat(actualResult.getValue(SECOND_CLUSTERING_KEY).isPresent()).isTrue();
actual.add(
new ClusteringKey(
actualResult.getValue(FIRST_CLUSTERING_KEY).get(),
actualResult.getValue(SECOND_CLUSTERING_KEY).get()));
}
assertThat(actual).describedAs(description).isEqualTo(expected);
}
private Comparator getClusteringKeyComparator(
Order firstClusteringOrder, Order secondClusteringOrder) {
return (l, r) -> {
ComparisonChain chain =
ComparisonChain.start()
.compare(
l.first,
r.first,
firstClusteringOrder == Order.ASC
? com.google.common.collect.Ordering.natural()
: com.google.common.collect.Ordering.natural().reverse());
if (l.second != null && r.second != null) {
chain =
chain.compare(
l.second,
r.second,
secondClusteringOrder == Order.ASC
? com.google.common.collect.Ordering.natural()
: com.google.common.collect.Ordering.natural().reverse());
}
return chain.result();
};
}
private void executeInParallel(TestForFirstClusteringKeyScan test)
throws java.util.concurrent.ExecutionException, InterruptedException {
List> testCallables = new ArrayList<>();
for (DataType firstClusteringKeyType : clusteringKeyTypes.keySet()) {
for (Order firstClusteringOrder : Order.values()) {
testCallables.add(
() -> {
random.get().setSeed(seed);
truncateTable(firstClusteringKeyType, firstClusteringOrder, DataType.INT, Order.ASC);
List clusteringKeys =
prepareRecords(
firstClusteringKeyType, firstClusteringOrder, DataType.INT, Order.ASC);
test.execute(clusteringKeys, firstClusteringKeyType, firstClusteringOrder);
return null;
});
}
}
executeInParallel(testCallables);
}
private void executeInParallel(TestForSecondClusteringKeyScan test)
throws java.util.concurrent.ExecutionException, InterruptedException {
List> testCallables = new ArrayList<>();
for (DataType firstClusteringKeyType : clusteringKeyTypes.keySet()) {
for (DataType secondClusteringKeyType : clusteringKeyTypes.get(firstClusteringKeyType)) {
for (Order firstClusteringOrder : Order.values()) {
for (Order secondClusteringOrder : Order.values()) {
testCallables.add(
() -> {
random.get().setSeed(seed);
truncateTable(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder);
List clusteringKeys =
prepareRecords(
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder);
test.execute(
clusteringKeys,
firstClusteringKeyType,
firstClusteringOrder,
secondClusteringKeyType,
secondClusteringOrder);
return null;
});
}
}
}
}
executeInParallel(testCallables);
}
private void executeDdls(List> ddls)
throws InterruptedException, java.util.concurrent.ExecutionException {
if (isParallelDdlSupported()) {
executeInParallel(ddls);
} else {
ddls.forEach(
ddl -> {
try {
ddl.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}
private void executeInParallel(List> testCallables)
throws InterruptedException, java.util.concurrent.ExecutionException {
List> futures = executorService.invokeAll(testCallables);
for (Future future : futures) {
future.get();
}
}
@FunctionalInterface
private interface TestForFirstClusteringKeyScan {
void execute(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder)
throws Exception;
}
@FunctionalInterface
private interface TestForSecondClusteringKeyScan {
void execute(
List clusteringKeys,
DataType firstClusteringKeyType,
Order firstClusteringOrder,
DataType secondClusteringKeyType,
Order secondClusteringOrder)
throws Exception;
}
private static class ClusteringKey implements Comparable {
public final Value> first;
@Nullable public final Value> second;
public ClusteringKey(Value> first, @Nullable Value> second) {
this.first = first;
this.second = second;
}
public ClusteringKey(Value> first) {
this(first, null);
}
@Override
public int compareTo(ClusteringKey o) {
ComparisonChain chain = ComparisonChain.start().compare(first, o.first);
if (second != null && o.second != null) {
chain = chain.compare(second, o.second);
}
return chain.result();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ClusteringKey)) {
return false;
}
ClusteringKey that = (ClusteringKey) o;
return first.equals(that.first) && Objects.equals(second, that.second);
}
@Override
public int hashCode() {
return Objects.hash(first, second);
}
@Override
public String toString() {
return "ClusteringKey{" + "first=" + first + ", second=" + second + '}';
}
}
}