/**
* (c) Copyright 2012 WibiData, Inc.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* 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.kiji.mapreduce.kvstore.lib;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.kiji.schema.util.ResourceUtils.closeOrLog;
import static org.kiji.schema.util.ResourceUtils.releaseOrLog;
import java.io.IOException;
import org.apache.avro.Schema;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ReflectionUtils;
import org.junit.Before;
import org.junit.Test;
import org.kiji.mapreduce.kvstore.KeyValueStoreReader;
import org.kiji.mapreduce.kvstore.framework.KeyValueStoreConfiguration;
import org.kiji.mapreduce.kvstore.impl.KeyValueStoreConfigSerializer;
import org.kiji.schema.KijiClientTest;
import org.kiji.schema.KijiRowKeyComponents;
import org.kiji.schema.KijiTable;
import org.kiji.schema.KijiTableWriter;
import org.kiji.schema.KijiURI;
import org.kiji.schema.layout.KijiTableLayouts;
public class TestKijiTableKeyValueStore extends KijiClientTest {
@Before
public void setupEnvironment() throws Exception {
getKiji().createTable(KijiTableLayouts.getLayout(KijiTableLayouts.SIMPLE));
}
/** @return an uninitialized store to test for initialization from a Configuration. */
@SuppressWarnings("unchecked")
private <T> KijiTableKeyValueStore<T> getUninitializedStore() {
return (KijiTableKeyValueStore<T>) ReflectionUtils.newInstance(
KijiTableKeyValueStore.class, new Configuration());
}
@Test
public void testSerialization() throws IOException {
// Test that we can serialize a KijiTableKeyValueStore to a conf and resurrect it.
KijiTableKeyValueStore<String> input = KijiTableKeyValueStore.builder()
.withTable(KijiURI.newBuilder(getKiji().getURI().toString() + "/table").build())
.withColumn("some", "column")
.withMinTimestamp(42)
.withMaxTimestamp(512)
.withCacheLimit(2121)
.withReaderSchema(Schema.create(Schema.Type.STRING))
.build();
KeyValueStoreConfiguration conf = KeyValueStoreConfiguration.fromConf(new Configuration());
input.storeToConf(conf);
conf.getDelegate().set(KeyValueStoreConfiguration.KEY_VALUE_STORE_NAMESPACE
+ ".0." + KeyValueStoreConfigSerializer.CONF_NAME, "the-store-name");
KijiTableKeyValueStore<String> output = getUninitializedStore();
output.initFromConf(conf);
assertEquals(input, output);
}
@Test
public void testOkWithoutSchema() throws IOException {
// Serializing without an explicit reader schema is ok.
KijiTableKeyValueStore<String> input = KijiTableKeyValueStore.builder()
.withTable(KijiURI.newBuilder(getKiji().getURI().toString() + "/table").build())
.withColumn("some", "column")
.withMinTimestamp(42)
.withMaxTimestamp(512)
.withCacheLimit(2121)
.build();
KeyValueStoreConfiguration conf = KeyValueStoreConfiguration.fromConf(
new Configuration(false));
input.storeToConf(conf);
conf.getDelegate().set(KeyValueStoreConfiguration.KEY_VALUE_STORE_NAMESPACE
+ ".0." + KeyValueStoreConfigSerializer.CONF_NAME, "the-store-name");
KijiTableKeyValueStore<String> output = getUninitializedStore();
output.initFromConf(conf);
assertEquals(input, output);
}
@Test
public void testRequiresRealTable() throws IOException {
final KijiURI tableURI =
KijiURI.newBuilder(getKiji().getURI().toString() + "/table_name_not_real").build();
try {
// The specified table must exist in the Kiji instance.
KijiTableKeyValueStore<String> input = KijiTableKeyValueStore.builder()
.withTable(tableURI)
.withColumn("some", "column")
.withMinTimestamp(42)
.withMaxTimestamp(512)
.withCacheLimit(2121)
.build();
fail("Should have thrown an IllegalArgumentException.");
} catch (IllegalArgumentException iae) {
assertEquals("Could not open table: " + tableURI, iae.getMessage());
}
}
@Test
public void testRequiresTableUri() {
try {
// Test that we need to set the table URI, or it will fail to verify as input.
KijiTableKeyValueStore<String> input = KijiTableKeyValueStore.builder()
.withColumn("some", "column")
.withMinTimestamp(42)
.withMaxTimestamp(512)
.withCacheLimit(2121)
.build();
fail("Should have thrown an IllegalArgumentException.");
} catch (IllegalArgumentException iae) {
assertEquals("Must specify non-null table URI", iae.getMessage());
}
}
@Test
public void testRequiresTableNameInUri() throws IOException {
try {
// Test that we need to set the table URI to have both an instance
// name and a table name, or it will fail to verify as input.
KijiTableKeyValueStore<String> input = KijiTableKeyValueStore.builder()
.withTable(getKiji().getURI())
.withColumn("some", "column")
.withMinTimestamp(42)
.withMaxTimestamp(512)
.withCacheLimit(2121)
.build();
fail("Should have thrown an IllegalArgumentException.");
} catch (IllegalArgumentException iae) {
assertEquals("Must specify a non-empty table name", iae.getMessage());
}
}
@Test
public void testRequiresColumn() throws IOException {
try {
// Test that we need to set the column to read.
KijiTableKeyValueStore<String> input = KijiTableKeyValueStore.builder()
.withTable(
KijiURI.newBuilder(getKiji().getURI().toString()).withTableName("table").build())
.withMinTimestamp(42)
.withMaxTimestamp(512)
.withCacheLimit(2121)
.build();
fail("Should have thrown an IllegalArgumentException.");
} catch (IllegalArgumentException iae) {
assertEquals("Must specify a fully-qualified column", iae.getMessage());
}
}
@Test
public void testSuccessfulReadingFromKVStore() throws IOException {
KijiTable table = getKiji().openTable("table");
try {
KijiRowKeyComponents rowKey = KijiRowKeyComponents.fromComponents("identifier");
String value = "value";
KijiTableWriter writer = table.openTableWriter();
try {
writer.put(rowKey.getEntityIdForTable(table), "family", "column", "value");
} finally {
closeOrLog(writer);
}
KijiTableKeyValueStore<CharSequence> input = KijiTableKeyValueStore.builder()
.withTable(KijiURI.newBuilder(getKiji().getURI().toString() + "/table").build())
.withColumn("family", "column")
.build();
KeyValueStoreReader<KijiRowKeyComponents, CharSequence> reader = input.open();
try {
assertTrue(reader.containsKey(rowKey));
assertEquals(value, reader.get(rowKey).toString());
assertFalse(reader.containsKey(KijiRowKeyComponents.fromComponents("missingIdentifier")));
} finally {
reader.close();
}
} finally {
releaseOrLog(table);
}
}
}