Extract get_service_bot_events().

There are several reasons to extract this function:

    * It's easy to unit test without extensive mocking.
    * It will show up when we profile code.
    * It is something that you can mostly ignore for
      most messages.

The main reason to extract this, though, is that we are about
to do some fairly complex splicing of data for the use case
of mentioning service bots on streams they are not subscribed to,
and we want to localize the complexity.
This commit is contained in:
Steve Howell
2017-09-26 14:55:15 -07:00
committed by showell
parent b2c4a25a7b
commit b340b28055
2 changed files with 113 additions and 36 deletions

View File

@@ -863,6 +863,46 @@ def get_recipient_info(recipient, sender_id):
) # type: RecipientInfoResult
return info
def get_service_bot_events(sender, service_bot_tuples, mentioned_user_ids, recipient_type):
# type: (UserProfile, List[Tuple[int, int]], Set[int], int) -> Dict[str, List[Dict[str, Any]]]
# TODO: Right now, service bots need to be subscribed to a stream in order to
# receive messages when mentioned; we will want to change that structure.
# Prepare to collect service queue events triggered by the message.
event_dict = defaultdict(list) # type: Dict[str, List[Dict[str, Any]]]
# Avoid infinite loops by preventing messages sent by bots from generating
# Service events.
if sender.is_bot:
return event_dict
for user_profile_id, bot_type in service_bot_tuples:
if bot_type == UserProfile.OUTGOING_WEBHOOK_BOT:
queue_name = 'outgoing_webhooks'
elif bot_type == UserProfile.EMBEDDED_BOT:
queue_name = 'embedded_bots'
else:
logging.error(
'Unexpected bot_type for Service bot id=%s: %s' %
(user_profile_id, bot_type))
continue
# Mention triggers, primarily for stream messages
if user_profile_id in mentioned_user_ids:
trigger = 'mention'
# PM triggers for personal and huddle messsages
elif recipient_type != Recipient.STREAM:
trigger = 'private_message'
else:
continue
event_dict[queue_name].append({
'trigger': trigger,
'user_profile_id': user_profile_id,
})
return event_dict
def do_send_messages(messages_maybe_none):
# type: (Sequence[Optional[MutableMapping[str, Any]]]) -> List[int]
# Filter out messages which didn't pass internal_prep_message properly
@@ -935,41 +975,12 @@ def do_send_messages(messages_maybe_none):
ums.extend(user_messages)
# Prepare to collect service queue events triggered by the message.
message['message'].service_queue_events = defaultdict(list)
# Avoid infinite loops by preventing messages sent by bots from generating
# Service events.
sender = message['message'].sender
if sender.is_bot:
continue
# TODO: Right now, service bots need to be subscribed to a stream in order to
# receive messages when mentioned; we will want to change that structure.
for user_profile_id, bot_type in message['service_bot_tuples']:
if bot_type == UserProfile.OUTGOING_WEBHOOK_BOT:
queue_name = 'outgoing_webhooks'
elif bot_type == UserProfile.EMBEDDED_BOT:
queue_name = 'embedded_bots'
else:
logging.error(
'Unexpected bot_type for Service bot id=%s: %s' %
(user_profile_id, bot_type))
continue
# Mention triggers, primarily for stream messages
if user_profile_id in mentioned_user_ids:
trigger = 'mention'
# PM triggers for personal and huddle messsages
elif message['message'].recipient.type != Recipient.STREAM:
trigger = 'private_message'
else:
continue
message['message'].service_queue_events[queue_name].append({
'trigger': trigger,
'user_profile_id': user_profile_id,
})
message['message'].service_queue_events = get_service_bot_events(
sender=message['message'].sender,
service_bot_tuples=message['service_bot_tuples'],
mentioned_user_ids=mentioned_user_ids,
recipient_type=message['message'].recipient.type,
)
bulk_insert_ums(ums)

View File

@@ -5,7 +5,10 @@ from __future__ import print_function
import mock
from typing import Any, Union, Mapping, Callable
from zerver.lib.actions import do_create_user
from zerver.lib.actions import (
do_create_user,
get_service_bot_events,
)
from zerver.lib.test_classes import ZulipTestCase
from zerver.models import (
get_realm,
@@ -18,6 +21,69 @@ BOT_TYPE_TO_QUEUE_NAME = {
UserProfile.EMBEDDED_BOT: 'embedded_bots',
}
class TestServiceBotBasics(ZulipTestCase):
def _get_outgoing_bot(self):
# type: () -> UserProfile
outgoing_bot = do_create_user(
email="bar-bot@zulip.com",
password="test",
realm=get_realm("zulip"),
full_name="BarBot",
short_name='bb',
bot_type=UserProfile.OUTGOING_WEBHOOK_BOT,
bot_owner=self.example_user('cordelia'),
)
return outgoing_bot
def test_service_events_for_pms(self):
# type: () -> None
sender = self.example_user('hamlet')
assert(not sender.is_bot)
outgoing_bot = self._get_outgoing_bot()
event_dict = get_service_bot_events(
sender=sender,
service_bot_tuples=[
(outgoing_bot.id, outgoing_bot.bot_type),
],
mentioned_user_ids=set(),
recipient_type=Recipient.PERSONAL,
)
expected = dict(
outgoing_webhooks=[
dict(trigger='private_message', user_profile_id=outgoing_bot.id),
],
)
self.assertEqual(event_dict, expected)
def test_service_events_for_stream_mentions(self):
# type: () -> None
sender = self.example_user('hamlet')
assert(not sender.is_bot)
outgoing_bot = self._get_outgoing_bot()
event_dict = get_service_bot_events(
sender=sender,
service_bot_tuples=[
(outgoing_bot.id, outgoing_bot.bot_type),
],
mentioned_user_ids={outgoing_bot.id},
recipient_type=Recipient.STREAM,
)
expected = dict(
outgoing_webhooks=[
dict(trigger='mention', user_profile_id=outgoing_bot.id),
],
)
self.assertEqual(event_dict, expected)
class TestServiceBotEventTriggers(ZulipTestCase):
def setUp(self):