/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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 com.asakusafw.runtime.mapreduce.simple;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.serializer.SerializationFactory;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.junit.rules.TemporaryFolder;
import com.asakusafw.runtime.io.util.DataBuffer;
import com.asakusafw.runtime.util.hadoop.ConfigurationProvider;
import com.asakusafw.utils.io.Source;
/**
* Test class for {@link KeyValueSorter}.
*/
public class KeyValueSorterTest {
/**
* The temporary folder.
*/
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
final LinkedList<Object> resources = new LinkedList<>();
/**
* Closer.
*/
@Rule
public final ExternalResource closer = new ExternalResource() {
@Override
protected void after() {
for (Object resource : resources) {
if (resource instanceof Closeable) {
try {
((Closeable) resource).close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
KeyValueSorter<IntWritable, Text> sorter;
final IntWritable keyWritable = new IntWritable();
final Text valueWritable = new Text();
/**
* simple case.
* @throws Exception if failed
*/
@Test
public void simple() throws Exception {
put(100);
put(300);
put(200);
put(400);
Source<IntWritable> results = sort();
check(results, 100);
check(results, 200);
check(results, 300);
check(results, 400);
assertThat(results.next(), is(false));
}
/**
* middle.
* @throws Exception if failed
*/
@Test
public void middle() throws Exception {
int count = 2000;
for (int i = 0; i < count; i++) {
put(100);
put(300);
put(200);
put(400);
}
Source<IntWritable> results = sort();
for (int value : new int[] { 100, 200, 300, 400 }) {
for (int i = 0; i < count; i++) {
check(results, value);
}
}
assertThat(results.next(), is(false));
}
/**
* large case.
* @throws Exception if failed
*/
@Test
public void large() throws Exception {
int count = 10000;
for (int i = 0; i < count; i++) {
put(100);
put(300);
put(200);
put(400);
}
Source<IntWritable> results = sort();
for (int value : new int[] { 100, 200, 300, 400 }) {
for (int i = 0; i < count; i++) {
check(results, value);
}
}
assertThat(results.next(), is(false));
}
/**
* extra-large case.
* @throws Exception if failed
*/
@Test
public void xlarge() throws Exception {
int count = 100000;
for (int i = 0; i < count; i++) {
put(100);
put(300);
put(200);
put(400);
}
Source<IntWritable> results = sort();
for (int value : new int[] { 100, 200, 300, 400 }) {
for (int i = 0; i < count; i++) {
check(results, value);
}
}
assertThat(results.next(), is(false));
}
private void check(Source<IntWritable> results, int expected) throws IOException, InterruptedException {
assertTrue(results.next());
assertEquals(expected, results.get().get());
}
private void put(int value) throws IOException, InterruptedException {
keyWritable.set(value);
valueWritable.set(String.valueOf(value));
sorter().put(keyWritable, valueWritable);
}
private Source<IntWritable> sort() throws IOException, InterruptedException {
return manage(new DeserSource(sorter().sort()));
}
private KeyValueSorter<IntWritable, Text> sorter() throws IOException {
if (sorter == null) {
sorter = manage(new KeyValueSorter<>(
new SerializationFactory(new ConfigurationProvider().newInstance()),
IntWritable.class,
Text.class,
new IntWritable.Comparator(),
new KeyValueSorter.Options()
.withBufferSize(0)
.withTemporaryDirectory(temporaryFolder.newFolder())));
}
return sorter;
}
private <T> T manage(T object) {
resources.addFirst(object);
return object;
}
private static final class DeserSource implements Source<IntWritable> {
private final Source<KeyValueSlice> origin;
private final IntWritable writable = new IntWritable();
private final Text text = new Text();
private final DataBuffer buffer = new DataBuffer();
public DeserSource(Source<KeyValueSlice> origin) {
this.origin = origin;
}
@Override
public boolean next() throws IOException, InterruptedException {
if (origin.next() == false) {
return false;
}
KeyValueSlice slice = origin.get();
buffer.reset(slice.getBytes(), slice.getKeyOffset(), slice.getKeyLength());
writable.readFields(buffer);
buffer.reset(slice.getBytes(), slice.getValueOffset(), slice.getValueLength());
text.readFields(buffer);
assertEquals(writable.get(), Integer.parseInt(text.toString()));
return true;
}
@Override
public IntWritable get() throws IOException, InterruptedException {
return writable;
}
@Override
public void close() throws IOException {
origin.close();
}
}
}