コード例 #1
0
    def setUp(self):
        self.logger = Mock()
        self.logger.error = Mock(side_effect=print_msg)
        self.servo = Mock()

        self.exchange = Exchange(self.logger)
        self.timer = StubTimer()
        TimeShift(self.exchange, self.timer.time)
コード例 #2
0
    def setUp(self):
        self.logger = Mock()
        self.logger.error = Mock(side_effect=print_msg)
        self.servo = Mock()

        self.exchange = Exchange(self.logger)
        self.timer = StubTimer()
        TimeShift(self.exchange,self.timer.time)
コード例 #3
0
class EventTestCase(unittest.TestCase):
    def setUp(self):
        self.last_event = Event("None")
        self.events = {}
        self.exchange = Exchange(test_logger(logging.ERROR))

    def event_recorder(self, event):
        self.last_event = event
        self.events[event.name].append(event)

    def listen(self, event_name):
        self.events[event_name] = []
        self.exchange.subscribe(event_name, self.event_recorder)

    def event_count(self, event_name):
        if event_name in self.events:
            return len(self.events[event_name])
        else:
            return 0
コード例 #4
0
ファイル: test_utils.py プロジェクト: andyrobinson/pi-nav
class EventTestCase(unittest.TestCase):

    def setUp(self):
        self.last_event = Event("None")
        self.events = {}
        self.exchange = Exchange(test_logger(logging.ERROR))

    def event_recorder(self,event):
        self.last_event = event
        self.events[event.name].append(event)

    def listen(self,event_name):
        self.events[event_name] = []
        self.exchange.subscribe(event_name,self.event_recorder)

    def event_count(self,event_name):
        if event_name in self.events:
            return len(self.events[event_name])
        else:
            return 0
コード例 #5
0
    def __init__(self, gps=False, servo_port=SERVO_PORT):
        # devices
        self._gps = gps
        self.windsensor = WindSensor(I2C(WINDSENSOR_I2C_ADDRESS))
        self.compass = Compass(I2C(COMPASS_I2C_ADDRESS),
                               I2C(ACCELEROMETER_I2C_ADDRESS))
        self.red_led = GpioWriter(17, os)
        self.green_led = GpioWriter(18, os)

        # Navigation
        self.globe = Globe()
        self.timer = Timer()
        self.application_logger = self._rotating_logger(APPLICATION_NAME)
        self.position_logger = self._rotating_logger("position")
        self.exchange = Exchange(self.application_logger)
        self.timeshift = TimeShift(self.exchange, self.timer.time)
        self.event_source = EventSource(self.exchange, self.timer,
                                        self.application_logger,
                                        CONFIG['event source'])

        self.sensors = Sensors(self.gps, self.windsensor, self.compass,
                               self.timer.time, self.exchange,
                               self.position_logger, CONFIG['sensors'])
        self.gps_console_writer = GpsConsoleWriter(self.gps)
        self.rudder_servo = Servo(serial.Serial(servo_port),
                                  RUDDER_SERVO_CHANNEL, RUDDER_MIN_PULSE,
                                  RUDDER_MIN_ANGLE, RUDDER_MAX_PULSE,
                                  RUDDER_MAX_ANGLE)
        self.steerer = Steerer(self.rudder_servo, self.application_logger,
                               CONFIG['steerer'])
        self.helm = Helm(self.exchange, self.sensors, self.steerer,
                         self.application_logger, CONFIG['helm'])
        self.course_steerer = CourseSteerer(self.sensors, self.helm,
                                            self.timer,
                                            CONFIG['course steerer'])
        self.navigator = Navigator(self.sensors, self.globe, self.exchange,
                                   self.application_logger,
                                   CONFIG['navigator'])
        self.self_test = SelfTest(self.red_led, self.green_led, self.timer,
                                  self.rudder_servo, RUDDER_MIN_ANGLE,
                                  RUDDER_MAX_ANGLE)

        # Tracking
        self.tracking_logger = self._rotating_logger("track")
        self.tracking_sensors = Sensors(self.gps, self.windsensor,
                                        self.compass, self.timer.time,
                                        self.exchange, self.tracking_logger,
                                        CONFIG['sensors'])
        self.tracker = Tracker(self.tracking_logger, self.tracking_sensors,
                               self.timer)
コード例 #6
0
    def __init__(self):
        self.globe = Globe()
        self.console_logger = self._console_logger()
        self.exchange = Exchange(self.console_logger)
        self.gps = SimulatedGPS(CHORLTON.position,0,0.1)
        self.vehicle = SimulatedVehicle(self.gps, self.globe,self.console_logger,single_step=False)
        self.timeshift = TimeShift(self.exchange,self.vehicle.timer.time)
        self.event_source = EventSource(self.exchange,self.vehicle.timer,self.console_logger,CONFIG['event source'])
        self.sensors = Sensors(self.vehicle.gps, self.vehicle.windsensor,self.vehicle.compass,self.vehicle.timer.time,self.exchange,self.console_logger,CONFIG['sensors'])
        self.steerer = Steerer(self.vehicle.rudder,self.console_logger,CONFIG['steerer'])
        self.helm = Helm(self.exchange, self.sensors, self.steerer, self.console_logger, CONFIG['helm'])
        self.course_steerer = CourseSteerer(self.sensors,self.helm,self.vehicle.timer, CONFIG['course steerer'])
        self.navigator_simulator = Navigator(self.sensors,self.globe,self.exchange,self.console_logger,CONFIG['navigator'])

        self.tracking_timer = Timer()
        self.tracker_simulator = Tracker(self.console_logger,self.sensors,self.tracking_timer)
コード例 #7
0
ファイル: test_events.py プロジェクト: andyrobinson/pi-nav
    def test_errors_during_logging_should_be_ignored_and_event_processing_continues(
            self):
        failing_logger = Mock()
        failing_logger.configure_mock(**{'error.side_effect': RuntimeError})

        exchange = Exchange(failing_logger)
        ts_error = TestSubscriber(exchange)
        ts_after_error = TestSubscriber(exchange)

        event = Event("bong")
        exchange.subscribe("bong", ts_error.bad_call)
        exchange.subscribe("bong", ts_after_error.callme)

        exchange.publish(event)

        failing_logger.error.assert_has_calls(
            [call('Exchange, RuntimeError: oops')])
        self.assertEqual(ts_after_error.event_call_count("bong"), 1)
コード例 #8
0
ファイル: test_events.py プロジェクト: andyrobinson/pi-nav
    def test_errors_during_logging_should_be_ignored_and_event_processing_continues(self):
        failing_logger = Mock()
        failing_logger.configure_mock(**{'error.side_effect': RuntimeError})

        exchange = Exchange(failing_logger)
        ts_error = TestSubscriber(exchange)
        ts_after_error = TestSubscriber(exchange)

        event = Event("bong")
        exchange.subscribe("bong",ts_error.bad_call)
        exchange.subscribe("bong",ts_after_error.callme)

        exchange.publish(event)

        failing_logger.error.assert_has_calls([call('Exchange, RuntimeError: oops')])
        self.assertEqual(ts_after_error.event_call_count("bong"),1)
コード例 #9
0
ファイル: test_follower.py プロジェクト: andyrobinson/pi-nav
 def setUp(self):
     self.mock_logger = Mock()
     self.mock_logger.error = Mock(side_effect=print_msg)
     self.exchange = Exchange(self.mock_logger)
     self.timer = StubTimer()
     self.timeshift = TimeShift(self.exchange, self.timer.time)
     self.event_source = EventSource(self.exchange, self.timer,
                                     self.mock_logger,
                                     {'tick interval': 0.2})
     gps = FakeMovingGPS([
         Position(10, 10),
         Position(11, 11),
         Position(12, 12),
         Position(13, 13)
     ])
     self.navigator = Navigator(gps, Globe(), self.exchange,
                                self.mock_logger, {
                                    'min time to steer': 5,
                                    'max time to steer': 20
                                })
コード例 #10
0
class TestEventSource(unittest.TestCase):

    def setUp(self):
        self.mock_logger = Mock()
        self.exchange = Exchange(self.mock_logger)
        self.timer = Mock()
        self.last_event = None

    def event_recorder(self,event):
        self.last_listened_event = event
        self.event_count += 1

    def intercept_publish(self,event):
        self.exchange.original_publish(event)
        if event.name == EventName.tick:
            raise RuntimeError("oops")

    def listen(self,event_name):
        self.event_count = 0
        self.exchange.subscribe(event_name,self.event_recorder)

    def after(self,times,event_name):
        self.ticks_left = times
        self.end_event_name = event_name

    def count_down_ticks(self,args):
        self.ticks_left -= 1
        if self.ticks_left <= 0:
            self.exchange.publish(Event(self.end_event_name))

    def finish(self,args):
        self.exchange.publish(Event(EventName.end))

    def test_should_publish_start_navigation_event(self):
        self.listen(EventName.start)
        self.timer.wait_for = Mock(side_effect=self.finish)

        event_source = EventSource(self.exchange,self.timer, self.mock_logger,CONFIG)
        event_source.start()

        self.assertEqual(self.last_listened_event.name,EventName.start)

    def test_should_publish_a_tick_event(self):
        self.listen(EventName.tick)
        self.timer.wait_for = Mock(side_effect=self.finish)

        event_source = EventSource(self.exchange, self.timer, self.mock_logger, CONFIG)
        event_source.start()

        self.assertEqual(self.last_listened_event.name,EventName.tick)

    def test_should_publish_multiple_events_until_nav_complete(self):
        self.listen(EventName.tick)
        self.after(5,EventName.end)
        self.timer.wait_for = Mock(side_effect=self.count_down_ticks)

        event_source = EventSource(self.exchange,self.timer, self.mock_logger,CONFIG)
        event_source.start()

        self.assertEqual(self.event_count,5)

    def test_errors_should_be_logged_and_events_continue(self):
        self.listen(EventName.tick)
        self.after(2,EventName.end)
        self.timer.wait_for = Mock(side_effect=self.count_down_ticks)

        self.exchange.original_publish = self.exchange.publish
        self.exchange.publish = self.intercept_publish

        event_source = EventSource(self.exchange,self.timer, self.mock_logger,CONFIG)
        event_source.start()

        self.mock_logger.error.assert_has_calls([call('EventSource, RuntimeError: oops')])
        self.assertEqual(self.event_count,2)

    def test_errors_during_logging_should_be_ignored_and_event_processing_continues(self):
        failing_logger = Mock()
        failing_logger.configure_mock(**{'error.side_effect': RuntimeError})

        self.listen(EventName.tick)
        self.after(2,EventName.end)
        self.timer.wait_for = Mock(side_effect=self.count_down_ticks)

        self.exchange.original_publish = self.exchange.publish
        self.exchange.publish = self.intercept_publish

        event_source = EventSource(self.exchange,self.timer, failing_logger,CONFIG)
        event_source.start()

        failing_logger.error.assert_has_calls([call('EventSource, RuntimeError: oops')])
        self.assertEqual(self.event_count,2)
コード例 #11
0
class TestNavigationAndHelm(unittest.TestCase):

    def ticks(self,number,duration):
        for i in range(1,number):
            self.exchange.publish(Event(EventName.tick))
            self.timer.wait_for(duration)

    def setUp(self):
        self.logger = Mock()
        self.logger.error = Mock(side_effect=print_msg)
        self.servo = Mock()

        self.exchange = Exchange(self.logger)
        self.timer = StubTimer()
        TimeShift(self.exchange,self.timer.time)

    def test_should_steer_to_next_waypoint(self):
        destination = Waypoint(Position(10.03,10.03),10)
        gps = FakeMovingGPS([Position(10,10),Position(10.01,10.01),Position(10.02,10.02),Position(10.03,10.03)])
        sensors = FakeSensors(gps,1,45)
        steerer = Steerer(self.servo,self.logger, CONFIG['steerer'])
        helm = Helm(self.exchange,sensors,steerer,self.logger, CONFIG['helm'])
        navigator = Navigator(sensors,Globe(),self.exchange,self.logger, CONFIG['navigator'])

        self.exchange.publish(Event(EventName.navigate,waypoint = destination))
        self.ticks(number = 14,duration=200)

        self.logger.info.assert_has_calls(
            [call('Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 4681.8m, review after 600s'),
             call('Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 3121.2m, review after 600s'),
             call('Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 1560.6m, review after 600s'),
             call('Navigator, arrived at +10.030000,+10.030000')])

    def test_should_navigate_to_next_waypoint_with_kink_in_route(self):
        destination = Waypoint(Position(10.03,10.03),10)
        gps = FakeMovingGPS([Position(10,10),Position(10.01,10.01),Position(10.025,10.015),Position(10.03,10.03)])
        sensors = FakeSensors(gps,1,45)
        steerer = Steerer(self.servo,self.logger, CONFIG['steerer'])
        helm = Helm(self.exchange,sensors,steerer,self.logger, CONFIG['helm'])
        navigator = Navigator(sensors,Globe(),self.exchange,self.logger, CONFIG['navigator'])

        self.exchange.publish(Event(EventName.navigate,waypoint = destination))
        self.ticks(number = 14,duration=200)

        self.logger.info.assert_has_calls(
            [call('Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 4681.8m, review after 600s'),
             call('Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 3121.2m, review after 600s'),
             call('Navigator, steering to +10.030000,+10.030000, bearing  71.3, distance 1734.0m, review after 600s'),
             call('Navigator, arrived at +10.030000,+10.030000')])

    def test_should_steer_repeatedly_during_navigation(self):
        logger = Mock()
        destination = Waypoint(Position(10.0003,10.0003),10)
        gps = FakeMovingGPS([Position(10,10),Position(10.0001,10.00015),Position(10.00025,10.0002),Position(10.0003,10.0003)])
        sensors = FakeSensors(gps,1,45)
        steerer = Steerer(self.servo,logger, CONFIG['steerer'])
        helm = Helm(self.exchange,sensors,steerer,logger, CONFIG['helm'])
        navigator = Navigator(sensors,Globe(),self.exchange,logger, CONFIG['navigator'])

        self.exchange.publish(Event(EventName.navigate,waypoint = destination))
        self.ticks(number = 7,duration=20)

        logger.debug.assert_has_calls(
            [call('Navigator, distance from waypoint +46.819018, combined tolerance +10.000000'),
             call('Navigator, distance from waypoint +27.647432, combined tolerance +10.000000'),
             call('Steerer, steering 36.4, heading 45.0, rate of turn +1.0, rudder +0.0, new rudder +4.6'),
             call('Steerer, steering 36.4, heading 45.0, rate of turn +1.0, rudder +4.6, new rudder +9.2'),
             call('Navigator, distance from waypoint +12.281099, combined tolerance +10.000000'),
             call('Steerer, steering 63.1, heading 45.0, rate of turn +1.0, rudder +9.2, new rudder +0.4'),
             call('Navigator, distance from waypoint +0.000000, combined tolerance +10.000000'),
             call('Steerer, steering 63.1, heading 45.0, rate of turn +1.0, rudder +0.4, new rudder -8.3'),
             call('Steerer, steering 63.1, heading 45.0, rate of turn +1.0, rudder -8.3, new rudder -17.1')])

        logger.info.assert_has_calls(
            [call('Navigator, steering to +10.000300,+10.000300, bearing  44.6, distance 46.8m, review after 23s'),
             call('Navigator, steering to +10.000300,+10.000300, bearing  36.4, distance 27.6m, review after 13s'),
             call('Navigator, steering to +10.000300,+10.000300, bearing  63.1, distance 12.3m, review after 6s'),
             call('Navigator, arrived at +10.000300,+10.000300')])
コード例 #12
0
ファイル: test_utils.py プロジェクト: andyrobinson/pi-nav
 def setUp(self):
     self.last_event = Event("None")
     self.events = {}
     self.exchange = Exchange(test_logger(logging.ERROR))
コード例 #13
0
 def setUp(self):
     self.mock_logger = Mock()
     self.exchange = Exchange(self.mock_logger)
     self.timer = Mock()
     self.last_event = None
コード例 #14
0
class TestEventSource(unittest.TestCase):
    def setUp(self):
        self.mock_logger = Mock()
        self.exchange = Exchange(self.mock_logger)
        self.timer = Mock()
        self.last_event = None

    def event_recorder(self, event):
        self.last_listened_event = event
        self.event_count += 1

    def intercept_publish(self, event):
        self.exchange.original_publish(event)
        if event.name == EventName.tick:
            raise RuntimeError("oops")

    def listen(self, event_name):
        self.event_count = 0
        self.exchange.subscribe(event_name, self.event_recorder)

    def after(self, times, event_name):
        self.ticks_left = times
        self.end_event_name = event_name

    def count_down_ticks(self, args):
        self.ticks_left -= 1
        if self.ticks_left <= 0:
            self.exchange.publish(Event(self.end_event_name))

    def finish(self, args):
        self.exchange.publish(Event(EventName.end))

    def test_should_publish_start_navigation_event(self):
        self.listen(EventName.start)
        self.timer.wait_for = Mock(side_effect=self.finish)

        event_source = EventSource(self.exchange, self.timer, self.mock_logger,
                                   CONFIG)
        event_source.start()

        self.assertEqual(self.last_listened_event.name, EventName.start)

    def test_should_publish_a_tick_event(self):
        self.listen(EventName.tick)
        self.timer.wait_for = Mock(side_effect=self.finish)

        event_source = EventSource(self.exchange, self.timer, self.mock_logger,
                                   CONFIG)
        event_source.start()

        self.assertEqual(self.last_listened_event.name, EventName.tick)

    def test_should_publish_multiple_events_until_nav_complete(self):
        self.listen(EventName.tick)
        self.after(5, EventName.end)
        self.timer.wait_for = Mock(side_effect=self.count_down_ticks)

        event_source = EventSource(self.exchange, self.timer, self.mock_logger,
                                   CONFIG)
        event_source.start()

        self.assertEqual(self.event_count, 5)

    def test_errors_should_be_logged_and_events_continue(self):
        self.listen(EventName.tick)
        self.after(2, EventName.end)
        self.timer.wait_for = Mock(side_effect=self.count_down_ticks)

        self.exchange.original_publish = self.exchange.publish
        self.exchange.publish = self.intercept_publish

        event_source = EventSource(self.exchange, self.timer, self.mock_logger,
                                   CONFIG)
        event_source.start()

        self.mock_logger.error.assert_has_calls(
            [call('EventSource, RuntimeError: oops')])
        self.assertEqual(self.event_count, 2)

    def test_errors_during_logging_should_be_ignored_and_event_processing_continues(
            self):
        failing_logger = Mock()
        failing_logger.configure_mock(**{'error.side_effect': RuntimeError})

        self.listen(EventName.tick)
        self.after(2, EventName.end)
        self.timer.wait_for = Mock(side_effect=self.count_down_ticks)

        self.exchange.original_publish = self.exchange.publish
        self.exchange.publish = self.intercept_publish

        event_source = EventSource(self.exchange, self.timer, failing_logger,
                                   CONFIG)
        event_source.start()

        failing_logger.error.assert_has_calls(
            [call('EventSource, RuntimeError: oops')])
        self.assertEqual(self.event_count, 2)
コード例 #15
0
ファイル: test_events.py プロジェクト: andyrobinson/pi-nav
 def setUp(self):
     self.mock_logger = Mock()
     self.exchange = Exchange(self.mock_logger)
コード例 #16
0
ファイル: test_events.py プロジェクト: andyrobinson/pi-nav
class TestEvents(unittest.TestCase):
    def setUp(self):
        self.mock_logger = Mock()
        self.exchange = Exchange(self.mock_logger)

    def test_should_return_nil_event_if_not_called(self):
        ts = TestSubscriber()
        self.assertEqual(ts.last_event_called.name, "nil")

    def test_should_call_back(self):
        ts = TestSubscriber(self.exchange)

        self.exchange.subscribe("thing", ts.callme)
        self.exchange.publish(Event("thing"))

    def test_should_ignore_events_with_no_subscribers_and_log_warning(self):
        self.exchange.publish(Event("doesnotexist"))
        self.mock_logger.warn.assert_called_with(
            "Event(doesnotexist) published but no subscribers")

    def test_should_be_able_to_unsubscribe(self):
        ts1 = TestSubscriber(self.exchange)
        self.exchange.subscribe("never", ts1.callme)
        self.exchange.unsubscribe("never", ts1.callme)
        self.exchange.publish(Event("never"))

        self.assertEqual(ts1.last_event_called.name, "nil")
        self.mock_logger.warn.assert_called_with(
            "Event(never) published but no subscribers")

    def test_should_accept_unsubscribe_without_subscribe(self):
        ts1 = TestSubscriber(self.exchange)
        self.exchange.unsubscribe("never", ts1.callme)
        self.exchange.publish(Event("never"))

        self.assertEqual(ts1.last_event_called.name, "nil")
        self.mock_logger.warn.assert_called_with(
            "Event(never) published but no subscribers")

    def test_should_signal_events_to_multiple_subscribers(self):
        ts1 = TestSubscriber(self.exchange)
        ts2 = TestSubscriber(self.exchange)

        self.exchange.subscribe("boo", ts1.callme)
        self.exchange.subscribe("boo", ts2.callme)
        self.exchange.publish(Event("boo"))

        self.assertEqual(ts1.last_event_called.name, "boo")
        self.assertEqual(ts2.last_event_called.name, "boo")

    def test_should_be_able_to_chain_events(self):
        ts1 = TestSubscriber(self.exchange)
        ts2 = TestSubscriber(self.exchange)

        self.exchange.subscribe("chain", ts1.callme)
        self.exchange.subscribe("secondevent", ts2.callme)
        self.exchange.publish(Event("chain"))

        self.assertEqual(ts2.last_event_called.name, "secondevent")

    def test_should_chain_a_few_events(self):
        ts = TestSubscriber(self.exchange)
        ts2 = TestSubscriber(self.exchange)

        self.exchange.subscribe("chain", ts.callme)
        self.exchange.subscribe("secondevent", ts.callme)
        self.exchange.subscribe("secondevent", ts2.callme)
        self.exchange.publish(Event("chain"))

        self.assertEqual(ts.event_call_count("secondevent"), 1)
        self.assertEqual(ts2.event_call_count("secondevent"), 1)

    def test_should_call_events_again_if_we_signal_primary_event_again(self):
        ts = TestSubscriber(self.exchange)
        event = Event("bing")
        self.exchange.subscribe("bing", ts.callme)
        self.exchange.publish(event)
        self.exchange.publish(event)
        self.exchange.publish(event)

        self.assertEqual(ts.event_call_count("bing"), 3)

    def test_errors_should_be_logged_and_event_processing_continues(self):
        ts_error = TestSubscriber(self.exchange)
        ts_after_error = TestSubscriber(self.exchange)
        event = Event("bong")
        self.exchange.subscribe("bong", ts_error.bad_call)
        self.exchange.subscribe("bong", ts_after_error.callme)

        self.exchange.publish(event)

        self.mock_logger.error.assert_has_calls(
            [call('Exchange, RuntimeError: oops')])
        self.assertEqual(ts_after_error.event_call_count("bong"), 1)

    def test_errors_during_logging_should_be_ignored_and_event_processing_continues(
            self):
        failing_logger = Mock()
        failing_logger.configure_mock(**{'error.side_effect': RuntimeError})

        exchange = Exchange(failing_logger)
        ts_error = TestSubscriber(exchange)
        ts_after_error = TestSubscriber(exchange)

        event = Event("bong")
        exchange.subscribe("bong", ts_error.bad_call)
        exchange.subscribe("bong", ts_after_error.callme)

        exchange.publish(event)

        failing_logger.error.assert_has_calls(
            [call('Exchange, RuntimeError: oops')])
        self.assertEqual(ts_after_error.event_call_count("bong"), 1)
コード例 #17
0
 def setUp(self):
     self.mock_logger = Mock()
     self.exchange = Exchange(self.mock_logger)
     self.timer = Mock()
     self.last_event = None
コード例 #18
0
 def setUp(self):
     self.last_event = Event("None")
     self.events = {}
     self.exchange = Exchange(test_logger(logging.ERROR))
コード例 #19
0
ファイル: test_events.py プロジェクト: andyrobinson/pi-nav
class TestEvents(unittest.TestCase):
    def setUp(self):
        self.mock_logger = Mock()
        self.exchange = Exchange(self.mock_logger)

    def test_should_return_nil_event_if_not_called(self):
        ts = TestSubscriber()
        self.assertEqual(ts.last_event_called.name,"nil")

    def test_should_call_back(self):
        ts = TestSubscriber(self.exchange)

        self.exchange.subscribe("thing",ts.callme)
        self.exchange.publish(Event("thing"))

    def test_should_ignore_events_with_no_subscribers_and_log_warning(self):
        self.exchange.publish(Event("doesnotexist"))
        self.mock_logger.warn.assert_called_with("Event(doesnotexist) published but no subscribers")

    def test_should_be_able_to_unsubscribe(self):
        ts1 = TestSubscriber(self.exchange)
        self.exchange.subscribe("never",ts1.callme)
        self.exchange.unsubscribe("never",ts1.callme)
        self.exchange.publish(Event("never"))

        self.assertEqual(ts1.last_event_called.name,"nil")
        self.mock_logger.warn.assert_called_with("Event(never) published but no subscribers")

    def test_should_accept_unsubscribe_without_subscribe(self):
        ts1 = TestSubscriber(self.exchange)
        self.exchange.unsubscribe("never",ts1.callme)
        self.exchange.publish(Event("never"))

        self.assertEqual(ts1.last_event_called.name,"nil")
        self.mock_logger.warn.assert_called_with("Event(never) published but no subscribers")

    def test_should_signal_events_to_multiple_subscribers(self):
        ts1 = TestSubscriber(self.exchange)
        ts2 = TestSubscriber(self.exchange)

        self.exchange.subscribe("boo",ts1.callme)
        self.exchange.subscribe("boo",ts2.callme)
        self.exchange.publish(Event("boo"))

        self.assertEqual(ts1.last_event_called.name,"boo")
        self.assertEqual(ts2.last_event_called.name,"boo")

    def test_should_be_able_to_chain_events(self):
        ts1 = TestSubscriber(self.exchange)
        ts2 = TestSubscriber(self.exchange)

        self.exchange.subscribe("chain",ts1.callme)
        self.exchange.subscribe("secondevent",ts2.callme)
        self.exchange.publish(Event("chain"))

        self.assertEqual(ts2.last_event_called.name,"secondevent")

    def test_should_chain_a_few_events(self):
        ts = TestSubscriber(self.exchange)
        ts2 = TestSubscriber(self.exchange)

        self.exchange.subscribe("chain",ts.callme)
        self.exchange.subscribe("secondevent",ts.callme)
        self.exchange.subscribe("secondevent",ts2.callme)
        self.exchange.publish(Event("chain"))

        self.assertEqual(ts.event_call_count("secondevent"),1)
        self.assertEqual(ts2.event_call_count("secondevent"),1)

    def test_should_call_events_again_if_we_signal_primary_event_again(self):
        ts = TestSubscriber(self.exchange)
        event = Event("bing")
        self.exchange.subscribe("bing",ts.callme)
        self.exchange.publish(event)
        self.exchange.publish(event)
        self.exchange.publish(event)

        self.assertEqual(ts.event_call_count("bing"),3)

    def test_errors_should_be_logged_and_event_processing_continues(self):
        ts_error = TestSubscriber(self.exchange)
        ts_after_error = TestSubscriber(self.exchange)
        event = Event("bong")
        self.exchange.subscribe("bong",ts_error.bad_call)
        self.exchange.subscribe("bong",ts_after_error.callme)

        self.exchange.publish(event)

        self.mock_logger.error.assert_has_calls([call('Exchange, RuntimeError: oops')])
        self.assertEqual(ts_after_error.event_call_count("bong"),1)

    def test_errors_during_logging_should_be_ignored_and_event_processing_continues(self):
        failing_logger = Mock()
        failing_logger.configure_mock(**{'error.side_effect': RuntimeError})

        exchange = Exchange(failing_logger)
        ts_error = TestSubscriber(exchange)
        ts_after_error = TestSubscriber(exchange)

        event = Event("bong")
        exchange.subscribe("bong",ts_error.bad_call)
        exchange.subscribe("bong",ts_after_error.callme)

        exchange.publish(event)

        failing_logger.error.assert_has_calls([call('Exchange, RuntimeError: oops')])
        self.assertEqual(ts_after_error.event_call_count("bong"),1)
コード例 #20
0
class TestNavigationAndHelm(unittest.TestCase):
    def ticks(self, number, duration):
        for i in range(1, number):
            self.exchange.publish(Event(EventName.tick))
            self.timer.wait_for(duration)

    def setUp(self):
        self.logger = Mock()
        self.logger.error = Mock(side_effect=print_msg)
        self.servo = Mock()

        self.exchange = Exchange(self.logger)
        self.timer = StubTimer()
        TimeShift(self.exchange, self.timer.time)

    def test_should_steer_to_next_waypoint(self):
        destination = Waypoint(Position(10.03, 10.03), 10)
        gps = FakeMovingGPS([
            Position(10, 10),
            Position(10.01, 10.01),
            Position(10.02, 10.02),
            Position(10.03, 10.03)
        ])
        sensors = FakeSensors(gps, 1, 45)
        steerer = Steerer(self.servo, self.logger, CONFIG['steerer'])
        helm = Helm(self.exchange, sensors, steerer, self.logger,
                    CONFIG['helm'])
        navigator = Navigator(sensors, Globe(), self.exchange, self.logger,
                              CONFIG['navigator'])

        self.exchange.publish(Event(EventName.navigate, waypoint=destination))
        self.ticks(number=14, duration=200)

        self.logger.info.assert_has_calls([
            call(
                'Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 4681.8m, review after 600s'
            ),
            call(
                'Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 3121.2m, review after 600s'
            ),
            call(
                'Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 1560.6m, review after 600s'
            ),
            call('Navigator, arrived at +10.030000,+10.030000')
        ])

    def test_should_navigate_to_next_waypoint_with_kink_in_route(self):
        destination = Waypoint(Position(10.03, 10.03), 10)
        gps = FakeMovingGPS([
            Position(10, 10),
            Position(10.01, 10.01),
            Position(10.025, 10.015),
            Position(10.03, 10.03)
        ])
        sensors = FakeSensors(gps, 1, 45)
        steerer = Steerer(self.servo, self.logger, CONFIG['steerer'])
        helm = Helm(self.exchange, sensors, steerer, self.logger,
                    CONFIG['helm'])
        navigator = Navigator(sensors, Globe(), self.exchange, self.logger,
                              CONFIG['navigator'])

        self.exchange.publish(Event(EventName.navigate, waypoint=destination))
        self.ticks(number=14, duration=200)

        self.logger.info.assert_has_calls([
            call(
                'Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 4681.8m, review after 600s'
            ),
            call(
                'Navigator, steering to +10.030000,+10.030000, bearing  44.6, distance 3121.2m, review after 600s'
            ),
            call(
                'Navigator, steering to +10.030000,+10.030000, bearing  71.3, distance 1734.0m, review after 600s'
            ),
            call('Navigator, arrived at +10.030000,+10.030000')
        ])

    def test_should_steer_repeatedly_during_navigation(self):
        logger = Mock()
        destination = Waypoint(Position(10.0003, 10.0003), 10)
        gps = FakeMovingGPS([
            Position(10, 10),
            Position(10.0001, 10.00015),
            Position(10.00025, 10.0002),
            Position(10.0003, 10.0003)
        ])
        sensors = FakeSensors(gps, 1, 45)
        steerer = Steerer(self.servo, logger, CONFIG['steerer'])
        helm = Helm(self.exchange, sensors, steerer, logger, CONFIG['helm'])
        navigator = Navigator(sensors, Globe(), self.exchange, logger,
                              CONFIG['navigator'])

        self.exchange.publish(Event(EventName.navigate, waypoint=destination))
        self.ticks(number=7, duration=20)

        logger.debug.assert_has_calls([
            call(
                'Navigator, distance from waypoint +46.819018, combined tolerance +10.000000'
            ),
            call(
                'Navigator, distance from waypoint +27.647432, combined tolerance +10.000000'
            ),
            call(
                'Steerer, steering 36.4, heading 45.0, rate of turn +1.0, rudder +0.0, new rudder +4.6'
            ),
            call(
                'Steerer, steering 36.4, heading 45.0, rate of turn +1.0, rudder +4.6, new rudder +9.2'
            ),
            call(
                'Navigator, distance from waypoint +12.281099, combined tolerance +10.000000'
            ),
            call(
                'Steerer, steering 63.1, heading 45.0, rate of turn +1.0, rudder +9.2, new rudder +0.4'
            ),
            call(
                'Navigator, distance from waypoint +0.000000, combined tolerance +10.000000'
            ),
            call(
                'Steerer, steering 63.1, heading 45.0, rate of turn +1.0, rudder +0.4, new rudder -8.3'
            ),
            call(
                'Steerer, steering 63.1, heading 45.0, rate of turn +1.0, rudder -8.3, new rudder -17.1'
            )
        ])

        logger.info.assert_has_calls([
            call(
                'Navigator, steering to +10.000300,+10.000300, bearing  44.6, distance 46.8m, review after 23s'
            ),
            call(
                'Navigator, steering to +10.000300,+10.000300, bearing  36.4, distance 27.6m, review after 13s'
            ),
            call(
                'Navigator, steering to +10.000300,+10.000300, bearing  63.1, distance 12.3m, review after 6s'
            ),
            call('Navigator, arrived at +10.000300,+10.000300')
        ])
コード例 #21
0
ファイル: test_events.py プロジェクト: andyrobinson/pi-nav
 def setUp(self):
     self.mock_logger = Mock()
     self.exchange = Exchange(self.mock_logger)