Example #1
0
 def setUp(self) -> None:
     self.event = {
         u'command': '@**test**',
         u'message': {
             'content': 'test_content',
         }
     }
     self.handler = GenericOutgoingWebhookService(service_name='test-service',
                                                  base_url='http://example.domain.com',
                                                  token='abcdef',
                                                  user_profile=None)
 def setUp(self) -> None:
     self.event = {
         u'command': '@**test**',
         u'message': {
             'content': '@**test**',
         },
         u'trigger': 'mention',
     }
     self.bot_user = get_user("*****@*****.**", get_realm("zulip"))
     self.handler = GenericOutgoingWebhookService(service_name='test-service',
                                                  base_url='http://example.domain.com',
                                                  token='abcdef',
                                                  user_profile=self.bot_user)
Example #3
0
    def test_retry_request(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        response = ResponseMock(500)
        with mock.patch(
                'requests.request',
                return_value=response), self.assertLogs(level="WARNING") as m:
            final_response = do_rest_call('', None, mock_event,
                                          service_handler)
            assert final_response is not None

            self.assertEqual(m.output, [
                f"WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code 500.\n Content of response (in quotes): \"{final_response.content.decode()}\""
            ])
        bot_owner_notification = self.get_last_message()
        self.assertEqual(
            bot_owner_notification.content,
            '''[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
The webhook got a response with status code *500*.''')

        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.id)
    def test_headers(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService("token", bot_user, "service")

        with mock.patch("requests.request") as mock_request, self.assertLogs(level="WARNING") as m:
            final_response = do_rest_call("", "payload-stub", mock_event, service_handler)
            assert final_response is not None

            self.assertEqual(
                m.output,
                [
                    f'WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code {final_response.status_code}.\n Content of response (in quotes): "{final_response.text}"'
                ],
            )

        kwargs = mock_request.call_args[1]
        self.assertEqual(kwargs["data"], "payload-stub")

        user_agent = "ZulipOutgoingWebhook/" + ZULIP_VERSION
        headers = {
            "content-type": "application/json",
            "User-Agent": user_agent,
        }
        self.assertEqual(kwargs["headers"], headers)
Example #5
0
    def test_successful_request(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        expect_send_response = mock.patch(
            "zerver.lib.outgoing_webhook.send_response_message")
        with mock.patch.object(
                service_handler,
                "session") as session, expect_send_response as mock_send:
            session.post.return_value = ResponseMock(
                200, orjson.dumps(dict(content="whatever")))
            with self.assertLogs(level="INFO") as logs:
                do_rest_call("", mock_event, service_handler)
            self.assert_length(logs.output, 1)
            self.assertIn(
                f"Outgoing webhook request from {bot_user.id}@zulip took ",
                logs.output[0])

        self.assertTrue(mock_send.called)

        for service_class in [
                GenericOutgoingWebhookService, SlackOutgoingWebhookService
        ]:
            handler = service_class("token", bot_user, "service")
            with mock.patch.object(handler, "session") as session:
                session.post.return_value = ResponseMock(200, b"{}")
                with self.assertLogs(level="INFO") as logs:
                    do_rest_call("", mock_event, handler)
                self.assert_length(logs.output, 1)
                self.assertIn(
                    f"Outgoing webhook request from {bot_user.id}@zulip took ",
                    logs.output[0])
                session.post.assert_called_once()
Example #6
0
    def test_headers(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        session = service_handler.session
        with mock.patch.object(session, "send") as mock_send:
            mock_send.return_value = ResponseMock(200, b"{}")
            with self.assertLogs(level="INFO") as logs:
                final_response = do_rest_call("https://example.com/",
                                              mock_event, service_handler)
            assert final_response is not None

            self.assert_length(logs.output, 1)
            self.assertIn(
                f"Outgoing webhook request from {bot_user.id}@zulip took ",
                logs.output[0])

            mock_send.assert_called_once()
            prepared_request = mock_send.call_args[0][0]
            user_agent = "ZulipOutgoingWebhook/" + ZULIP_VERSION
            headers = {
                "Content-Type": "application/json",
                "User-Agent": user_agent,
            }
            self.assertLessEqual(headers.items(),
                                 prepared_request.headers.items())
Example #7
0
    def test_invalid_json_in_response(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        expect_logging_info = self.assertLogs(level="INFO")
        expect_fail = mock.patch(
            "zerver.lib.outgoing_webhook.fail_with_message")

        with responses.RequestsMock(
                assert_all_requests_are_fired=True) as requests_mock:
            # We mock the endpoint to return response with a body which isn't valid json.
            requests_mock.add(
                requests_mock.POST,
                "https://example.zulip.com",
                status=200,
                body="this isn't valid json",
            )
            with expect_logging_info, expect_fail as mock_fail:
                do_rest_call("https://example.zulip.com", mock_event,
                             service_handler)
            self.assertTrue(mock_fail.called)
            bot_owner_notification = self.get_last_message()
            self.assertEqual(
                bot_owner_notification.content,
                """[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) to your bot @_**Outgoing Webhook** triggered an outgoing webhook.
The outgoing webhook server attempted to send a message in Zulip, but that request resulted in the following error:
> Invalid JSON in response\nThe response contains the following payload:\n```\n"this isn't valid json"\n```""",
            )
        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.recipient_id)
Example #8
0
    def test_jsonable_exception(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        # The "widget_content" key is required to be a string which is
        # itself JSON-encoded; passing arbitrary text data in it will
        # cause the hook to fail.
        response = {"content": "whatever", "widget_content": "test"}
        expect_logging_info = self.assertLogs(level="INFO")
        expect_fail = mock.patch(
            "zerver.lib.outgoing_webhook.fail_with_message")

        with responses.RequestsMock(
                assert_all_requests_are_fired=True) as requests_mock:
            requests_mock.add(requests_mock.POST,
                              "https://example.zulip.com",
                              status=200,
                              json=response)
            with expect_logging_info, expect_fail as mock_fail:
                do_rest_call("https://example.zulip.com", mock_event,
                             service_handler)
            self.assertTrue(mock_fail.called)
            bot_owner_notification = self.get_last_message()
            self.assertEqual(
                bot_owner_notification.content,
                """[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) to your bot @_**Outgoing Webhook** triggered an outgoing webhook.
The outgoing webhook server attempted to send a message in Zulip, but that request resulted in the following error:
> Widgets: API programmer sent invalid JSON content\nThe response contains the following payload:\n```\n'{"content": "whatever", "widget_content": "test"}'\n```""",
            )
        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.recipient_id)
Example #9
0
    def test_error_handling(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")
        bot_user_email = self.example_user_map['outgoing_webhook_bot']

        def helper(side_effect: Any, error_text: str) -> None:

            with mock.patch('requests.request', side_effect=side_effect):
                do_rest_call('', None, mock_event, service_handler)

            bot_owner_notification = self.get_last_message()
            self.assertIn(error_text, bot_owner_notification.content)
            self.assertIn('triggered', bot_owner_notification.content)
            assert bot_user.bot_owner is not None
            self.assertEqual(bot_owner_notification.recipient_id,
                             bot_user.bot_owner.id)

        with self.assertLogs(level="INFO") as i:
            helper(side_effect=timeout_error, error_text='A timeout occurred.')
            helper(side_effect=connection_error,
                   error_text='A connection error occurred.')

            log_output = [
                f"INFO:root:Trigger event {mock_event['command']} on {mock_event['service_name']} timed out. Retrying",
                f"WARNING:root:Maximum retries exceeded for trigger:{bot_user_email} event:{mock_event['command']}",
                f"INFO:root:Trigger event {mock_event['command']} on {mock_event['service_name']} resulted in a connection error. Retrying",
                f"WARNING:root:Maximum retries exceeded for trigger:{bot_user_email} event:{mock_event['command']}"
            ]

            self.assertEqual(i.output, log_output)
Example #10
0
    def test_headers(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        with mock.patch('requests.request') as mock_request, self.assertLogs(
                level="WARNING") as m:
            final_response = do_rest_call('', 'payload-stub', mock_event,
                                          service_handler)
            assert final_response is not None

            self.assertEqual(m.output, [
                f"WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code {final_response.status_code}.\n Content of response (in quotes): \"{final_response.content.decode()}\""
            ])

        kwargs = mock_request.call_args[1]
        self.assertEqual(kwargs['data'], 'payload-stub')

        user_agent = 'ZulipOutgoingWebhook/' + ZULIP_VERSION
        headers = {
            'content-type': 'application/json',
            'User-Agent': user_agent,
        }
        self.assertEqual(kwargs['headers'], headers)
Example #11
0
    def test_request_exception(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        expect_request_exception = mock.patch(
            "requests.request", side_effect=request_exception_error)
        expect_logging_exception = self.assertLogs(level="ERROR")
        expect_fail = mock.patch(
            "zerver.lib.outgoing_webhook.fail_with_message")

        # Don't think that we should catch and assert whole log output(which is actually a very big error traceback).
        # We are already asserting bot_owner_notification.content which verifies exception did occur.
        with expect_request_exception, expect_logging_exception, expect_fail as mock_fail:
            do_rest_call('', None, mock_event, service_handler)

        self.assertTrue(mock_fail.called)

        bot_owner_notification = self.get_last_message()
        self.assertEqual(
            bot_owner_notification.content,
            '''[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
When trying to send a request to the webhook service, an exception of type RequestException occurred:
```
I'm a generic exception :(
```''')
        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.id)
Example #12
0
    def setUp(self) -> None:
        super().setUp()
        realm = get_realm("zulip")
        user_profile = get_user("*****@*****.**", realm)
        self.mock_event = {
            # In the tests there is no active queue processor, so retries don't get processed.
            # Therefore, we need to emulate `retry_event` in the last stage when the maximum
            # retries have been exceeded.
            'failed_tries': 3,
            'message': {
                'display_recipient': 'Verona',
                'stream_id': 999,
                TOPIC_NAME: 'Foo',
                'id': '',
                'type': 'stream'
            },
            'user_profile_id': user_profile.id,
            'command': '',
            'service_name': ''
        }

        self.bot_user = self.example_user('outgoing_webhook_bot')
        self.service_handler = GenericOutgoingWebhookService(
            "token", self.bot_user, "service")
        logging.disable(logging.WARNING)
    def test_request_exception(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        expect_request_exception = mock.patch(
            "requests.request", side_effect=request_exception_error)
        expect_logging_exception = mock.patch("logging.exception")
        expect_fail = mock.patch(
            "zerver.lib.outgoing_webhook.fail_with_message")

        with expect_request_exception, expect_logging_exception, expect_fail as mock_fail:
            do_rest_call('', None, mock_event, service_handler)

        self.assertTrue(mock_fail.called)

        bot_owner_notification = self.get_last_message()
        self.assertEqual(
            bot_owner_notification.content,
            '''[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
When trying to send a request to the webhook service, an exception of type RequestException occurred:
```
I'm a generic exception :(
```''')
        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.id)
    def test_fail_request(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        response = ResponseMock(400)
        expect_400 = mock.patch("requests.request", return_value=response)
        expect_fail = mock.patch(
            "zerver.lib.outgoing_webhook.fail_with_message")
        expect_warnings = mock.patch("logging.warning")

        with expect_400, expect_fail as mock_fail, expect_warnings:
            do_rest_call('', None, mock_event, service_handler)

        self.assertTrue(mock_fail.called)

        bot_owner_notification = self.get_last_message()
        self.assertEqual(
            bot_owner_notification.content,
            '''[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
The webhook got a response with status code *400*.''')

        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.id)
Example #15
0
    def test_retry_request(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        with mock.patch.object(
                service_handler,
                "session") as session, self.assertLogs(level="WARNING") as m:
            session.post.return_value = ResponseMock(500)
            final_response = do_rest_call("", mock_event, service_handler)
            assert final_response is not None

            self.assertEqual(
                m.output,
                [
                    f'WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code 500.\n Content of response (in quotes): "{final_response.text}"'
                ],
            )
        bot_owner_notification = self.get_last_message()
        self.assertEqual(
            bot_owner_notification.content,
            """[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) to your bot @_**Outgoing Webhook** triggered an outgoing webhook.
The webhook got a response with status code *500*.""",
        )

        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.recipient_id)
class TestGenericOutgoingWebhookService(ZulipTestCase):
    def setUp(self) -> None:
        self.event = {
            u'command': '@**test**',
            u'message': {
                'content': '@**test**',
            },
            u'trigger': 'mention',
        }
        self.bot_user = get_user("*****@*****.**",
                                 get_realm("zulip"))
        self.handler = GenericOutgoingWebhookService(
            service_name='test-service',
            base_url='http://example.domain.com',
            token='abcdef',
            user_profile=self.bot_user)

    def test_process_event(self) -> None:
        rest_operation, request_data = self.handler.process_event(self.event)
        request_data = json.loads(request_data)
        self.assertEqual(request_data['data'], "@**test**")
        self.assertEqual(request_data['token'], "abcdef")
        self.assertEqual(rest_operation['base_url'],
                         "http://example.domain.com")
        self.assertEqual(rest_operation['method'], "POST")
        self.assertEqual(request_data['message'], self.event['message'])

    def test_process_success(self) -> None:
        response = mock.Mock(spec=Response)
        response.text = json.dumps({"response_not_required": True})
        success_response, _ = self.handler.process_success(
            response, self.event)
        self.assertEqual(success_response, None)

        response.text = json.dumps({"response_string": 'test_content'})
        success_response, _ = self.handler.process_success(
            response, self.event)
        self.assertEqual(success_response, 'test_content')

        response.text = json.dumps({})
        success_response, _ = self.handler.process_success(
            response, self.event)
        self.assertEqual(success_response, None)
 def setUp(self) -> None:
     self.event = {
         u'command': '@**test**',
         u'message': {
             'content': 'test_content',
         }
     }
     self.handler = GenericOutgoingWebhookService(service_name='test-service',
                                                  base_url='http://example.domain.com',
                                                  token='abcdef',
                                                  user_profile=None)
    def test_response_none(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        with mock.patch(
                "zerver.lib.outgoing_webhook.GenericOutgoingWebhookService.make_request",
                return_value=None,
        ), self.assertLogs(level="INFO") as logs:
            resp = do_rest_call("", mock_event, service_handler)
            self.assertEqual(resp, None)
        self.assert_length(logs.output, 1)
 def setUp(self) -> None:
     self.event = {
         u'command': '@**test**',
         u'message': {
             'content': '@**test**',
         },
         u'trigger': 'mention',
     }
     self.bot_user = get_user("*****@*****.**", get_realm("zulip"))
     self.handler = GenericOutgoingWebhookService(service_name='test-service',
                                                  base_url='http://example.domain.com',
                                                  token='abcdef',
                                                  user_profile=self.bot_user)
class TestGenericOutgoingWebhookService(ZulipTestCase):

    def setUp(self) -> None:
        self.event = {
            u'command': '@**test**',
            u'message': {
                'content': '@**test**',
            },
            u'trigger': 'mention',
        }
        self.bot_user = get_user("*****@*****.**", get_realm("zulip"))
        self.handler = GenericOutgoingWebhookService(service_name='test-service',
                                                     base_url='http://example.domain.com',
                                                     token='abcdef',
                                                     user_profile=self.bot_user)

    def test_process_event(self) -> None:
        rest_operation, request_data = self.handler.process_event(self.event)
        request_data = json.loads(request_data)
        self.assertEqual(request_data['data'], "@**test**")
        self.assertEqual(request_data['token'], "abcdef")
        self.assertEqual(rest_operation['base_url'], "http://example.domain.com")
        self.assertEqual(rest_operation['method'], "POST")
        self.assertEqual(request_data['message'], self.event['message'])

    def test_process_success(self) -> None:
        response = mock.Mock(spec=Response)
        response.text = json.dumps({"response_not_required": True})
        success_response, _ = self.handler.process_success(response, self.event)
        self.assertEqual(success_response, None)

        response.text = json.dumps({"response_string": 'test_content'})
        success_response, _ = self.handler.process_success(response, self.event)
        self.assertEqual(success_response, 'test_content')

        response.text = json.dumps({})
        success_response, _ = self.handler.process_success(response, self.event)
        self.assertEqual(success_response, None)
Example #21
0
        def helper(side_effect: Any, error_text: str) -> None:
            bot_user = self.example_user('outgoing_webhook_bot')
            mock_event = self.mock_event(bot_user)
            service_handler = GenericOutgoingWebhookService("token", bot_user, "service")

            with mock.patch('logging.warning'), mock.patch('logging.info'):
                with mock.patch('requests.request', side_effect=side_effect):
                    do_rest_call('', None, mock_event, service_handler)

            bot_owner_notification = self.get_last_message()
            self.assertIn(error_text, bot_owner_notification.content)
            self.assertIn('triggered', bot_owner_notification.content)
            assert bot_user.bot_owner is not None
            self.assertEqual(bot_owner_notification.recipient_id, bot_user.bot_owner.id)
    def test_bad_msg_type(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        mock_event["message"]["type"] = "unknown"
        with mock.patch.object(
                service_handler, "session") as session, self.assertRaises(
                    JsonableError), self.assertLogs(level="INFO"):
            session.post.return_value = ResponseMock(200)
            url = "http://somewhere.com/api/call"
            with mock.patch("zerver.lib.outgoing_webhook.get_message_url",
                            return_value=url):
                do_rest_call("", mock_event, service_handler)
Example #23
0
    def test_retry_request(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService("token", bot_user, "service")

        response = ResponseMock(500)

        with mock.patch('requests.request', return_value=response), mock.patch('logging.warning'):
            do_rest_call('',  None, mock_event, service_handler)

        bot_owner_notification = self.get_last_message()
        self.assertEqual(bot_owner_notification.content,
                         '''[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
The webhook got a response with status code *500*.''')

        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id, bot_user.bot_owner.id)
Example #24
0
    def test_headers(self) -> None:
        bot_user = self.example_user('outgoing_webhook_bot')
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService("token", bot_user, "service")

        with mock.patch('requests.request') as mock_request, mock.patch('logging.warning'):
            do_rest_call('', 'payload-stub', mock_event, service_handler)

        kwargs = mock_request.call_args[1]
        self.assertEqual(kwargs['data'], 'payload-stub')

        user_agent = 'ZulipOutgoingWebhook/' + ZULIP_VERSION
        headers = {
            'content-type': 'application/json',
            'User-Agent': user_agent,
        }
        self.assertEqual(kwargs['headers'], headers)
    def test_successful_request(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService("token", bot_user, "service")

        response = ResponseMock(200, orjson.dumps(dict(content="whatever")))
        expect_200 = mock.patch("requests.request", return_value=response)

        expect_send_response = mock.patch("zerver.lib.outgoing_webhook.send_response_message")
        with expect_200, expect_send_response as mock_send:
            do_rest_call("", None, mock_event, service_handler)
        self.assertTrue(mock_send.called)

        for service_class in [GenericOutgoingWebhookService, SlackOutgoingWebhookService]:
            handler = service_class("token", bot_user, "service")

            with expect_200:
                do_rest_call("", None, mock_event, handler)
Example #26
0
    def test_headers(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        session = service_handler.session
        with mock.patch.object(session, "send") as mock_send:
            mock_send.return_value = ResponseMock(200, b"{}")
            final_response = do_rest_call("https://example.com/", mock_event,
                                          service_handler)
            assert final_response is not None

            mock_send.assert_called_once()
            prepared_request = mock_send.call_args[0][0]
            user_agent = "ZulipOutgoingWebhook/" + ZULIP_VERSION
            headers = {
                "Content-Type": "application/json",
                "User-Agent": user_agent,
                "X-Smokescreen-Role": "webhook",
            }
            self.assertLessEqual(headers.items(),
                                 prepared_request.headers.items())
Example #27
0
    def test_fail_request(self) -> None:
        bot_user = self.example_user("outgoing_webhook_bot")
        mock_event = self.mock_event(bot_user)
        service_handler = GenericOutgoingWebhookService(
            "token", bot_user, "service")

        response = ResponseMock(400)
        expect_400 = mock.patch("requests.request", return_value=response)
        expect_fail = mock.patch(
            "zerver.lib.outgoing_webhook.fail_with_message")

        with expect_400, expect_fail as mock_fail, self.assertLogs(
                level="WARNING") as m:
            final_response = do_rest_call("", None, mock_event,
                                          service_handler)
            assert final_response is not None

            self.assertEqual(
                m.output,
                [
                    f'WARNING:root:Message http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/ triggered an outgoing webhook, returning status code 400.\n Content of response (in quotes): "{final_response.text}"'
                ],
            )

        self.assertTrue(mock_fail.called)

        bot_owner_notification = self.get_last_message()
        self.assertEqual(
            bot_owner_notification.content,
            """[A message](http://zulip.testserver/#narrow/stream/999-Verona/topic/Foo/near/) triggered an outgoing webhook.
The webhook got a response with status code *400*.""",
        )

        assert bot_user.bot_owner is not None
        self.assertEqual(bot_owner_notification.recipient_id,
                         bot_user.bot_owner.recipient_id)
def request_exception_error(http_method: Any, final_url: Any, data: Any,
                            **request_kwargs: Any) -> Any:
    raise requests.exceptions.RequestException("I'm a generic exception :(")


def timeout_error(http_method: Any, final_url: Any, data: Any,
                  **request_kwargs: Any) -> Any:
    raise requests.exceptions.Timeout("Time is up!")


def connection_error(http_method: Any, final_url: Any, data: Any,
                     **request_kwargs: Any) -> Any:
    raise requests.exceptions.ConnectionError()


service_handler = GenericOutgoingWebhookService(None, None, None)


class DoRestCallTests(ZulipTestCase):
    def setUp(self) -> None:
        super().setUp()
        realm = get_realm("zulip")
        user_profile = get_user("*****@*****.**", realm)
        self.mock_event = {
            # In the tests there is no active queue processor, so retries don't get processed.
            # Therefore, we need to emulate `retry_event` in the last stage when the maximum
            # retries have been exceeded.
            'failed_tries': 3,
            'message': {
                'display_recipient': 'Verona',
                'stream_id': 999,