/*
* Copyright © 2015 Cask Data, 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 co.cask.cdap.data2.dataset2.lib.table;
import co.cask.cdap.api.common.Bytes;
import co.cask.cdap.api.data.batch.Split;
import co.cask.cdap.api.data.batch.SplitReader;
import co.cask.cdap.api.dataset.lib.CloseableIterator;
import co.cask.cdap.api.dataset.lib.KeyValue;
import co.cask.cdap.api.dataset.lib.ObjectMappedTable;
import co.cask.cdap.api.dataset.lib.ObjectMappedTableProperties;
import co.cask.cdap.data2.dataset2.DatasetFrameworkTestUtil;
import co.cask.cdap.proto.Id;
import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Test for {@link ObjectMappedTableDataset}.
*/
public class ObjectMappedTableDatasetTest {
@ClassRule
public static DatasetFrameworkTestUtil dsFrameworkUtil = new DatasetFrameworkTestUtil();
private static final Id.DatasetInstance RECORDS_ID =
Id.DatasetInstance.from(DatasetFrameworkTestUtil.NAMESPACE_ID, "records");
@Test
public void testGetPutDelete() throws Exception {
dsFrameworkUtil.createInstance(ObjectMappedTable.class.getName(), RECORDS_ID,
ObjectMappedTableProperties.builder().setType(Record.class).build());
try {
ObjectMappedTableDataset<Record> records = dsFrameworkUtil.getInstance(RECORDS_ID);
Record record = new Record(Integer.MAX_VALUE, Long.MAX_VALUE, Float.MAX_VALUE, null, "foobar",
Bytes.toBytes("foobar"), ByteBuffer.wrap(Bytes.toBytes("foobar")), UUID.randomUUID());
records.write("123", record);
Record actual = records.read("123");
Assert.assertEquals(record, actual);
record = new Record(Integer.MAX_VALUE, Long.MAX_VALUE, null, Double.MAX_VALUE, "foobar",
Bytes.toBytes("foobar"), ByteBuffer.wrap(Bytes.toBytes("foobar")), UUID.randomUUID());
records.write("123", record);
actual = records.read("123");
Assert.assertEquals(record, actual);
records.delete("123");
Assert.assertNull(records.read("123"));
} finally {
dsFrameworkUtil.deleteInstance(RECORDS_ID);
}
}
@Test
public void testScan() throws Exception {
dsFrameworkUtil.createInstance(ObjectMappedTable.class.getName(), RECORDS_ID,
ObjectMappedTableProperties.builder().setType(Record.class).build());
try {
ObjectMappedTableDataset<Record> records = dsFrameworkUtil.getInstance(RECORDS_ID);
Record record1 = new Record(Integer.MAX_VALUE, Long.MAX_VALUE, Float.MAX_VALUE, Double.MAX_VALUE, "foobar",
Bytes.toBytes("foobar"), ByteBuffer.wrap(Bytes.toBytes("foobar")), UUID.randomUUID());
Record record2 = new Record(Integer.MIN_VALUE, Long.MIN_VALUE, Float.MIN_VALUE, Double.MIN_VALUE, "baz",
Bytes.toBytes("baz"), ByteBuffer.wrap(Bytes.toBytes("baz")), UUID.randomUUID());
Record record3 = new Record(1, 0L, 3.14f, 3.14159265358979323846, "hello",
Bytes.toBytes("world"), ByteBuffer.wrap(Bytes.toBytes("yo")), UUID.randomUUID());
List<KeyValue<byte[], Record>> recordList = Lists.newArrayList();
recordList.add(new KeyValue<>(Bytes.toBytes("123"), record1));
recordList.add(new KeyValue<>(Bytes.toBytes("456"), record2));
recordList.add(new KeyValue<>(Bytes.toBytes("789"), record3));
for (KeyValue<byte[], Record> record : recordList) {
records.write(record.getKey(), record.getValue());
}
List<KeyValue<byte[], Record>> actualList = Lists.newArrayList();
CloseableIterator<KeyValue<byte[], Record>> results = records.scan((String) null, null);
while (results.hasNext()) {
actualList.add(results.next());
}
results.close();
Assert.assertEquals(recordList.size(), actualList.size());
for (int i = 0; i < actualList.size(); i++) {
KeyValue<byte[], Record> expected = recordList.get(i);
KeyValue<byte[], Record> actual = actualList.get(i);
Assert.assertArrayEquals(expected.getKey(), actual.getKey());
Assert.assertEquals(expected.getValue(), actual.getValue());
}
results = records.scan("789", null);
KeyValue<byte[], Record> actualRecord = results.next();
Assert.assertFalse(results.hasNext());
Assert.assertArrayEquals(actualRecord.getKey(), recordList.get(2).getKey());
Assert.assertEquals(actualRecord.getValue(), recordList.get(2).getValue());
results.close();
results = records.scan(null, "124");
actualRecord = results.next();
Assert.assertFalse(results.hasNext());
Assert.assertArrayEquals(actualRecord.getKey(), recordList.get(0).getKey());
Assert.assertEquals(actualRecord.getValue(), recordList.get(0).getValue());
results.close();
results = records.scan(null, "123");
Assert.assertFalse(results.hasNext());
results.close();
} finally {
dsFrameworkUtil.deleteInstance(RECORDS_ID);
}
}
@Test
public void testGetSplits() throws Exception {
dsFrameworkUtil.createInstance(ObjectMappedTable.class.getName(), RECORDS_ID,
ObjectMappedTableProperties.builder().setType(Record.class).build());
try {
ObjectMappedTableDataset<Record> records = dsFrameworkUtil.getInstance(RECORDS_ID);
Record record = new Record(Integer.MAX_VALUE, Long.MAX_VALUE, Float.MAX_VALUE, Double.MAX_VALUE, "foobar",
Bytes.toBytes("foobar"), ByteBuffer.wrap(Bytes.toBytes("foobar")), UUID.randomUUID());
byte[] rowkey = Bytes.toBytes("row1");
records.write(rowkey, record);
// should not include the record, since upper bound is not inclusive
List<Split> splits = records.getSplits(1, null, rowkey);
List<Record> recordsRead = new ArrayList<>();
for (Split split : splits) {
SplitReader<byte[], Record> splitReader = records.createSplitReader(split);
try {
splitReader.initialize(split);
while (splitReader.nextKeyValue()) {
recordsRead.add(splitReader.getCurrentValue());
}
} finally {
splitReader.close();
}
}
Assert.assertEquals(0, recordsRead.size());
// should include the record, since lower bound is inclusive
splits = records.getSplits(1, rowkey, null);
recordsRead.clear();
for (Split split : splits) {
SplitReader<byte[], Record> splitReader = records.createSplitReader(split);
try {
splitReader.initialize(split);
while (splitReader.nextKeyValue()) {
recordsRead.add(splitReader.getCurrentValue());
}
} finally {
splitReader.close();
}
}
Assert.assertEquals(1, recordsRead.size());
Assert.assertEquals(record, recordsRead.get(0));
} finally {
dsFrameworkUtil.deleteInstance(RECORDS_ID);
}
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidTypeFails() throws Exception {
dsFrameworkUtil.createInstance(ObjectMappedTable.class.getName(),
Id.DatasetInstance.from(DatasetFrameworkTestUtil.NAMESPACE_ID, "custom"),
ObjectMappedTableProperties.builder().setType(Custom.class).build());
}
@Test(expected = IllegalArgumentException.class)
public void testRowKeyConflict() throws Exception {
dsFrameworkUtil.createInstance(ObjectMappedTable.class.getName(),
Id.DatasetInstance.from(DatasetFrameworkTestUtil.NAMESPACE_ID, "record"),
ObjectMappedTableProperties.builder()
.setType(Record.class)
.setRowKeyExploreName("intfield")
.build());
}
}