/* * #! * % * 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 de.hub.cs.dbis.lrb.util.Constants.l0; import static de.hub.cs.dbis.lrb.util.Constants.l1; import static de.hub.cs.dbis.lrb.util.Constants.l2; import static de.hub.cs.dbis.lrb.util.Constants.l4; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import org.junit.Assert; 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.PositionReport; import de.hub.cs.dbis.lrb.types.TollNotification; import de.hub.cs.dbis.lrb.types.internal.AccidentTuple; import de.hub.cs.dbis.lrb.types.internal.CountTuple; import de.hub.cs.dbis.lrb.types.internal.LavTuple; import de.hub.cs.dbis.lrb.util.Constants; /** * @author mjsax */ public class TollNotificationBoltTest { private final static Integer vid = new Integer(21); private final static Integer xway = new Integer(1); private final static Short d = Constants.EASTBOUND; // direction private final static Integer pos = new Integer(0); private final static Integer spd = new Integer(0); @SuppressWarnings("boxing") @Test public void testExecute() { Tuple tuple = mock(Tuple.class); OngoingStubbing<List<Object>> valueStub = when(tuple.getValues()); List<TollNotification> expectedNotifications = new ArrayList<TollNotification>(); List<TollNotification> expectedAssessments = new ArrayList<TollNotification>(); List<String> streamIdsToBeMocked = new LinkedList<String>(); short time; // test 1: empty highway -> no toll // entering highway time = (short)0; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l0, d, (short)5, pos)); expectedNotifications.add(new TollNotification(time, time, vid, -1, 0)); // same segment different lane time = (short)30; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)5, pos)); streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)59, xway, (short)6, d, 50)); // crossing segment same lane time = (short)60; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)6, pos)); expectedNotifications.add(new TollNotification(time, time, vid, -1, 0)); // crossing segment different lane time = (short)90; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l2, d, (short)7, pos)); expectedNotifications.add(new TollNotification(time, time, vid, -1, 0)); // crossing segment but exit highway time = (short)120; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l4, d, (short)8, pos)); // test 2: full and slow highway -> toll streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)179, xway, (short)10, d, 51)); // entering highway again time = (short)200; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l0, d, (short)10, pos)); expectedNotifications.add(new TollNotification(time, time, vid, -1, 2)); // same segment different lane time = (short)230; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)10, pos)); streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)239, xway, (short)11, d, 52)); streamIdsToBeMocked.add(TopologyControl.LAVS_STREAM_ID); valueStub = valueStub.thenReturn(new LavTuple((short)299, xway, (short)11, d, 39)); // accident already passed; no effect streamIdsToBeMocked.add(TopologyControl.ACCIDENTS_STREAM_ID); valueStub = valueStub.thenReturn(new AccidentTuple((short)239, xway, (short)10, d)); // accident too far downstream; no effect streamIdsToBeMocked.add(TopologyControl.ACCIDENTS_STREAM_ID); valueStub = valueStub.thenReturn(new AccidentTuple((short)239, xway, (short)16, d)); // crossing segment same lane time = (short)260; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)11, pos)); expectedNotifications.add(new TollNotification(time, time, vid, 39, 8)); expectedAssessments.add(new TollNotification((short)200, (short)200, vid, -1, 2)); // crossing segment but exit highway time = (short)290; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l4, d, (short)12, pos)); expectedAssessments.add(new TollNotification((short)260, (short)260, vid, 39, 8)); // test 2: full but fast highway -> no toll streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)359, xway, (short)20, d, 51)); streamIdsToBeMocked.add(TopologyControl.LAVS_STREAM_ID); valueStub = valueStub.thenReturn(new LavTuple((short)419, xway, (short)20, d, 40)); // entering highway again time = (short)400; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l0, d, (short)20, pos)); expectedNotifications.add(new TollNotification(time, time, vid, 40, 0)); // test 4: full and slow highway but accident (same segment) streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)479, xway, (short)30, d, 51)); // entering highway again (no accident yet -> toll) time = (short)500; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l0, d, (short)30, pos)); expectedNotifications.add(new TollNotification(time, time, vid, -1, 2)); // same segment different lane time = (short)530; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)30, pos)); streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)539, xway, (short)31, d, 52)); streamIdsToBeMocked.add(TopologyControl.LAVS_STREAM_ID); valueStub = valueStub.thenReturn(new LavTuple((short)599, xway, (short)31, d, 39)); streamIdsToBeMocked.add(TopologyControl.ACCIDENTS_STREAM_ID); valueStub = valueStub.thenReturn(new AccidentTuple((short)539, xway, (short)31, d)); // crossing segment same lane (accident same segment -> no toll) time = (short)560; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)31, pos)); expectedNotifications.add(new TollNotification(time, time, vid, 39, 0)); expectedAssessments.add(new TollNotification((short)500, (short)500, vid, -1, 2)); // crossing segment but exit highway time = (short)590; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l4, d, (short)32, pos)); // test 4: full and slow highway but accident (segment most far down stream) streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)599, xway, (short)30, d, 51)); // entering highway again (no accident yet -> toll) time = (short)600; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l0, d, (short)30, pos)); expectedNotifications.add(new TollNotification(time, time, vid, -1, 2)); // same segment different lane time = (short)630; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)30, pos)); streamIdsToBeMocked.add(TopologyControl.CAR_COUNTS_STREAM_ID); valueStub = valueStub.thenReturn(new CountTuple((short)659, xway, (short)31, d, 52)); streamIdsToBeMocked.add(TopologyControl.LAVS_STREAM_ID); valueStub = valueStub.thenReturn(new LavTuple((short)719, xway, (short)31, d, 39)); streamIdsToBeMocked.add(TopologyControl.ACCIDENTS_STREAM_ID); valueStub = valueStub.thenReturn(new AccidentTuple((short)659, xway, (short)35, d)); // crossing segment same lane (accident 4 segments down -> no toll) time = (short)660; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l1, d, (short)31, pos)); expectedNotifications.add(new TollNotification(time, time, vid, 39, 0)); expectedAssessments.add(new TollNotification((short)600, (short)600, vid, -1, 2)); // crossing segment but exit highway time = (short)690; streamIdsToBeMocked.add(TopologyControl.POSITION_REPORTS_STREAM_ID); valueStub = valueStub.thenReturn(new PositionReport(time, vid, spd, xway, l4, d, (short)32, pos)); valueStub.thenReturn(null); OngoingStubbing<String> streamStub = when(tuple.getSourceStreamId()); for(String streamId : streamIdsToBeMocked) { streamStub = streamStub.thenReturn(streamId); } streamStub.thenReturn(null); TollNotificationBolt bolt = new TollNotificationBolt(); TestOutputCollector collector = new TestOutputCollector(); bolt.prepare(null, null, new OutputCollector(collector)); for(int i = 0; i < streamIdsToBeMocked.size(); ++i) { bolt.execute(tuple); } Assert.assertEquals(2, collector.output.size()); Assert.assertEquals(expectedNotifications, collector.output.get(TopologyControl.TOLL_NOTIFICATIONS_STREAM_ID)); Assert.assertEquals(expectedAssessments, collector.output.get(TopologyControl.TOLL_ASSESSMENTS_STREAM_ID)); Assert.assertNull(collector.output.get(TimestampMerger.FLUSH_STREAM_ID)); Tuple flushTuple = mock(Tuple.class); when(flushTuple.getSourceStreamId()).thenReturn(TimestampMerger.FLUSH_STREAM_ID); bolt.execute(flushTuple); Assert.assertEquals(3, collector.output.size()); Assert.assertEquals(1, collector.output.get(TimestampMerger.FLUSH_STREAM_ID).size()); Assert.assertEquals(new Values((Object)null), collector.output.get(TimestampMerger.FLUSH_STREAM_ID).get(0)); } @Test public void testInputStreams() { TollNotificationBolt bolt = new TollNotificationBolt(); String[] streamIds = new String[] {TopologyControl.POSITION_REPORTS_STREAM_ID, TopologyControl.ACCIDENTS_STREAM_ID, TopologyControl.CAR_COUNTS_STREAM_ID, TopologyControl.LAVS_STREAM_ID, "invalidStreamId"}; Tuple tuple = mock(Tuple.class); OngoingStubbing<String> stub = when(tuple.getSourceStreamId()); for(int i = 0; i < streamIds.length; ++i) { stub = stub.thenReturn(streamIds[i]); } stub.thenReturn(null); // first 4 calls should throw due to invalid tuple, but no due to invalid stream id for(int i = 0; i < streamIds.length - 1; ++i) { try { bolt.execute(tuple); fail(); } catch(RuntimeException e) { if(e.getMessage().startsWith("Unknown input stream: '" + streamIds[i] + "' for tuple ")) { e.printStackTrace(); fail(); } } } // last call should throw due to invalid stream id try { bolt.execute(tuple); fail(); } catch(RuntimeException e) { if(!e.getMessage().startsWith("Unknown input stream: 'invalidStreamId' for tuple ")) { e.printStackTrace(); fail(); } } } @Test public void testDeclareOutputFields() { TollNotificationBolt bolt = new TollNotificationBolt(); TestDeclarer declarer = new TestDeclarer(); bolt.declareOutputFields(declarer); final int numberOfOutputStreams = 3; Assert.assertEquals(numberOfOutputStreams, declarer.streamIdBuffer.size()); Assert.assertEquals(numberOfOutputStreams, declarer.schemaBuffer.size()); Assert.assertEquals(numberOfOutputStreams, declarer.directBuffer.size()); Fields schema = new Fields(TopologyControl.TYPE_FIELD_NAME, TopologyControl.TIMESTAMP_FIELD_NAME, TopologyControl.EMIT_FIELD_NAME, TopologyControl.VEHICLE_ID_FIELD_NAME, TopologyControl.SPEED_FIELD_NAME, TopologyControl.TOLL_FIELD_NAME); HashMap<String, Fields> expectedStreams = new HashMap<String, Fields>(); expectedStreams.put(TopologyControl.TOLL_NOTIFICATIONS_STREAM_ID, schema); expectedStreams.put(TopologyControl.TOLL_ASSESSMENTS_STREAM_ID, schema); expectedStreams.put(TimestampMerger.FLUSH_STREAM_ID, new Fields("ts")); Assert.assertEquals(expectedStreams.keySet(), new HashSet<String>(declarer.streamIdBuffer)); for(int i = 0; i < numberOfOutputStreams; ++i) { Assert.assertEquals(expectedStreams.get(declarer.streamIdBuffer.get(i)).toList(), declarer.schemaBuffer .get(i).toList()); Assert.assertEquals(new Boolean(false), declarer.directBuffer.get(i)); } } }