blob: b2f2bf9b07ccd9dfc93e06bfc8cf3d69ea4cb28a [file] [log] [blame]
/*
* 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.phoenix.end2end;
import static org.apache.phoenix.util.PhoenixRuntime.TENANT_ID_ATTRIB;
import static org.apache.phoenix.query.PhoenixTestBuilder.DDLDefaults.MAX_ROWS;
import static org.apache.phoenix.query.PhoenixTestBuilder.DDLDefaults.COLUMN_TYPES;
import static org.apache.phoenix.query.PhoenixTestBuilder.DDLDefaults.GLOBAL_VIEW_COLUMNS;
import static org.apache.phoenix.query.PhoenixTestBuilder.DDLDefaults.TENANT_VIEW_COLUMNS;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.ConnectOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.OtherOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.GlobalViewOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.GlobalViewIndexOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TableIndexOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TableOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TenantViewOptions;
import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TenantViewIndexOptions;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Random;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellComparator;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder;
import org.apache.phoenix.query.PhoenixTestBuilder.DataSupplier;
import org.apache.phoenix.query.PhoenixTestBuilder.DataWriter;
import org.apache.phoenix.query.PhoenixTestBuilder.BasicDataWriter;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.util.IndexUtil;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.TestUtil;
import org.junit.Ignore;
import org.junit.Test;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Each column in HBase can have a different timestamp depending on when it gets updated.
* The timestamp of the EMPTY_COLUMN can serve as the timestamp of the row (a row in PHOENIX)
* and can be used to determine TTL expiration of a row in PHOENIX.
* These tests are to validate our expectations of the EMPTY_COLUMN behavior.
* Checks :-
* 1. Behavior for various tables, views (global and tenant), indexes (global and local)
* 2. Behavior under different CF's combinations.
* 3. Behavior under different COLUMN ENCODINGS
*/
public class EmptyColumnIT extends ParallelStatsDisabledIT {
private static final Logger LOGGER = LoggerFactory.getLogger(EmptyColumnIT.class);
private static int DEFAULT_NUM_ROWS = 5;
// Scans the HBase rows directly for the empty column and asserts
private void assertAllHBaseRowsHaveEmptyColumnCell(byte[] hbaseTableName,
byte[] emptyColumnFamilyName, byte[] emptyColumnName, long minTimestamp,
int expectedRows) throws IOException, SQLException {
try (Table tbl = driver.getConnectionQueryServices(getUrl(), TestUtil.TEST_PROPERTIES)
.getTable(hbaseTableName)) {
Scan allRows = new Scan();
allRows.setTimeRange(minTimestamp, minTimestamp + Integer.MAX_VALUE);
ResultScanner scanner = tbl.getScanner(allRows);
int numMatchingRows = getNumRowsWithEmptyColumnAndMaxTimestamp(scanner,
emptyColumnFamilyName, emptyColumnName);
assertEquals(String.format("Expected rows do match for table = %s at timestamp %d",
Bytes.toString(hbaseTableName), minTimestamp), expectedRows, numMatchingRows);
}
}
// return the number of rows that contain the empty column with the the max timestamp.
private int getNumRowsWithEmptyColumnAndMaxTimestamp(ResultScanner scanner,
byte[] emptyColumnFamilyName, byte[] emptyColumnName) {
int numMatchingRows = 0;
try {
for (Result result = scanner.next(); result != null; result = scanner.next()) {
boolean emptyColumnHasMaxTimestamp = true;
if (result.containsColumn(emptyColumnFamilyName, emptyColumnName)) {
Cell emptyColumnCell =
result.getColumnLatestCell(emptyColumnFamilyName, emptyColumnName);
CellScanner cellScanner = result.cellScanner();
while (cellScanner.advance()) {
Cell current = cellScanner.current();
// if current.timestamp > emptyColumnCell.timestamp then it returns -1
if (CellComparator.getInstance().compareTimestamps(current, emptyColumnCell) < 0) {
emptyColumnHasMaxTimestamp &= false;
}
}
if (emptyColumnHasMaxTimestamp) {
numMatchingRows++;
}
}
}
}
catch(Exception e) {
LOGGER.info(e.getLocalizedMessage());
}
return numMatchingRows;
}
/**
* -----------------
* Test methods
* -----------------
*/
@Ignore("fails with java.lang.ArrayIndexOutOfBoundsException: -1 , "
+ "fails for both Table and GlobalView indexes")
// https://issues.apache.org/jira/browse/PHOENIX-5317
// https://issues.apache.org/jira/browse/PHOENIX-5322
public void testWithBasicTenantViewAndTableIndex() throws Exception {
// Define the test schema.
OtherOptions otherOptions = new OtherOptions();
otherOptions.setTableCFs(Lists.newArrayList(null, "A", "B"));
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.getTablePKColumns().add("ID");
tableOptions.getTablePKColumnTypes().add("CHAR(15)");
GlobalViewOptions globalViewOptions = new GlobalViewOptions();
globalViewOptions.setGlobalViewColumns(GLOBAL_VIEW_COLUMNS);
globalViewOptions.setGlobalViewColumnTypes(COLUMN_TYPES);
otherOptions.setGlobalViewCFs(Lists.newArrayList(null, "A", "B"));
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).withGlobalViewOptions(globalViewOptions)
.withSimpleTenantView().withOtherOptions(otherOptions).build();
schemaBuilder.withTableIndexDefaults().build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
@Override public List<Object> getValues(int rowIndex) {
Random rnd = new Random();
String id = String.format("00A0y000%07d", rowIndex);
String col1 = String.format("a%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col2 = String.format("b%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col3 = String.format("c%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col4 = String.format("d%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col5 = String.format("e%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col6 = String.format("f%05d", rowIndex + rnd.nextInt(MAX_ROWS));
return Lists.newArrayList(new Object[] { id, col1, col2, col3, col4, col5, col6 });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
String
tenantConnectUrl =
getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions()
.getTenantId();
try (Connection connection = DriverManager.getConnection(tenantConnectUrl)) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("ID", "COL1", "COL2", "COL3", "COL4", "COL5", "COL6"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTenantViewName());
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, DEFAULT_NUM_ROWS, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, null);
}
}
@Ignore //(" Fails with java.lang.ArrayIndexOutOfBoundsException: 127")
// https://issues.apache.org/jira/browse/PHOENIX-5317
// https://issues.apache.org/jira/browse/PHOENIX-5322
public void testWhenCustomTenantViewWithPKAndGlobalIndex() throws Exception {
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableDefaults().withGlobalViewDefaults().withGlobalViewIndexDefaults()
.withTenantViewDefaults().build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
@Override public List<Object> getValues(int rowIndex) {
String id = String.format("00A0y000%07d", rowIndex);
String zid = String.format("0050z000%07d", rowIndex);
return Lists.newArrayList(
new Object[] { id, zid, "a", "b", "c", "d", "e", "f", "g", "h", "i" });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
String
tenantConnectUrl =
getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions()
.getTenantId();
try (Connection connection = DriverManager.getConnection(tenantConnectUrl)) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("ID", "ZID",
"COL1", "COL2", "COL3",
"COL4", "COL5", "COL6",
"COL7", "COL8", "COL9"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTenantViewName());
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, null);
}
}
@Test public void testWithBasicTableAndNoAdditionalCols() throws Exception {
// Define the test schema.
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.getTablePKColumns().add("ID");
tableOptions.getTablePKColumnTypes().add("CHAR(15)");
tableOptions.getTableColumns().clear();
tableOptions.getTableColumnTypes().clear();
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
final String
orgId =
String.format("00D0x000%s", schemaBuilder.getDataOptions().getUniqueName());
final String kp = SchemaUtil.normalizeIdentifier(schemaBuilder.getEntityKeyPrefix());
@Override public List<Object> getValues(int rowIndex) {
String id = String.format("00A0y000%07d", rowIndex);
return Lists.newArrayList(new Object[] { orgId, kp, id });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
try (Connection connection = DriverManager.getConnection(getUrl())) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(Lists.newArrayList("OID", "KP", "ID"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTableName());
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, null);
}
}
@Test public void testWithGlobalViewAndNoAdditionalCols() throws Exception {
// Define the test schema.
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.getTableColumns().clear();
tableOptions.getTableColumnTypes().clear();
GlobalViewOptions globalViewOptions = GlobalViewOptions.withDefaults();
globalViewOptions.getGlobalViewColumns().clear();
globalViewOptions.getGlobalViewColumnTypes().clear();
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).withGlobalViewOptions(globalViewOptions)
.build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
final String
orgId =
String.format("00D0x000%s", schemaBuilder.getDataOptions().getUniqueName());
final String kp = SchemaUtil.normalizeIdentifier(schemaBuilder.getEntityKeyPrefix());
@Override public List<Object> getValues(int rowIndex) {
String id = String.format("00A0y000%07d", rowIndex);
return Lists.newArrayList(new Object[] { orgId, kp, id });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
try (Connection connection = DriverManager.getConnection(getUrl())) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(Lists.newArrayList("OID", "KP", "ID"));
dataWriter.setTargetEntity(schemaBuilder.getEntityGlobalViewName());
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, null);
}
}
@Test public void testWithCustomTenantViewAndTenantOnlyColumns() throws Exception {
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.getTableColumns().clear();
tableOptions.getTableColumnTypes().clear();
// Define the test schema.
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).withTenantViewDefaults().build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
final String
orgId =
String.format("00D0x000%s", schemaBuilder.getDataOptions().getUniqueName());
final String kp = SchemaUtil.normalizeIdentifier(schemaBuilder.getEntityKeyPrefix());
@Override public List<Object> getValues(int rowIndex) {
Random rnd = new Random();
String zid = String.format("00A0y000%07d", rowIndex);
String col7 = String.format("g%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col8 = String.format("h%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col9 = String.format("i%05d", rowIndex + rnd.nextInt(MAX_ROWS));
return Lists.newArrayList(new Object[] { orgId, kp, zid, col7, col8, col9 });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
String
tenantConnectUrl =
getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions()
.getTenantId();
try (Connection connection = DriverManager.getConnection(tenantConnectUrl)) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("OID", "KP", "ZID", "COL7", "COL8", "COL9"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTenantViewName());
// dataSupplier.upsertValues column positions to be used for partial updates.
List<Integer> columnsForPartialUpdates = Lists.newArrayList(0, 1, 2, 3, 5);
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, columnsForPartialUpdates);
}
}
/**
* This test uses a simple table and NO indexes and
* run with different combinations of table properties and column family options.
*/
@Test public void testWhenTableWithNoIndexAndVariousOptions() throws Exception {
for (String additionalProps : Lists
.newArrayList("COLUMN_ENCODED_BYTES=0", "DEFAULT_COLUMN_FAMILY='Z'")) {
StringBuilder withTableProps = new StringBuilder();
withTableProps.append("MULTI_TENANT=true,").append(additionalProps);
for (OtherOptions options : getTableColumnFamilyOptions()) {
// Define the test schema.
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.getTablePKColumns().add("ID");
tableOptions.getTablePKColumnTypes().add("CHAR(15)");
tableOptions.setTableProps(withTableProps.toString());
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).withOtherOptions(options).build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
final String
orgId =
String.format("00D0x000%s",
schemaBuilder.getDataOptions().getUniqueName());
final String
kp =
SchemaUtil.normalizeIdentifier(schemaBuilder.getEntityKeyPrefix());
@Override public List<Object> getValues(int rowIndex) {
Random rnd = new Random();
String id = String.format("00A0y000%07d", rowIndex);
String col1 = String.format("a%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col2 = String.format("b%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col3 = String.format("c%05d", rowIndex + rnd.nextInt(MAX_ROWS));
return Lists.newArrayList(new Object[] { orgId, kp, id, col1, col2, col3 });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
try (Connection connection = DriverManager.getConnection(getUrl())) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("OID", "KP", "ID", "COL1", "COL2", "COL3"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTableName());
// dataSupplier.upsertValues column positions to be used for partial updates.
List<Integer> columnsForPartialUpdates = Lists.newArrayList(0, 1, 2, 3, 5);
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, columnsForPartialUpdates);
}
}
}
}
/**
* This test uses a simple table and index and
* runs with different combinations of
* table properties, index types (local or global) and column family options.
*/
@Test public void testWhenTableWithIndexAndVariousOptions() throws Exception {
// Run for different combinations of
// table properties, index types (local or global) and column family options.
for (String additionalProps : Lists
.newArrayList("COLUMN_ENCODED_BYTES=0", "DEFAULT_COLUMN_FAMILY='Z'")) {
StringBuilder withTableProps = new StringBuilder();
withTableProps.append("MULTI_TENANT=true,").append(additionalProps);
for (boolean isTableIndexLocal : Lists.newArrayList(true, false)) {
for (OtherOptions options : getTableColumnFamilyOptions()) {
// Define the test table schema.
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.getTablePKColumns().add("ID");
tableOptions.getTablePKColumnTypes().add("CHAR(15)");
tableOptions.setTableProps(withTableProps.toString());
// Define the index on the test table.
TableIndexOptions tableIndexOptions = TableIndexOptions.withDefaults();
tableIndexOptions.setLocal(isTableIndexLocal);
// Build the schema with the above options
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions)
.withTableIndexOptions(tableIndexOptions).withOtherOptions(options)
.build();
// Define the test data provider.
DataSupplier dataSupplier = new DataSupplier() {
final String
orgId =
String.format("00D0x000%s",
schemaBuilder.getDataOptions().getUniqueName());
final String
kp =
SchemaUtil.normalizeIdentifier(schemaBuilder.getEntityKeyPrefix());
@Override public List<Object> getValues(int rowIndex) {
Random rnd = new Random();
String id = String.format("00A0y000%07d", rowIndex);
String col1 = String.format("a%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col2 = String.format("b%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col3 = String.format("c%05d", rowIndex + rnd.nextInt(MAX_ROWS));
return Lists
.newArrayList(new Object[] { orgId, kp, id, col1, col2, col3 });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
try (Connection connection = DriverManager.getConnection(getUrl())) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("OID", "KP", "ID", "COL1", "COL2", "COL3"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTableName());
// dataSupplier.upsertValues column positions to be used for partial updates.
List<Integer> columnsForPartialUpdates = Lists.newArrayList(0, 1, 2, 3, 5);
// COL3 is the include column for the table index in this schema => index pos of 2
// and there are no global and view indexes.
List<Integer>
includeColumnPositionOfIndexes =
Lists.newArrayList(2, null, null);
/**
* When table indexes are local i.e index rows are co-located.
* AND
* When there are more than one index and
* the CFs of the include columns match.
* Then the # of index rows in the table (when local) and
* in the index table (when global)
* is => # of rows * # of indexes
*
* But in this schema there is only one index =>
* # of index rows = # of upserted rows.
*/
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, DEFAULT_NUM_ROWS, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults,
dataWriter, schemaBuilder, columnsForPartialUpdates,
includeColumnPositionOfIndexes);
}
}
}
}
}
/**
* This test uses a tenant view hierarchy => table -> globalView -> tenantView
* Run with different combinations of
* table properties, index types (local or global) and column family options.
*/
@Test public void testWhenCustomTenantViewWithNoIndexAndVariousOptions() throws Exception {
for (String additionalProps : Lists
.newArrayList("COLUMN_ENCODED_BYTES=0", "DEFAULT_COLUMN_FAMILY='Z'")) {
StringBuilder withTableProps = new StringBuilder();
withTableProps.append("MULTI_TENANT=true,").append(additionalProps);
for (OtherOptions options : getTableAndGlobalAndTenantColumnFamilyOptions()) {
// Define the test schema
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.setTableProps(withTableProps.toString());
TenantViewOptions tenantViewOptions = new TenantViewOptions();
tenantViewOptions.setTenantViewColumns(Lists.newArrayList(TENANT_VIEW_COLUMNS));
tenantViewOptions.setTenantViewColumnTypes(Lists.newArrayList(COLUMN_TYPES));
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).withGlobalViewDefaults()
.withTenantViewOptions(tenantViewOptions).withOtherOptions(options).build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
@Override public List<Object> getValues(int rowIndex) {
Random rnd = new Random();
String id = String.format("00A0y000%07d", rowIndex);
String col1 = String.format("a%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col2 = String.format("b%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col3 = String.format("c%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col4 = String.format("d%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col5 = String.format("e%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col6 = String.format("f%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col7 = String.format("g%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col8 = String.format("h%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String col9 = String.format("i%05d", rowIndex + rnd.nextInt(MAX_ROWS));
return Lists.newArrayList(
new Object[] { id, col1, col2, col3, col4, col5, col6, col7, col8,
col9 });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
String
tenantConnectUrl =
getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions()
.getTenantId();
try (Connection connection = DriverManager.getConnection(tenantConnectUrl)) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("ID",
"COL1", "COL2", "COL3",
"COL4", "COL5", "COL6",
"COL7", "COL8", "COL9"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTenantViewName());
// dataSupplier.upsertValues column positions to be used for partial updates.
List<Integer> columnsForPartialUpdates = Lists.newArrayList(0, 7, 9);
// Write the data and run validations
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0, 0);
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults, dataWriter,
schemaBuilder, columnsForPartialUpdates);
}
}
}
}
@Ignore("Fails with - "
+ "Expected rows do match for table = xxxx at timestamp xxx expected:<5> but was:<10>")
// https://issues.apache.org/jira/browse/PHOENIX-5476
public void testWhenCustomTenantViewWithIndexAndVariousOptions() throws Exception {
for (String additionalProps : Lists
.newArrayList("COLUMN_ENCODED_BYTES=0", "DEFAULT_COLUMN_FAMILY='Z'")) {
StringBuilder withTableProps = new StringBuilder();
withTableProps.append("MULTI_TENANT=true,").append(additionalProps);
for (boolean isGlobalViewLocal : Lists.newArrayList(true, false)) {
for (boolean isTenantViewLocal : Lists.newArrayList(true, false)) {
for (OtherOptions options : getTableAndGlobalAndTenantColumnFamilyOptions()) {
// Define the test schema
TableOptions tableOptions = TableOptions.withDefaults();
tableOptions.setTableProps(withTableProps.toString());
GlobalViewIndexOptions
globalViewIndexOptions =
GlobalViewIndexOptions.withDefaults();
globalViewIndexOptions.setLocal(isGlobalViewLocal);
TenantViewOptions tenantViewOptions = new TenantViewOptions();
tenantViewOptions
.setTenantViewColumns(Lists.newArrayList(TENANT_VIEW_COLUMNS));
tenantViewOptions
.setTenantViewColumnTypes(Lists.newArrayList(COLUMN_TYPES));
TenantViewIndexOptions
tenantViewIndexOptions =
TenantViewIndexOptions.withDefaults();
tenantViewIndexOptions.setLocal(isTenantViewLocal);
final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
schemaBuilder.withTableOptions(tableOptions).withGlobalViewDefaults()
.withGlobalViewIndexOptions(globalViewIndexOptions)
.withTenantViewOptions(tenantViewOptions)
.withTenantViewIndexOptions(tenantViewIndexOptions)
.withOtherOptions(options).build();
// Define the test data.
DataSupplier dataSupplier = new DataSupplier() {
@Override public List<Object> getValues(int rowIndex) {
Random rnd = new Random();
String id = String.format("00A0y000%07d", rowIndex);
String
col1 =
String.format("a%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col2 =
String.format("b%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col3 =
String.format("c%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col4 =
String.format("d%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col5 =
String.format("e%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col6 =
String.format("f%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col7 =
String.format("g%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col8 =
String.format("h%05d", rowIndex + rnd.nextInt(MAX_ROWS));
String
col9 =
String.format("i%05d", rowIndex + rnd.nextInt(MAX_ROWS));
return Lists.newArrayList(
new Object[] { id, col1, col2, col3, col4, col5, col6, col7,
col8, col9 });
}
};
// Create a test data writer for the above schema.
DataWriter dataWriter = new BasicDataWriter();
String
tenantConnectUrl =
getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder
.getDataOptions().getTenantId();
try (Connection connection = DriverManager
.getConnection(tenantConnectUrl)) {
connection.setAutoCommit(true);
dataWriter.setConnection(connection);
dataWriter.setDataSupplier(dataSupplier);
dataWriter.setUpsertColumns(
Lists.newArrayList("ID", "COL1", "COL2", "COL3", "COL4", "COL5",
"COL6", "COL7", "COL8", "COL9"));
dataWriter.setTargetEntity(schemaBuilder.getEntityTenantViewName());
// upsertValues column positions to be used for partial updates.
List<Integer> columnsForPartialUpdates = Lists.newArrayList(0, 7, 9);
// No index for table.
// COL6 is the include column for the global view index => index pos of 2
// COL7 is the include column for the tenant view index => index pos of 0
List<Integer>
includeColumnPositionOfIndexes =
Lists.newArrayList(null, 2, 0);
// Write the data and run validations
try {
LOGGER.debug(String.format("### BEGIN %s",
schemaBuilder.getOtherOptions().getTestName()));
/**
* WHEN global and tenant view indexes are
* either both local or both global i.e index rows are co-located.
* AND
* WHEN the CFs of the include columns match.
* THEN the # of index rows in the table (when local) and
* in the index table (when global)
* # of index rows => # of upserted rows * # of indexes
* ELSE
* # of index rows => # of upserted rows
*/
ExpectedTestResults
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0,
DEFAULT_NUM_ROWS);
boolean colocated = !(isGlobalViewLocal ^ isTenantViewLocal);
boolean
cfsAreNull =
(options.getGlobalViewCFs().get(2) == null
&& options.getGlobalViewCFs().get(2) == options
.getTenantViewCFs().get(0));
boolean
cfsAreNotNullButEqual =
!(cfsAreNull) && (options.getGlobalViewCFs().get(2)
.equalsIgnoreCase(
options.getTenantViewCFs().get(0)));
if (colocated && (cfsAreNull || cfsAreNotNullButEqual)) {
expectedTestResults =
new ExpectedTestResults(DEFAULT_NUM_ROWS, 0,
DEFAULT_NUM_ROWS * 2);
}
upsertDataAndRunValidations(DEFAULT_NUM_ROWS, expectedTestResults,
dataWriter, schemaBuilder, columnsForPartialUpdates,
includeColumnPositionOfIndexes);
LOGGER.debug(String.format(
"### Case => [GlobalView (local) = %b, "
+ "TenantView (local) = %b] : %s",
isGlobalViewLocal, isTenantViewLocal, "Passed"));
} catch (AssertionError ae) {
LOGGER.debug(String.format(
"### Case => [GlobalView (local) = %b, "
+ "TenantView (local) = %b] : %s",
isGlobalViewLocal, isTenantViewLocal, ae.getMessage()));
} finally {
LOGGER.debug(String.format("### END %s",
schemaBuilder.getOtherOptions().getTestName()));
}
}
}
}
}
}
}
private void upsertDataAndRunValidations(int numRowsToUpsert,
ExpectedTestResults expectedTestResults, DataWriter dataWriter,
SchemaBuilder schemaBuilder, List<Integer> overriddenColumnsPositions)
throws IOException, SQLException {
//Insert for the first time and validate them.
validateEmptyColumnsAreUpdated(upsertData(dataWriter, numRowsToUpsert), expectedTestResults,
schemaBuilder, Lists.newArrayList(new Integer[] {}));
// Update the above rows and validate the same.
validateEmptyColumnsAreUpdated(upsertData(dataWriter, numRowsToUpsert), expectedTestResults,
schemaBuilder, Lists.newArrayList(new Integer[] {}));
if (overriddenColumnsPositions != null && overriddenColumnsPositions.size() > 0) {
dataWriter.setColumnPositionsToUpdate(overriddenColumnsPositions);
}
// Upsert and validate the partially updated rows.
validateEmptyColumnsAreUpdated(upsertData(dataWriter, numRowsToUpsert), expectedTestResults,
schemaBuilder, Lists.newArrayList(new Integer[] {}));
}
private void upsertDataAndRunValidations(int numRowsToUpsert,
ExpectedTestResults expectedTestResults, DataWriter dataWriter,
SchemaBuilder schemaBuilder, List<Integer> overriddenColumnsPositions,
List<Integer> indexedCFPositions) throws IOException, SQLException {
//Insert for the first time and validate them.
validateEmptyColumnsAreUpdated(upsertData(dataWriter, numRowsToUpsert), expectedTestResults,
schemaBuilder, indexedCFPositions);
// Update the above rows and validate the same.
validateEmptyColumnsAreUpdated(upsertData(dataWriter, numRowsToUpsert), expectedTestResults,
schemaBuilder, indexedCFPositions);
if (overriddenColumnsPositions != null && overriddenColumnsPositions.size() > 0) {
dataWriter.setColumnPositionsToUpdate(overriddenColumnsPositions);
}
// Upsert and validate the partially updated rows.
validateEmptyColumnsAreUpdated(upsertData(dataWriter, numRowsToUpsert), expectedTestResults,
schemaBuilder, indexedCFPositions);
}
private long upsertData(DataWriter dataWriter, int numRowsToUpsert) throws SQLException {
// Upsert rows
long earliestTimestamp = System.currentTimeMillis();
for (int i = 0; i < numRowsToUpsert; i++) {
dataWriter.upsertRow(i);
}
return earliestTimestamp;
}
private void validateEmptyColumnsAreUpdated(long earliestTimestamp,
ExpectedTestResults expectedTestResults, SchemaBuilder schemaBuilder,
List<Integer> indexedCFPositions) throws IOException, SQLException {
// Base table's empty CF and column name
PTable table = schemaBuilder.getBaseTable();
byte[] emptyColumnFamilyName = SchemaUtil.getEmptyColumnFamily(table);
byte[]
emptyColumnName =
table.getEncodingScheme() == PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS ?
QueryConstants.EMPTY_COLUMN_BYTES :
table.getEncodingScheme().encode(QueryConstants.ENCODED_EMPTY_COLUMN_NAME);
byte[]
hbaseBaseTableName =
SchemaUtil.getTableNameAsBytes(table.getSchemaName().getString(),
table.getTableName().getString());
byte[] hbaseIndexTableName = Bytes.toBytes("");
byte[] indexColumnFamilyName = Bytes.toBytes("");
byte[] hbaseGlobalViewIndexTableName = Bytes.toBytes("");
byte[] globalViewIndexCFName = Bytes.toBytes("");
byte[] hbaseTenantViewIndexTableName = Bytes.toBytes("");
byte[] tenantViewIndexCFName = Bytes.toBytes("");
boolean assertOnIndexTable = false;
boolean assertOnGlobalIndexTable = false;
boolean assertOnTenantIndexTable = false;
// Find the index CF name when table index exists.
if (schemaBuilder.isTableIndexEnabled() && schemaBuilder.isTableIndexCreated()
&& indexedCFPositions.size() > 0) {
String tableIndexName = String.format("IDX_%s", table.getTableName().getString());
// The table holding the index data - depends on whether index is local or global.
hbaseIndexTableName =
schemaBuilder.getTableIndexOptions().isLocal() ?
hbaseBaseTableName :
SchemaUtil.getTableNameAsBytes(table.getSchemaName().getString(),
tableIndexName);
String
testDataColumnFamilyName =
schemaBuilder.getOtherOptions().getTableCFs().get(indexedCFPositions.get(0));
String
dataColumnFamilyName =
testDataColumnFamilyName == null ?
Bytes.toString(emptyColumnFamilyName) :
testDataColumnFamilyName;
indexColumnFamilyName =
Bytes.toBytes(schemaBuilder.getTableIndexOptions().isLocal() ?
IndexUtil.getLocalIndexColumnFamily(dataColumnFamilyName) :
dataColumnFamilyName);
LOGGER.debug(String.format("### Table Index CF name : %s, Table Index table name : %s",
Bytes.toString(indexColumnFamilyName), Bytes.toString(hbaseIndexTableName)));
assertOnIndexTable = true;
}
// Find the index CF name when global view index exists.
if (schemaBuilder.isGlobalViewIndexEnabled() && schemaBuilder.isGlobalViewIndexCreated()
&& indexedCFPositions.size() > 0) {
String
viewIndexSchemaName =
String.format("_IDX_%s", table.getSchemaName().getString());
hbaseGlobalViewIndexTableName =
schemaBuilder.getGlobalViewIndexOptions().isLocal() ?
hbaseBaseTableName :
SchemaUtil.getTableNameAsBytes(viewIndexSchemaName,
table.getTableName().getString());
String
testDataColumnFamilyName =
schemaBuilder.getOtherOptions().getGlobalViewCFs()
.get(indexedCFPositions.get(1));
String
dataColumnFamilyName =
testDataColumnFamilyName == null ?
Bytes.toString(emptyColumnFamilyName) :
testDataColumnFamilyName;
globalViewIndexCFName =
Bytes.toBytes(schemaBuilder.getGlobalViewIndexOptions().isLocal() ?
IndexUtil.getLocalIndexColumnFamily(dataColumnFamilyName) :
dataColumnFamilyName);
LOGGER.info(String.format(
"### Global View Index CF name : %s, Global View Index table name : %s",
Bytes.toString(indexColumnFamilyName),
Bytes.toString(hbaseGlobalViewIndexTableName)));
assertOnGlobalIndexTable = true;
}
// Find the index CF name when tenant view index exists.
if (schemaBuilder.isTenantViewIndexEnabled() && schemaBuilder.isTenantViewIndexCreated()
&& indexedCFPositions.size() > 0) {
String
viewIndexSchemaName =
String.format("_IDX_%s", table.getSchemaName().getString());
hbaseTenantViewIndexTableName =
schemaBuilder.getTenantViewIndexOptions().isLocal() ?
hbaseBaseTableName :
SchemaUtil.getTableNameAsBytes(viewIndexSchemaName,
table.getTableName().getString());
String
testDataColumnFamilyName =
schemaBuilder.getOtherOptions().getTenantViewCFs()
.get(indexedCFPositions.get(2));
String
dataColumnFamilyName =
testDataColumnFamilyName == null ?
Bytes.toString(emptyColumnFamilyName) :
testDataColumnFamilyName;
tenantViewIndexCFName =
Bytes.toBytes(schemaBuilder.getTenantViewIndexOptions().isLocal() ?
IndexUtil.getLocalIndexColumnFamily(dataColumnFamilyName) :
dataColumnFamilyName);
LOGGER.info(String.format("### Tenant Index CF name : %s, Tenant Index table name : %s",
Bytes.toString(indexColumnFamilyName),
Bytes.toString(hbaseTenantViewIndexTableName)));
assertOnTenantIndexTable = true;
}
// Assert on base table rows
assertAllHBaseRowsHaveEmptyColumnCell(hbaseBaseTableName, emptyColumnFamilyName,
emptyColumnName, earliestTimestamp, expectedTestResults.numTableRowsExpected);
// Assert on index table rows
if (assertOnIndexTable) {
assertAllHBaseRowsHaveEmptyColumnCell(hbaseIndexTableName, indexColumnFamilyName,
emptyColumnName, earliestTimestamp,
expectedTestResults.numTableIndexRowsExpected);
}
// Assert on global view index table rows
if (assertOnGlobalIndexTable) {
assertAllHBaseRowsHaveEmptyColumnCell(hbaseGlobalViewIndexTableName,
globalViewIndexCFName, emptyColumnName, earliestTimestamp,
expectedTestResults.numViewIndexRowsExpected);
}
// Assert on tenant view index table rows
if (assertOnTenantIndexTable) {
assertAllHBaseRowsHaveEmptyColumnCell(hbaseTenantViewIndexTableName,
tenantViewIndexCFName, emptyColumnName, earliestTimestamp,
expectedTestResults.numViewIndexRowsExpected);
}
}
private List<ConnectOptions> getConnectOptions() {
List<ConnectOptions> testCases = Lists.newArrayList();
ConnectOptions defaultConnectOptions = new ConnectOptions();
testCases.add(defaultConnectOptions);
ConnectOptions globalOnlyConnectOptions = new ConnectOptions();
globalOnlyConnectOptions.setUseGlobalConnectionOnly(true);
testCases.add(globalOnlyConnectOptions);
ConnectOptions tenantOnlyConnectOptions = new ConnectOptions();
tenantOnlyConnectOptions.setUseTenantConnectionForGlobalView(true);
testCases.add(tenantOnlyConnectOptions);
return testCases;
}
private List<OtherOptions> getTableColumnFamilyOptions() {
List<OtherOptions> testCases = Lists.newArrayList();
OtherOptions testCaseWhenAllCFMatch = new OtherOptions();
testCaseWhenAllCFMatch.setTestName("testCaseWhenAllCFMatch");
testCaseWhenAllCFMatch.setTableCFs(Lists.newArrayList("A", "A", "A"));
testCases.add(testCaseWhenAllCFMatch);
OtherOptions testCaseWhenManyCFs = new OtherOptions();
testCaseWhenManyCFs.setTestName("testCaseWhenManyCFs");
testCaseWhenManyCFs.setTableCFs(Lists.newArrayList(null, "A", "B"));
testCases.add(testCaseWhenManyCFs);
OtherOptions testCaseWhenAllCFsAreSpecified = new OtherOptions();
testCaseWhenAllCFsAreSpecified.setTestName("testCaseWhenAllCFsAreSpecified");
testCaseWhenAllCFsAreSpecified.setTableCFs(Lists.newArrayList("A", "A", "B"));
testCases.add(testCaseWhenAllCFsAreSpecified);
OtherOptions testCaseWhenDefaultCFs = new OtherOptions();
testCaseWhenDefaultCFs.setTestName("testCaseWhenDefaultCFs");
testCaseWhenDefaultCFs.setTableCFs(Lists.newArrayList((String) null, null, null));
testCases.add(testCaseWhenDefaultCFs);
return testCases;
}
private List<OtherOptions> getTableAndGlobalAndTenantColumnFamilyOptions() {
List<OtherOptions> testCases = Lists.newArrayList();
OtherOptions testCaseWhenAllCFMatchAndAllDefault = new OtherOptions();
testCaseWhenAllCFMatchAndAllDefault.setTestName("testCaseWhenAllCFMatchAndAllDefault");
testCaseWhenAllCFMatchAndAllDefault
.setTableCFs(Lists.newArrayList((String) null, null, null));
testCaseWhenAllCFMatchAndAllDefault
.setGlobalViewCFs(Lists.newArrayList((String) null, null, null));
testCaseWhenAllCFMatchAndAllDefault
.setTenantViewCFs(Lists.newArrayList((String) null, null, null));
testCases.add(testCaseWhenAllCFMatchAndAllDefault);
OtherOptions testCaseWhenAllCFMatchAndSame = new OtherOptions();
testCaseWhenAllCFMatchAndSame.setTestName("testCaseWhenAllCFMatchAndSame");
testCaseWhenAllCFMatchAndSame.setTableCFs(Lists.newArrayList("A", "A", "A"));
testCaseWhenAllCFMatchAndSame.setGlobalViewCFs(Lists.newArrayList("A", "A", "A"));
testCaseWhenAllCFMatchAndSame.setTenantViewCFs(Lists.newArrayList("A", "A", "A"));
testCases.add(testCaseWhenAllCFMatchAndSame);
OtherOptions testCaseWhenAllCFMatch = new OtherOptions();
testCaseWhenAllCFMatch.setTestName("testCaseWhenAllCFMatch");
testCaseWhenAllCFMatch.setTableCFs(Lists.newArrayList(null, "A", "B"));
testCaseWhenAllCFMatch.setGlobalViewCFs(Lists.newArrayList(null, "A", "B"));
testCaseWhenAllCFMatch.setTenantViewCFs(Lists.newArrayList(null, "A", "B"));
testCases.add(testCaseWhenAllCFMatch);
OtherOptions testCaseWhenTableCFsAreDiff = new OtherOptions();
testCaseWhenTableCFsAreDiff.setTestName("testCaseWhenTableCFsAreDiff");
testCaseWhenTableCFsAreDiff.setTableCFs(Lists.newArrayList(null, "A", "B"));
testCaseWhenTableCFsAreDiff.setGlobalViewCFs(Lists.newArrayList("A", "A", "B"));
testCaseWhenTableCFsAreDiff.setTenantViewCFs(Lists.newArrayList("A", "A", "B"));
testCases.add(testCaseWhenTableCFsAreDiff);
OtherOptions testCaseWhenGlobalAndTenantCFsAreDiff = new OtherOptions();
testCaseWhenGlobalAndTenantCFsAreDiff.setTestName("testCaseWhenGlobalAndTenantCFsAreDiff");
testCaseWhenGlobalAndTenantCFsAreDiff.setTableCFs(Lists.newArrayList(null, "A", "B"));
testCaseWhenGlobalAndTenantCFsAreDiff.setGlobalViewCFs(Lists.newArrayList("A", "A", "A"));
testCaseWhenGlobalAndTenantCFsAreDiff.setTenantViewCFs(Lists.newArrayList("B", "B", "B"));
testCases.add(testCaseWhenGlobalAndTenantCFsAreDiff);
OtherOptions testCaseWhenNoDefaultCF = new OtherOptions();
testCaseWhenNoDefaultCF.setTestName("testCaseWhenNoDefaultCF");
testCaseWhenNoDefaultCF.setTableCFs(Lists.newArrayList("A", "A", "B"));
testCaseWhenNoDefaultCF.setGlobalViewCFs(Lists.newArrayList("A", "A", "B"));
testCaseWhenNoDefaultCF.setTenantViewCFs(Lists.newArrayList("A", "A", "B"));
testCases.add(testCaseWhenNoDefaultCF);
OtherOptions testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff = new OtherOptions();
testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff
.setTestName("testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff");
testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff
.setTableCFs(Lists.newArrayList("A", "A", "B"));
testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff
.setGlobalViewCFs(Lists.newArrayList("B", "B", "B"));
testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff
.setTenantViewCFs(Lists.newArrayList("A", "A", "A"));
testCases.add(testCaseWhenNoDefaultCFAndGlobalAndTenantCFsAreDiff);
/*
// This fails even with "phoenix.view.allowNewColumnFamily" == true
OtherOptions testCaseWhenTableAndViewCFAreDisjoint = new OtherOptions();
testCaseWhenTableAndViewCFAreDisjoint.tableCFs = Lists.newArrayList("A", "A", "B");
testCaseWhenTableAndViewCFAreDisjoint.globalViewCFs = Lists.newArrayList("A", "C", "D");
testCaseWhenTableAndViewCFAreDisjoint.tenantViewCFs = Lists.newArrayList("A", "E", "F");
testCases.add(testCaseWhenTableAndViewCFAreDisjoint);
*/
return testCases;
}
private static class ExpectedTestResults {
int numTableRowsExpected;
int numTableIndexRowsExpected;
int numViewIndexRowsExpected;
public ExpectedTestResults(int numTableRowsExpected, int numTableIndexRowsExpected,
int numViewIndexRowsExpected) {
this.numTableRowsExpected = numTableRowsExpected;
this.numTableIndexRowsExpected = numTableIndexRowsExpected;
this.numViewIndexRowsExpected = numViewIndexRowsExpected;
}
}
}