/*
* #!
* %
* Copyright (C) 2014 - 2016 Humboldt-Universität zu Berlin
* %
* 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 de.hub.cs.dbis.aeolus.spouts;
import static org.mockito.Mockito.mock;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import backtype.storm.Config;
import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.utils.Utils;
import de.hub.cs.dbis.aeolus.testUtils.TestDeclarer;
import de.hub.cs.dbis.aeolus.testUtils.TestSpoutOutputCollector;
import de.hub.cs.dbis.aeolus.testUtils.TimestampComperator;
/**
* @author mjsax
*/
@RunWith(PowerMockRunner.class)
public class OrderedInputSpoutTest {
private long seed;
private Random r;
@Before
public void prepare() {
this.seed = System.currentTimeMillis();
this.r = new Random(this.seed);
System.out.println("Test seed: " + this.seed);
}
@Test
public void testDeclareOutputFields() {
List<Deque<String>> data = new LinkedList<Deque<String>>();
// test without explicit stream ID
AbstractOrderedInputSpout<?> spout = new TestOrderedInputSpout(data, this.r);
TestDeclarer declarer = new TestDeclarer();
spout.declareOutputFields(declarer);
Assert.assertEquals(1, declarer.directBuffer.size());
Assert.assertEquals(1, declarer.schemaBuffer.size());
Assert.assertEquals(1, declarer.streamIdBuffer.size());
Assert.assertFalse(declarer.directBuffer.get(0).booleanValue());
Assert.assertEquals(2, declarer.schemaBuffer.get(0).size());
Assert.assertEquals("ts", declarer.schemaBuffer.get(0).get(0));
Assert.assertEquals("rawTuple", declarer.schemaBuffer.get(0).get(1));
Assert.assertNull(declarer.streamIdBuffer.get(0));
// test with explicit stream ID
String streamID = "streamID";
spout = new TestOrderedInputSpout(data, this.r, streamID);
declarer = new TestDeclarer();
spout.declareOutputFields(declarer);
Assert.assertEquals(1, declarer.directBuffer.size());
Assert.assertEquals(1, declarer.schemaBuffer.size());
Assert.assertEquals(1, declarer.streamIdBuffer.size());
Assert.assertFalse(declarer.directBuffer.get(0).booleanValue());
Assert.assertEquals(2, declarer.schemaBuffer.get(0).size());
Assert.assertEquals("ts", declarer.schemaBuffer.get(0).get(0));
Assert.assertEquals("rawTuple", declarer.schemaBuffer.get(0).get(1));
Assert.assertEquals(streamID, declarer.streamIdBuffer.get(0));
}
@Test
public void testClosePartiton() {
Deque<String> partition1 = new LinkedList<String>();
partition1.add("0");
Deque<String> partition2 = new LinkedList<String>();
partition2.add("1");
@SuppressWarnings("unchecked")
List<Deque<String>> data = new LinkedList<Deque<String>>(Arrays.asList(partition1, partition2));
TestOrderedInputSpout spout = new TestOrderedInputSpout(data, this.r);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put(TestOrderedInputSpout.NUMBER_OF_PARTITIONS, new Integer(2));
spout.open(map, null, mock(SpoutOutputCollector.class));
spout.nextTuple();
Assert.assertEquals(0, spout.emitted.size());
spout.nextTuple();
Assert.assertEquals(1, spout.emitted.size());
int partition = ((Long)spout.emitted.keySet().iterator().next().get(0)).intValue();
spout.emitted.clear();
spout.nextTuple();
Assert.assertEquals(0, spout.emitted.size());
Assert.assertFalse(spout.closePartition(new Integer(1 - partition)));
Assert.assertTrue(spout.closePartition(new Integer(partition)));
spout.nextTuple();
Assert.assertEquals(1, spout.emitted.size());
spout.nextTuple();
Assert.assertEquals(0, spout.emitted.size());
Assert.assertTrue(spout.closePartition(new Integer(1 - partition)));
spout.nextTuple();
Assert.assertEquals(0, spout.emitted.size());
}
@Test
public void testSingleEmptyPartition() {
@SuppressWarnings("unchecked")
List<Deque<String>> data = new LinkedList<Deque<String>>(Arrays.asList(new LinkedList<String>()));
TestOrderedInputSpout spout = new TestOrderedInputSpout(data, this.r);
Config conf = new Config();
conf.put(TestOrderedInputSpout.NUMBER_OF_PARTITIONS, new Integer(1));
TestSpoutOutputCollector col = new TestSpoutOutputCollector();
spout.open(conf, mock(TopologyContext.class), new SpoutOutputCollector(col));
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
Assert.assertEquals(0, col.output.size());
}
@Test
public void testAllPartitionsEmpty() {
@SuppressWarnings("unchecked")
List<Deque<String>> data = new LinkedList<Deque<String>>(Arrays.asList(new LinkedList<String>(),
new LinkedList<String>(), new LinkedList<String>()));
TestOrderedInputSpout spout = new TestOrderedInputSpout(data, this.r);
Config conf = new Config();
conf.put(TestOrderedInputSpout.NUMBER_OF_PARTITIONS, new Integer(3));
TestSpoutOutputCollector col = new TestSpoutOutputCollector();
spout.open(conf, mock(TopologyContext.class), new SpoutOutputCollector(col));
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
Assert.assertEquals(0, col.output.size());
}
@Test
public void testSinglePartition() {
LinkedList<String> partition = new LinkedList<String>();
partition.add("1");
partition.add("2");
partition.add("3");
LinkedList<List<Object>> expectedResult = new LinkedList<List<Object>>();
expectedResult.add(Arrays.asList(new Object[] {new Long(1), new String("1")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(2), new String("2")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(3), new String("3")}));
@SuppressWarnings("unchecked")
List<Deque<String>> data = new LinkedList<Deque<String>>(Arrays.asList(partition));
TestOrderedInputSpout spout = new TestOrderedInputSpout(data, this.r);
Config conf = new Config();
conf.put(TestOrderedInputSpout.NUMBER_OF_PARTITIONS, new Integer(1));
TestSpoutOutputCollector col = new TestSpoutOutputCollector();
spout.open(conf, mock(TopologyContext.class), new SpoutOutputCollector(col));
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
Assert.assertEquals(1, col.output.size());
Assert.assertNotEquals(null, col.output.get(Utils.DEFAULT_STREAM_ID));
Assert.assertEquals(expectedResult, col.output.get(Utils.DEFAULT_STREAM_ID));
}
@Test
public void testMultiplePartitionsStrict() {
Deque<String> partition1 = new LinkedList<String>();
partition1.add("1");
partition1.add("2");
partition1.add("3");
Deque<String> partition2 = new LinkedList<String>();
partition2.add("1 ");
partition2.add("2 ");
partition2.add("3 ");
Deque<String> partition3 = new LinkedList<String>();
partition3.add(" 1");
partition3.add(" 2");
partition3.add(" 3");
LinkedList<List<Object>> expectedResult = new LinkedList<List<Object>>();
expectedResult.add(Arrays.asList(new Object[] {new Long(1), new String("1")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(1), new String("1 ")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(1), new String(" 1")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(2), new String("2 ")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(2), new String(" 2")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(2), new String("2")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(3), new String(" 3")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(3), new String("3")}));
expectedResult.add(Arrays.asList(new Object[] {new Long(3), new String("3 ")}));
Collections.sort(expectedResult, new TimestampComperator());
@SuppressWarnings("unchecked")
List<Deque<String>> data = new LinkedList<Deque<String>>(Arrays.asList(partition1, partition2, partition3));
TestOrderedInputSpout spout = new TestOrderedInputSpout(data, this.r);
Config conf = new Config();
conf.put(TestOrderedInputSpout.NUMBER_OF_PARTITIONS, new Integer(3));
TestSpoutOutputCollector col = new TestSpoutOutputCollector();
spout.open(conf, mock(TopologyContext.class), new SpoutOutputCollector(col));
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
spout.nextTuple();
Assert.assertEquals(1, col.output.size());
Assert.assertNotEquals(null, col.output.get(Utils.DEFAULT_STREAM_ID));
Assert.assertEquals(9, col.output.get(Utils.DEFAULT_STREAM_ID).size());
for(int i = 0; i < 3; ++i) {
Set<List<Object>> expectedSubset = new HashSet<List<Object>>();
Set<List<Object>> resultSubset = new HashSet<List<Object>>();
for(int j = 0; j < 3; ++j) {
expectedSubset.add(expectedResult.removeFirst());
resultSubset.add(col.output.get(Utils.DEFAULT_STREAM_ID).removeFirst());
}
Assert.assertEquals(expectedSubset, resultSubset);
}
}
@Test
public void testMultiplePartitionsRandom() {
LinkedList<List<Object>> expectedResult = new LinkedList<List<Object>>();
int size, number, totalInputSize = 0;
final int stepSizeRange = 1 + this.r.nextInt(6);
size = 20 + this.r.nextInt(200);
totalInputSize += size;
Deque<String> partition1 = new LinkedList<String>();
number = 0;
for(int i = 0; i < size; ++i) {
number += this.r.nextInt(stepSizeRange);
partition1.add("" + number);
expectedResult.add(Arrays.asList(new Object[] {new Long(number), new String("" + number)}));
}
size = 20 + this.r.nextInt(200);
totalInputSize += size;
Deque<String> partition2 = new LinkedList<String>();
number = 0;
for(int i = 0; i < size; ++i) {
number += this.r.nextInt(stepSizeRange);
partition2.add(" " + number);
expectedResult.add(Arrays.asList(new Object[] {new Long(number), new String(" " + number)}));
}
size = 20 + this.r.nextInt(200);
totalInputSize += size;
Deque<String> partition3 = new LinkedList<String>();
number = 0;
for(int i = 0; i < size; ++i) {
number += this.r.nextInt(stepSizeRange);
partition3.add(number + " ");
expectedResult.add(Arrays.asList(new Object[] {new Long(number), new String(number + " ")}));
}
Collections.sort(expectedResult, new TimestampComperator());
@SuppressWarnings("unchecked")
List<Deque<String>> data = new LinkedList<Deque<String>>(Arrays.asList(partition1, partition2, partition3));
TestOrderedInputSpout spout = new TestOrderedInputSpout(data, this.r);
Config conf = new Config();
conf.put(TestOrderedInputSpout.NUMBER_OF_PARTITIONS, new Integer(3));
TestSpoutOutputCollector col = new TestSpoutOutputCollector();
spout.open(conf, mock(TopologyContext.class), new SpoutOutputCollector(col));
final int numberOfNextTupleCalls = (int)(0.8 * totalInputSize) + this.r.nextInt((int)(0.4 * totalInputSize));
for(int i = 0; i < numberOfNextTupleCalls; ++i) {
spout.nextTuple();
}
Assert.assertEquals(1, col.output.size());
Assert.assertNotEquals(null, col.output.get(Utils.DEFAULT_STREAM_ID));
System.out.println(expectedResult);
System.out.println(col.output.get(Utils.DEFAULT_STREAM_ID));
List<Object> lastRemoved = null;
while(expectedResult.size() > col.output.get(Utils.DEFAULT_STREAM_ID).size()) {
lastRemoved = expectedResult.removeLast();
}
if(lastRemoved != null) {
while(expectedResult.size() > 0
&& ((Long)lastRemoved.get(0)).longValue() == ((Long)expectedResult.getLast().get(0)).longValue()) {
expectedResult.removeLast();
}
}
while(expectedResult.size() > 0) {
Set<List<Object>> expectedSubset = new HashSet<List<Object>>();
Set<List<Object>> resultSubset = new HashSet<List<Object>>();
List<Object> first;
do {
first = expectedResult.removeFirst();
expectedSubset.add(first);
resultSubset.add(col.output.get(Utils.DEFAULT_STREAM_ID).removeFirst());
if(expectedResult.size() == 0) {
break;
}
} while(((Long)expectedResult.getFirst().get(0)).longValue() == ((Long)first.get(0)).longValue());
Assert.assertEquals(expectedSubset, resultSubset);
}
}
}