def test_async_datafeed_handles_500(self):

        events = [
            make_events(count=2, aio=True),
            make_error(503, "Server encountered an unknown error", aio=True),
            make_events(count=2, aio=True)
        ]
        event_service = StoppableAsyncService(self.bot_client)
        with SymphonyApiMocker(True) as m:

            m.add_mock_events(events)
            _run(event_service.start_datafeed())
    def test_async_datafeed_handles_400(self):

        events = [
            make_events(count=2, aio=True),
            make_error(400,
                       "Could not find a datafeed with the id: XXXXX",
                       aio=True),
            make_events(count=2, aio=True)
        ]
        event_service = StoppableAsyncService(self.bot_client)
        with SymphonyApiMocker(True) as m:

            m.add_mock_events(events)
            _run(event_service.start_datafeed())
    def test_datafeed_doesnt_exist_400(self):
        """This is a fairly common occurence in the wild"""

        with SymphonyApiMocker() as m:
            events = [
                make_events(count=2),
                make_error(400,
                           "Could not find a datafeed with the id: XXXXX"),
                make_events(count=2)
            ]

            m.add_mock_events(events)

            event_service = StoppableService(self.bot_client, log_events=True)
            event_service.start_datafeed()
    def test_async_datafeed_eventually_throws(self):

        events = [
            make_events(count=2, aio=True),
            make_error(400,
                       "Could not find a datafeed with the id: XXXXX",
                       aio=True),
            make_error(400,
                       "Could not find a datafeed with the id: XXXXX",
                       aio=True),
            make_error(400,
                       "Could not find a datafeed with the id: XXXXX",
                       aio=True),
            make_error(400,
                       "Could not find a datafeed with the id: XXXXX",
                       aio=True),
            make_error(400,
                       "Could not find a datafeed with the id: XXXXX",
                       aio=True),
        ]

        event_service = StoppableAsyncService(self.bot_client,
                                              log_events=True,
                                              error_timeout_sec=0.1)
        event_service.upper_threshold = 1.0

        with SymphonyApiMocker(True) as m:
            m.add_mock_events(events)

            with self.assertRaises(RuntimeError):
                _run(event_service.start_datafeed())
    def test_datafeed_server_500(self):
        """Ideally the retry logic would be tested for more complicated situations like multiple
        consecutive 500 errors, but global timeouts, and constantly reauthenticating during the
        test suite makes this difficult to do in isolation"""

        with SymphonyApiMocker() as m:

            events = [
                make_events(count=2),
                make_error(503),
                make_events(count=2)
            ]

            m.add_mock_events(events)

            event_service = StoppableService(self.bot_client)
            event_service.start_datafeed()
    def test_start_datafeed_and_stop_multiple_messages(self):
        """Test the stop event works for the custom datafeed when multiple events are
        passed at once"""
        with SymphonyApiMocker() as m:
            m.add_mock_events(
                [make_events(count=2),
                 make_events([None, None, STOP_EVENT])],
                add_stop_event=False)

            event_service = StoppableService(self.bot_client)
            event_service.start_datafeed()

            datafeed_calls = [
                req for req in m.requests_mock_manager.request_history
                if READ_DATAFEED_URL.match(req.url)
            ]

            self.assertEqual(len(datafeed_calls), 2)
    def test_start_datafeed_and_stop(self):
        """Test the stop event works for the custom datafeed"""

        with SymphonyApiMocker(True) as m:

            m.add_mock_events([make_events([STOP_EVENT], aio=True)])

            event_service = StoppableAsyncService(self.bot_client)
            _run(event_service.start_datafeed())
    def test_datafeed_listeners_run_asynchronously(self):
        """Specific test to make sure messages are handled asynchronously. A slow handler
        and a fast handler are created, with a message going to the slow handler first.
        It's asserted that the fast handler returns first - meaning it wasn't blocked"""
        class SlowFastListener(IMListener):
            def __init__(self):
                self.count = 0
                self.completed = []

            async def on_im_message(self, message):
                current_count = self.count
                self.count += 1
                if current_count == 0:
                    await asyncio.sleep(1)

                self.completed.append(current_count)

            async def on_im_created(self, stream):
                pass

        event_service = StoppableAsyncService(self.bot_client)
        listener = SlowFastListener()
        event_service.add_im_listener(listener)

        # First batch of two messages SENTMESSAGE in one call
        first_batch = make_events(count=2, aio=True)
        # A second batch of two messages, 2nd, 3rd and 4th should complete before the 1st
        second_batch = make_events(count=2, aio=True)
        events = [first_batch, second_batch]

        with SymphonyApiMocker(True) as m:

            m.add_mock_events(events)
            _run(event_service.start_datafeed())

        # Doesn't matter what order the last three occurred, as long as they all
        # completed before the first one
        self.assertEqual(len(listener.completed), 4)
        self.assertEqual(listener.completed[-1], 0)
    def test_datafeed_listeners_throw_errors(self):
        """Specific test to make sure errors thrown by listeners are not silently swallowed"""
        class ThrowingListener(IMListener):
            async def on_im_message(self, message):
                1 / 0

            async def on_im_created(self, stream):
                pass

        event_service = StoppableAsyncService(self.bot_client)
        event_service.add_im_listener(ThrowingListener())

        events = [make_events(count=1, aio=True)]

        with SymphonyApiMocker(True) as m:
            m.add_mock_events(events)
            with self.assertRaises(ZeroDivisionError):
                _run(event_service.start_datafeed())
    def test_multiple_messages_in_array(self):
        """Specific test to make sure different messages delivered together are both
        recognised"""
        class RecordingListener(IMListener):
            def __init__(self):
                self.received = []

            async def on_im_message(self, message):
                logging.debug(message)
                self.received.append(message["message"])

            async def on_im_created(self, stream):
                pass

        listener = RecordingListener()
        event_service = StoppableAsyncService(self.bot_client)
        event_service.add_im_listener(listener)

        expected_messages = ["Hello", "World"]
        # One message with Hello, another with World
        made_events = make_events(count=2,
                                  messages=expected_messages,
                                  aio=True)

        with SymphonyApiMocker(True) as m:

            m.add_mock_events([made_events])

            _run(event_service.start_datafeed())

        self.assertEqual(len(listener.received), 2)
        for expected in expected_messages:
            found = False
            for actual_message in listener.received:
                if expected in actual_message:
                    found = True
                    break
            self.assertTrue(
                found, "Did not find {} in {}".format(expected,
                                                      listener.received))
    def test_datafeed_throws_after_enough_exceptions(self):

        events = [
            make_events(count=2),
            make_error(400, "Could not find a datafeed with the id: XXXXX"),
            make_error(400, "Could not find a datafeed with the id: XXXXX"),
            make_error(400, "Could not find a datafeed with the id: XXXXX"),
            make_error(400, "Could not find a datafeed with the id: XXXXX"),
            make_error(400, "Could not find a datafeed with the id: XXXXX"),
        ]

        event_service = StoppableService(self.bot_client, log_events=True)
        event_service.baseline_timeout_sec = 0.1
        event_service.current_timeout_sec = 0.1
        event_service.lower_threshold = 0.1
        event_service.timeout_multiplier = 2.0
        event_service.upper_threshold = 1.0

        with SymphonyApiMocker() as m:

            m.add_mock_events(events)
            with self.assertRaises(RuntimeError, msg="threshold exceeded"):
                event_service.start_datafeed()