/**
* (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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import com.google.common.base.Preconditions;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.NullWritable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.kiji.mapreduce.framework.HFileKeyValue;
import org.kiji.mapreduce.impl.DirectKijiTableWriterContext;
import org.kiji.mapreduce.input.KijiTableMapReduceJobInput.RowOptions;
import org.kiji.mapreduce.input.MapReduceJobInputs;
import org.kiji.mapreduce.output.MapReduceJobOutputs;
import org.kiji.schema.EntityId;
import org.kiji.schema.Kiji;
import org.kiji.schema.KijiDataRequest;
import org.kiji.schema.KijiRowData;
import org.kiji.schema.KijiRowScanner;
import org.kiji.schema.KijiTable;
import org.kiji.schema.KijiTableReader;
import org.kiji.schema.layout.KijiTableLayout;
import org.kiji.schema.util.InstanceBuilder;
import org.kiji.schema.util.ResourceUtils;
/** Runs a map-only job in-process against a fake HBase instance. */
public class TestLaunchMapReduce {
private static final Logger LOG = LoggerFactory.getLogger(TestLaunchMapReduce.class);
/**
* Example mapper intended to run on the generic KijiMR test layout. This test uses the resource
* org/kiji/mapreduce/layout/test.json
*/
public static class ExampleMapper
extends KijiMapper<EntityId, KijiRowData, HFileKeyValue, NullWritable> {
private KijiTableContext mTableContext;
/** {@inheritDoc} */
@Override
protected void setup(Context context)
throws IOException, InterruptedException {
super.setup(context);
Preconditions.checkState(mTableContext == null);
mTableContext = DirectKijiTableWriterContext.create(context);
}
/** {@inheritDoc} */
@Override
protected void map(EntityId eid, KijiRowData row, Context hadoopContext)
throws IOException, InterruptedException {
Preconditions.checkNotNull(mTableContext);
final String userId = Bytes.toString((byte[]) eid.getComponentByIndex(0));
final EntityId genEId = mTableContext.getEntityId("generated row for " + userId);
mTableContext.put(genEId, "primitives", "string", "generated content for " + userId);
}
/** {@inheritDoc} */
@Override
protected void cleanup(Context context)
throws IOException, InterruptedException {
Preconditions.checkNotNull(mTableContext);
mTableContext.close();
mTableContext = null;
super.cleanup(context);
}
/** {@inheritDoc} */
@Override
public Class<?> getOutputKeyClass() {
return HFileKeyValue.class;
}
/** {@inheritDoc} */
@Override
public Class<?> getOutputValueClass() {
return NullWritable.class;
}
}
private Kiji mKiji;
private KijiTable mTable;
private KijiTableReader mReader;
@Before
public void setUp() throws Exception {
// Get the test table layouts.
final KijiTableLayout layout =
KijiTableLayout.newLayout(KijiMRTestLayouts.getTestLayout());
// Populate the environment.
mKiji = new InstanceBuilder()
.withTable("test", layout)
.withRow("Marsellus Wallace")
.withFamily("info")
.withQualifier("first_name").withValue("Marsellus")
.withQualifier("last_name").withValue("Wallace")
.withRow("Vincent Vega")
.withFamily("info")
.withQualifier("first_name").withValue("Vincent")
.withQualifier("last_name").withValue("Vega")
.build();
// Fill local variables.
mTable = mKiji.openTable("test");
mReader = mTable.openTableReader();
}
@After
public void tearDown() throws Exception {
ResourceUtils.closeOrLog(mReader);
ResourceUtils.releaseOrLog(mTable);
ResourceUtils.releaseOrLog(mKiji);
}
@Test
public void testMapReduce() throws Exception {
final Configuration jobConf = new Configuration();
jobConf.set("mapreduce.jobtracker.address", "local");
final String tmpDir = "file:///tmp/hdfs-testing-" + System.nanoTime();
jobConf.set("fs.default.name", tmpDir);
jobConf.set("fs.default.FS", tmpDir);
// Run the transform (map-only job):
final KijiMapReduceJob job = KijiMapReduceJobBuilder.create()
.withConf(jobConf)
.withMapper(ExampleMapper.class)
.withInput(MapReduceJobInputs.newKijiTableMapReduceJobInput(
mTable.getURI(), KijiDataRequest.create("info"), RowOptions.create()))
.withOutput(MapReduceJobOutputs.newDirectKijiTableMapReduceJobOutput(mTable.getURI()))
.build();
assertTrue(job.run());
// Validate the output table content:
{
final KijiRowScanner scanner = mTable.openTableReader().getScanner(
KijiDataRequest.create("info"));
for (KijiRowData row : scanner) {
final EntityId eid = row.getEntityId();
final String userId = Bytes.toString((byte[]) eid.getComponentByIndex(0));
LOG.info("Row: {}", userId);
if (!userId.startsWith("generated row for ")) {
assertEquals(userId, String.format("%s %s",
row.getMostRecentValue("info", "first_name"),
row.getMostRecentValue("info", "last_name")));
}
}
scanner.close();
}
}
}