/**
* Copyright 2015 Cloudera Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kitesdk.data.hbase.spi;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.kitesdk.data.DatasetDescriptor;
import org.kitesdk.data.DatasetReader;
import org.kitesdk.data.RandomAccessDataset;
import org.kitesdk.data.hbase.HBaseDatasetRepository;
import org.kitesdk.data.hbase.HBaseDatasetRepositoryTest;
import org.kitesdk.data.hbase.avro.AvroUtils;
import org.kitesdk.data.hbase.avro.entities.ArrayRecord;
import org.kitesdk.data.hbase.avro.entities.EmbeddedRecord;
import org.kitesdk.data.hbase.avro.entities.TestEntity;
import org.kitesdk.data.hbase.avro.entities.TestEnum;
import org.kitesdk.data.hbase.impl.PutAction;
import org.kitesdk.data.hbase.impl.PutActionModifier;
import org.kitesdk.data.hbase.impl.ScanModifier;
import org.kitesdk.data.hbase.testing.HBaseTestUtils;
import java.util.ArrayList;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test for registering action modifiers
*/
public class TestHBaseActionModifiable {
private static final String testEntity;
private static final String tableName = "testtable";
private static final String managedTableName = "managed_schemas";
private HBaseDatasetRepository repo;
private RandomAccessDataset<TestEntity> ds;
static {
try {
testEntity = AvroUtils.inputStreamToString(
HBaseDatasetRepositoryTest.class
.getResourceAsStream("/TestEntity.avsc"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@BeforeClass
public static void beforeClass() throws Exception {
HBaseTestUtils.getMiniCluster();
// managed table should be created by HBaseDatasetRepository
HBaseTestUtils.util.deleteTable(Bytes.toBytes(managedTableName));
}
@AfterClass
public static void afterClass() throws Exception {
HBaseTestUtils.util.deleteTable(Bytes.toBytes(tableName));
}
@Before
public void setup() throws Exception {
repo = new HBaseDatasetRepository.Builder()
.configuration(HBaseTestUtils.getConf()).build();
DatasetDescriptor descriptor = new DatasetDescriptor.Builder()
.schemaLiteral(testEntity).build();
ds = repo.create("default", tableName, descriptor, TestEntity.class);
}
@After
public void after() throws Exception {
((HBaseActionModifiable) ds).clearAllModifiers();
repo.delete("default", tableName);
HBaseTestUtils.util.truncateTable(Bytes.toBytes(tableName));
HBaseTestUtils.util.truncateTable(Bytes.toBytes(managedTableName));
}
@Test
public void testGetActionModifiers() {
HBaseActionModifiable amd = (HBaseActionModifiable) ds;
PutActionModifier putActionModifier = newPutActionModifier("testModifierId",
"TestValue");
amd.registerPutActionModifier(putActionModifier);
ScanModifier scanModifier = newScanModifier("OtherTestValue");
amd.registerScanModifier(scanModifier);
assertTrue(amd.getGetModifiers().isEmpty());
assertTrue(amd.getDeleteActionModifiers().isEmpty());
assertEquals(1, amd.getPutActionModifiers().size());
assertEquals(putActionModifier, amd.getPutActionModifiers().get(0));
assertEquals(1, amd.getScanModifiers().size());
assertEquals(scanModifier, amd.getScanModifiers().get(0));
}
@Test
public void testPutScanActionModifiers() {
HBaseActionModifiable amd = (HBaseActionModifiable) ds;
amd.registerPutActionModifier(
newPutActionModifier("testModifierId", "TestValue"));
saveTestEntity(newTestEntity());
amd.registerScanModifier(newScanModifier("OtherTestValue"));
checkRecord(false);
amd.clearScanModifiers();
amd.registerScanModifier(newScanModifier("TestValue"));
checkRecord(true);
}
@Test
public void testDuplicatePutActionModifiers() {
HBaseActionModifiable amd = (HBaseActionModifiable) ds;
// This should be replaced
amd.registerPutActionModifier(
newPutActionModifier("testModifiedId", "OtherTestValue"));
amd.registerPutActionModifier(
newPutActionModifier("testModifiedId", "TestValue"));
saveTestEntity(newTestEntity());
// Scan with OtherTestValue should not return any records
amd.registerScanModifier(newScanModifier("OtherTestValue"));
checkRecord(false);
amd.clearScanModifiers();
// Scan with TestValue should return records
amd.registerScanModifier(newScanModifier("TestValue"));
checkRecord(true);
}
private void checkRecord(boolean shouldExist) {
DatasetReader<TestEntity> dsReader = ds.newReader();
try {
if (shouldExist) {
assertTrue(dsReader.hasNext());
} else {
assertFalse(dsReader.hasNext());
}
} finally {
dsReader.close();
}
}
private ScanModifier newScanModifier(final String value) {
return new ScanModifier() {
@Override
public Scan modifyScan(Scan scan) {
scan.addColumn(Bytes.toBytes("meta"), Bytes.toBytes("testcf"));
SingleColumnValueFilter filter = new SingleColumnValueFilter(
Bytes.toBytes("meta"), Bytes.toBytes("testcf"),
CompareFilter.CompareOp.EQUAL, Bytes.toBytes(value));
filter.setFilterIfMissing(true);
scan.setFilter(filter);
return scan;
}
};
}
private PutActionModifier newPutActionModifier(String id, String value) {
return new TestPutActionModifier(id, value);
}
private void saveTestEntity(TestEntity entity) {
ds.put(entity);
}
private TestEntity newTestEntity() {
return TestEntity.newBuilder().setPart1("part1").setPart2("part2")
.setField1("field1").setField2("field2")
.setField3(new HashMap<String, String>()).setField4(
EmbeddedRecord.newBuilder().setEmbeddedField1("embeddedField1")
.setEmbeddedField2(2).build())
.setField5(new ArrayList<ArrayRecord>()).setEnum$(TestEnum.ENUM1)
.build();
}
private class TestPutActionModifier implements PutActionModifier {
private String id;
private String value;
public TestPutActionModifier(String id, String value) {
this.id = id;
this.value = value;
}
@Override
public PutAction modifyPutAction(PutAction putAction) {
Put put = putAction.getPut();
put.add(Bytes.toBytes("meta"), Bytes.toBytes("testcf"),
Bytes.toBytes(value));
return new PutAction(put);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TestPutActionModifier that = (TestPutActionModifier) o;
return id.equals(that.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}
}