/* * #! * % * 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.lrb.operators; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.stubbing.OngoingStubbing; import backtype.storm.task.OutputCollector; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import de.hub.cs.dbis.aeolus.testUtils.TestDeclarer; import de.hub.cs.dbis.aeolus.testUtils.TestOutputCollector; import de.hub.cs.dbis.aeolus.utils.TimestampMerger; import de.hub.cs.dbis.lrb.queries.utils.TopologyControl; import de.hub.cs.dbis.lrb.types.internal.AvgSpeedTuple; import de.hub.cs.dbis.lrb.types.internal.LavTuple; import de.hub.cs.dbis.lrb.types.util.SegmentIdentifier; import de.hub.cs.dbis.lrb.util.Constants; /** * @author richter * @author mjsax */ public class LastAverageVelocityBoltTest { 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 testExecute() { LatestAverageVelocityBolt instance = new LatestAverageVelocityBolt(); TestOutputCollector collector = new TestOutputCollector(); instance.prepare(null, null, new OutputCollector(collector)); final short numberOfMinutes = 10; final int numberOfHighways = 1 + this.r.nextInt(3); final int numberOfSegments = 1 + this.r.nextInt(5); final Map<SegmentIdentifier, List<Double>> allSpeedsPerSegments = new HashMap<SegmentIdentifier, List<Double>>(); final List<SegmentIdentifier> allSegments = new LinkedList<SegmentIdentifier>(); final List<SegmentIdentifier> skippedSegments = new LinkedList<SegmentIdentifier>(); Tuple tuple = mock(Tuple.class); when(tuple.getSourceStreamId()).thenReturn("streamId"); OngoingStubbing<List<Object>> tupleStub = when(tuple.getValues()); for(short minute = 1; minute <= numberOfMinutes; ++minute) { List<AvgSpeedTuple> input = new LinkedList<AvgSpeedTuple>(); for(int xway = 1; xway <= numberOfHighways; ++xway) { for(short segment = 1; segment <= numberOfSegments; ++segment) { // randomly skip some AvgSpeedTuple if(this.r.nextDouble() < 0.5 / numberOfSegments) { input.add(null); skippedSegments.add(new SegmentIdentifier(new Integer(xway), new Short(segment), Constants.EASTBOUND)); continue; } int avgSpeed = 1 + this.r.nextInt(Constants.MAX_SPEED); input.add(new AvgSpeedTuple(new Short(minute), new Integer(xway), new Short(segment), Constants.EASTBOUND, new Double(avgSpeed))); } } Collections.shuffle(input, this.r); for(AvgSpeedTuple t : input) { SegmentIdentifier sid; if(t != null) { sid = new SegmentIdentifier(t); } else { sid = skippedSegments.remove(0); } allSegments.add(sid); List<Double> speeds = allSpeedsPerSegments.get(sid); if(speeds == null) { speeds = new LinkedList<Double>(); allSpeedsPerSegments.put(sid, speeds); } if(t != null) { speeds.add(t.getAvgSpeed()); tupleStub = tupleStub.thenReturn(t); } else { speeds.add(null); } } } int executeCounter = 0; int lastMinute = 0; LinkedList<Values> expectedFlushs = null; for(short minute = 1; minute <= numberOfMinutes; ++minute) { boolean firstTupleOfMinute = true; boolean flushed = false; for(int i = 0; i < numberOfHighways * numberOfSegments; ++i) { SegmentIdentifier sid = allSegments.remove(0); List<Double> speeds = allSpeedsPerSegments.get(sid); if(speeds.get(minute - 1) == null) { continue; } instance.execute(tuple); ++executeCounter; if(!flushed) { if(expectedFlushs == null) { expectedFlushs = new LinkedList<Values>(); } expectedFlushs.add(new Values(new Short((short)((minute * 60) - 1)))); flushed = true; } List<LavTuple> expectedResult = new LinkedList<LavTuple>(); if(firstTupleOfMinute && minute > 1) { // process open (incomplete windows) for(int m = minute - 5; m < minute - 1; ++m) { if(m < 0 || m <= lastMinute) { continue; } lastMinute = m; for(Entry<SegmentIdentifier, List<Double>> e : allSpeedsPerSegments.entrySet()) { List<Double> speedList = e.getValue(); if(speedList.get(m) == null) { this.addResult(speedList, (short)(m + 1), expectedResult, e.getKey()); } } } } this.addResult(speeds, minute, expectedResult, sid); assertEquals(2, collector.output.size()); assertEquals(executeCounter, collector.acked.size()); assertEquals(expectedFlushs, collector.output.get(TimestampMerger.FLUSH_STREAM_ID)); List<List<Object>> result = collector.output.get(TopologyControl.LAVS_STREAM_ID); HashSet<List<Object>> ers = new HashSet<List<Object>>(); HashSet<List<Object>> rs = new HashSet<List<Object>>(); while(expectedResult.size() > 0) { LavTuple t = expectedResult.remove(0); ers.add(t); rs.add(result.remove(0)); while(expectedResult.size() > 0) { LavTuple t2 = expectedResult.get(0); if(t2.getMinuteNumber() == t.getMinuteNumber()) { ers.add(expectedResult.remove(0)); rs.add(result.remove(0)); } else { break; } } } assertEquals(ers, rs); assertEquals(0, result.size()); firstTupleOfMinute = false; } assertEquals(expectedFlushs, collector.output.get(TimestampMerger.FLUSH_STREAM_ID)); } Tuple flushTuple = mock(Tuple.class); when(flushTuple.getSourceStreamId()).thenReturn(TimestampMerger.FLUSH_STREAM_ID); instance.execute(flushTuple); ++executeCounter; short minute = numberOfMinutes + 1; List<LavTuple> expectedResult = new LinkedList<LavTuple>(); for(int m = minute - 5; m < minute - 1; ++m) { if(m < 0 || m <= lastMinute) { continue; } lastMinute = m; boolean lastMinuteEmpty = true; for(Entry<SegmentIdentifier, List<Double>> e : allSpeedsPerSegments.entrySet()) { List<Double> speedList = e.getValue(); if(speedList.get(m) == null) { this.addResult(speedList, (short)(m + 1), expectedResult, e.getKey()); } else { lastMinuteEmpty = false; } } if(lastMinuteEmpty) { for(int i = 0; i < numberOfHighways; ++i) { expectedResult.remove(expectedResult.size() - 1); } } } List<List<Object>> result = collector.output.get(TopologyControl.LAVS_STREAM_ID); HashSet<List<Object>> ers = new HashSet<List<Object>>(); HashSet<List<Object>> rs = new HashSet<List<Object>>(); while(expectedResult.size() > 0) { LavTuple t = expectedResult.remove(0); ers.add(t); rs.add(result.remove(0)); while(expectedResult.size() > 0) { LavTuple t2 = expectedResult.get(0); if(t2.getMinuteNumber() == t.getMinuteNumber()) { ers.add(expectedResult.remove(0)); rs.add(result.remove(0)); } else { break; } } } if(expectedFlushs == null) { expectedFlushs = new LinkedList<Values>(); } expectedFlushs.add(new Values((Object)null)); assertEquals(ers, rs); assertEquals(0, result.size()); assertEquals(executeCounter, collector.acked.size()); assertEquals(2, collector.output.size()); assertEquals(expectedFlushs, collector.output.get(TimestampMerger.FLUSH_STREAM_ID)); } private void addResult(List<Double> speeds, short minute, List<LavTuple> expectedResult, SegmentIdentifier sid) { double sum = 0; int cnt = 0; List<Double> window = speeds.subList(minute > 5 ? minute - 5 : 0, minute); for(Double avgs : window) { if(avgs == null) { continue; } sum += avgs.intValue(); ++cnt; } if(cnt == 0) { return; } expectedResult.add(new LavTuple(new Short((short)(((minute + 1) * 60) - 1)), sid.getXWay(), sid.getSegment(), sid.getDirection(), new Integer((int)(sum / cnt)))); } @Test public void testDeclareOutputFields() { LatestAverageVelocityBolt bolt = new LatestAverageVelocityBolt(); TestDeclarer declarer = new TestDeclarer(); bolt.declareOutputFields(declarer); Assert.assertEquals(2, declarer.streamIdBuffer.size()); Assert.assertEquals(2, declarer.schemaBuffer.size()); Assert.assertEquals(2, declarer.directBuffer.size()); Assert.assertEquals(TopologyControl.LAVS_STREAM_ID, declarer.streamIdBuffer.get(0)); Assert.assertEquals(new Fields(TopologyControl.MINUTE_FIELD_NAME, TopologyControl.XWAY_FIELD_NAME, TopologyControl.SEGMENT_FIELD_NAME, TopologyControl.DIRECTION_FIELD_NAME, TopologyControl.LAST_AVERAGE_SPEED_FIELD_NAME).toList(), declarer.schemaBuffer.get(0).toList()); Assert.assertEquals(new Boolean(false), declarer.directBuffer.get(0)); Assert.assertEquals(TimestampMerger.FLUSH_STREAM_ID, declarer.streamIdBuffer.get(1)); Assert.assertEquals(new Fields("ts").toList(), declarer.schemaBuffer.get(1).toList()); Assert.assertEquals(new Boolean(false), declarer.directBuffer.get(1)); } }