mirror of https://github.com/zulip/zulip.git
647 lines
25 KiB
Python
647 lines
25 KiB
Python
from typing import Any, Dict, List, Union
|
|
from unittest import mock
|
|
|
|
from django.utils.timezone import now as timezone_now
|
|
|
|
from zerver.lib.cache import cache_delete, to_dict_cache_key_id
|
|
from zerver.lib.markdown import version as markdown_version
|
|
from zerver.lib.message import MessageDict, messages_for_ids, sew_messages_and_reactions
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
from zerver.lib.test_helpers import make_client, queries_captured
|
|
from zerver.lib.topic import TOPIC_LINKS
|
|
from zerver.lib.types import DisplayRecipientT, UserDisplayRecipient
|
|
from zerver.models import (
|
|
Message,
|
|
Reaction,
|
|
Realm,
|
|
RealmFilter,
|
|
Recipient,
|
|
Stream,
|
|
UserProfile,
|
|
flush_per_request_caches,
|
|
get_display_recipient,
|
|
get_realm,
|
|
get_stream,
|
|
)
|
|
|
|
|
|
class MessageDictTest(ZulipTestCase):
|
|
def test_both_codepaths(self) -> None:
|
|
"""
|
|
We have two different codepaths that
|
|
extract a particular shape of dictionary
|
|
for messages to send to clients:
|
|
|
|
events:
|
|
|
|
These are the events we send to MANY
|
|
clients when a message is originally
|
|
sent.
|
|
|
|
fetch:
|
|
|
|
These are the messages we send to ONE
|
|
client when they fetch messages via
|
|
some narrow/search in the UI.
|
|
|
|
Different clients have different needs
|
|
when it comes to things like generating avatar
|
|
hashes or including both rendered and unrendered
|
|
Markdown, so that explains the different shapes.
|
|
|
|
And then the two codepaths have different
|
|
performance needs. In the events codepath, we
|
|
have the Django view generate a single "wide"
|
|
dictionary that gets put on the event queue,
|
|
and then we send events to multiple clients,
|
|
finalizing the payload for each of them depending
|
|
on the "shape" they want. (We also avoid
|
|
doing extra work for any two clients who want
|
|
the same shape dictionary, but that's out of the
|
|
scope of this particular test).
|
|
|
|
In the fetch scenario, the single client only needs
|
|
a dictionary of one shape, but we need to re-hydrate
|
|
the sender information, since the sender details
|
|
may have changed since the message was originally
|
|
sent.
|
|
|
|
This test simply verifies that the two codepaths
|
|
ultimately provide the same result.
|
|
"""
|
|
|
|
def reload_message(msg_id: int) -> Message:
|
|
# Get a clean copy of the message, and
|
|
# clear the cache.
|
|
cache_delete(to_dict_cache_key_id(msg_id))
|
|
msg = Message.objects.get(id=msg_id)
|
|
return msg
|
|
|
|
def get_send_message_payload(
|
|
msg_id: int, apply_markdown: bool, client_gravatar: bool
|
|
) -> Dict[str, Any]:
|
|
msg = reload_message(msg_id)
|
|
wide_dict = MessageDict.wide_dict(msg)
|
|
|
|
narrow_dict = MessageDict.finalize_payload(
|
|
wide_dict,
|
|
apply_markdown=apply_markdown,
|
|
client_gravatar=client_gravatar,
|
|
)
|
|
return narrow_dict
|
|
|
|
def get_fetch_payload(
|
|
msg_id: int, apply_markdown: bool, client_gravatar: bool
|
|
) -> Dict[str, Any]:
|
|
msg = reload_message(msg_id)
|
|
unhydrated_dict = MessageDict.to_dict_uncached_helper([msg])[0]
|
|
# The next step mutates the dict in place
|
|
# for performance reasons.
|
|
MessageDict.post_process_dicts(
|
|
[unhydrated_dict],
|
|
apply_markdown=apply_markdown,
|
|
client_gravatar=client_gravatar,
|
|
)
|
|
final_dict = unhydrated_dict
|
|
return final_dict
|
|
|
|
def test_message_id() -> int:
|
|
hamlet = self.example_user("hamlet")
|
|
self.login_user(hamlet)
|
|
msg_id = self.send_stream_message(
|
|
hamlet,
|
|
"Scotland",
|
|
topic_name="editing",
|
|
content="before edit",
|
|
)
|
|
return msg_id
|
|
|
|
flag_setups = [
|
|
[False, False],
|
|
[False, True],
|
|
[True, False],
|
|
[True, True],
|
|
]
|
|
|
|
msg_id = test_message_id()
|
|
|
|
for (apply_markdown, client_gravatar) in flag_setups:
|
|
send_message_payload = get_send_message_payload(
|
|
msg_id,
|
|
apply_markdown=apply_markdown,
|
|
client_gravatar=client_gravatar,
|
|
)
|
|
|
|
fetch_payload = get_fetch_payload(
|
|
msg_id,
|
|
apply_markdown=apply_markdown,
|
|
client_gravatar=client_gravatar,
|
|
)
|
|
|
|
self.assertEqual(send_message_payload, fetch_payload)
|
|
|
|
def test_bulk_message_fetching(self) -> None:
|
|
sender = self.example_user("othello")
|
|
receiver = self.example_user("hamlet")
|
|
pm_recipient = Recipient.objects.get(type_id=receiver.id, type=Recipient.PERSONAL)
|
|
stream_name = "Çiğdem"
|
|
stream = self.make_stream(stream_name)
|
|
stream_recipient = Recipient.objects.get(type_id=stream.id, type=Recipient.STREAM)
|
|
sending_client = make_client(name="test suite")
|
|
|
|
ids = []
|
|
for i in range(300):
|
|
for recipient in [pm_recipient, stream_recipient]:
|
|
message = Message(
|
|
sender=sender,
|
|
recipient=recipient,
|
|
content=f"whatever {i}",
|
|
rendered_content="DOES NOT MATTER",
|
|
rendered_content_version=markdown_version,
|
|
date_sent=timezone_now(),
|
|
sending_client=sending_client,
|
|
last_edit_time=timezone_now(),
|
|
edit_history="[]",
|
|
)
|
|
message.set_topic_name("whatever")
|
|
message.save()
|
|
ids.append(message.id)
|
|
|
|
Reaction.objects.create(
|
|
user_profile=sender, message=message, emoji_name="simple_smile"
|
|
)
|
|
|
|
num_ids = len(ids)
|
|
self.assertTrue(num_ids >= 600)
|
|
|
|
flush_per_request_caches()
|
|
with queries_captured() as queries:
|
|
rows = list(MessageDict.get_raw_db_rows(ids))
|
|
|
|
objs = [MessageDict.build_dict_from_raw_db_row(row) for row in rows]
|
|
MessageDict.post_process_dicts(objs, apply_markdown=False, client_gravatar=False)
|
|
|
|
self.assert_length(queries, 7)
|
|
self.assert_length(rows, num_ids)
|
|
|
|
def test_applying_markdown(self) -> None:
|
|
sender = self.example_user("othello")
|
|
receiver = self.example_user("hamlet")
|
|
recipient = Recipient.objects.get(type_id=receiver.id, type=Recipient.PERSONAL)
|
|
sending_client = make_client(name="test suite")
|
|
message = Message(
|
|
sender=sender,
|
|
recipient=recipient,
|
|
content="hello **world**",
|
|
date_sent=timezone_now(),
|
|
sending_client=sending_client,
|
|
last_edit_time=timezone_now(),
|
|
edit_history="[]",
|
|
)
|
|
message.set_topic_name("whatever")
|
|
message.save()
|
|
|
|
# An important part of this test is to get the message through this exact code path,
|
|
# because there is an ugly hack we need to cover. So don't just say "row = message".
|
|
row = MessageDict.get_raw_db_rows([message.id])[0]
|
|
dct = MessageDict.build_dict_from_raw_db_row(row)
|
|
expected_content = "<p>hello <strong>world</strong></p>"
|
|
self.assertEqual(dct["rendered_content"], expected_content)
|
|
message = Message.objects.get(id=message.id)
|
|
self.assertEqual(message.rendered_content, expected_content)
|
|
self.assertEqual(message.rendered_content_version, markdown_version)
|
|
|
|
@mock.patch("zerver.lib.message.markdown_convert")
|
|
def test_applying_markdown_invalid_format(self, convert_mock: Any) -> None:
|
|
# pretend the converter returned an invalid message without raising an exception
|
|
convert_mock.return_value = None
|
|
sender = self.example_user("othello")
|
|
receiver = self.example_user("hamlet")
|
|
recipient = Recipient.objects.get(type_id=receiver.id, type=Recipient.PERSONAL)
|
|
sending_client = make_client(name="test suite")
|
|
message = Message(
|
|
sender=sender,
|
|
recipient=recipient,
|
|
content="hello **world**",
|
|
date_sent=timezone_now(),
|
|
sending_client=sending_client,
|
|
last_edit_time=timezone_now(),
|
|
edit_history="[]",
|
|
)
|
|
message.set_topic_name("whatever")
|
|
message.save()
|
|
|
|
# An important part of this test is to get the message through this exact code path,
|
|
# because there is an ugly hack we need to cover. So don't just say "row = message".
|
|
row = MessageDict.get_raw_db_rows([message.id])[0]
|
|
dct = MessageDict.build_dict_from_raw_db_row(row)
|
|
error_content = (
|
|
"<p>[Zulip note: Sorry, we could not understand the formatting of your message]</p>"
|
|
)
|
|
self.assertEqual(dct["rendered_content"], error_content)
|
|
|
|
def test_topic_links_use_stream_realm(self) -> None:
|
|
# Set up a realm filter on 'zulip' and assert that messages
|
|
# sent to a stream on 'zulip' have the topic linkified,
|
|
# and not linkified when sent to a stream in 'lear'.
|
|
zulip_realm = get_realm("zulip")
|
|
lear_realm = get_realm("lear")
|
|
url_format_string = r"https://trac.example.com/ticket/%(id)s"
|
|
links = {"url": "https://trac.example.com/ticket/123", "text": "#123"}
|
|
topic_name = "test #123"
|
|
|
|
linkifier = RealmFilter(
|
|
realm=zulip_realm, pattern=r"#(?P<id>[0-9]{2,8})", url_format_string=url_format_string
|
|
)
|
|
self.assertEqual(
|
|
linkifier.__str__(),
|
|
"<RealmFilter(zulip): #(?P<id>[0-9]{2,8}) https://trac.example.com/ticket/%(id)s>",
|
|
)
|
|
|
|
def get_message(sender: UserProfile, realm: Realm) -> Message:
|
|
stream_name = "Denmark"
|
|
if not Stream.objects.filter(realm=realm, name=stream_name).exists():
|
|
self.make_stream(stream_name, realm)
|
|
msg_id = self.send_stream_message(sender, "Denmark", "hello world", topic_name, realm)
|
|
return Message.objects.get(id=msg_id)
|
|
|
|
def assert_topic_links(links: List[Dict[str, str]], msg: Message) -> None:
|
|
dct = MessageDict.to_dict_uncached_helper([msg])[0]
|
|
self.assertEqual(dct[TOPIC_LINKS], links)
|
|
|
|
# Send messages before and after saving the realm filter from each user.
|
|
assert_topic_links([], get_message(self.example_user("othello"), zulip_realm))
|
|
assert_topic_links([], get_message(self.lear_user("cordelia"), lear_realm))
|
|
assert_topic_links([], get_message(self.notification_bot(), zulip_realm))
|
|
linkifier.save()
|
|
assert_topic_links([links], get_message(self.example_user("othello"), zulip_realm))
|
|
assert_topic_links([], get_message(self.lear_user("cordelia"), lear_realm))
|
|
assert_topic_links([links], get_message(self.notification_bot(), zulip_realm))
|
|
|
|
def test_reaction(self) -> None:
|
|
sender = self.example_user("othello")
|
|
receiver = self.example_user("hamlet")
|
|
recipient = Recipient.objects.get(type_id=receiver.id, type=Recipient.PERSONAL)
|
|
sending_client = make_client(name="test suite")
|
|
message = Message(
|
|
sender=sender,
|
|
recipient=recipient,
|
|
content="hello **world**",
|
|
date_sent=timezone_now(),
|
|
sending_client=sending_client,
|
|
last_edit_time=timezone_now(),
|
|
edit_history="[]",
|
|
)
|
|
message.set_topic_name("whatever")
|
|
message.save()
|
|
|
|
reaction = Reaction.objects.create(
|
|
message=message, user_profile=sender, emoji_name="simple_smile"
|
|
)
|
|
row = MessageDict.get_raw_db_rows([message.id])[0]
|
|
msg_dict = MessageDict.build_dict_from_raw_db_row(row)
|
|
self.assertEqual(msg_dict["reactions"][0]["emoji_name"], reaction.emoji_name)
|
|
self.assertEqual(msg_dict["reactions"][0]["user_id"], sender.id)
|
|
self.assertEqual(msg_dict["reactions"][0]["user"]["id"], sender.id)
|
|
self.assertEqual(msg_dict["reactions"][0]["user"]["email"], sender.email)
|
|
self.assertEqual(msg_dict["reactions"][0]["user"]["full_name"], sender.full_name)
|
|
|
|
def test_missing_anchor(self) -> None:
|
|
self.login("hamlet")
|
|
result = self.client_get(
|
|
"/json/messages",
|
|
{"use_first_unread_anchor": "false", "num_before": "1", "num_after": "1"},
|
|
)
|
|
|
|
self.assert_json_error(result, "Missing 'anchor' argument.")
|
|
|
|
def test_invalid_anchor(self) -> None:
|
|
self.login("hamlet")
|
|
result = self.client_get(
|
|
"/json/messages",
|
|
{
|
|
"use_first_unread_anchor": "false",
|
|
"num_before": "1",
|
|
"num_after": "1",
|
|
"anchor": "chocolate",
|
|
},
|
|
)
|
|
|
|
self.assert_json_error(result, "Invalid anchor")
|
|
|
|
|
|
class MessageHydrationTest(ZulipTestCase):
|
|
def test_hydrate_stream_recipient_info(self) -> None:
|
|
realm = get_realm("zulip")
|
|
cordelia = self.example_user("cordelia")
|
|
|
|
stream_id = get_stream("Verona", realm).id
|
|
|
|
obj = dict(
|
|
recipient_type=Recipient.STREAM,
|
|
recipient_type_id=stream_id,
|
|
sender_is_mirror_dummy=False,
|
|
sender_email=cordelia.email,
|
|
sender_full_name=cordelia.full_name,
|
|
sender_id=cordelia.id,
|
|
)
|
|
|
|
MessageDict.hydrate_recipient_info(obj, "Verona")
|
|
|
|
self.assertEqual(obj["display_recipient"], "Verona")
|
|
self.assertEqual(obj["type"], "stream")
|
|
|
|
def test_hydrate_pm_recipient_info(self) -> None:
|
|
cordelia = self.example_user("cordelia")
|
|
display_recipient: List[UserDisplayRecipient] = [
|
|
dict(
|
|
email="aaron@example.com",
|
|
full_name="Aaron Smith",
|
|
id=999,
|
|
is_mirror_dummy=False,
|
|
),
|
|
]
|
|
|
|
obj = dict(
|
|
recipient_type=Recipient.PERSONAL,
|
|
recipient_type_id=None,
|
|
sender_is_mirror_dummy=False,
|
|
sender_email=cordelia.email,
|
|
sender_full_name=cordelia.full_name,
|
|
sender_id=cordelia.id,
|
|
)
|
|
|
|
MessageDict.hydrate_recipient_info(obj, display_recipient)
|
|
|
|
self.assertEqual(
|
|
obj["display_recipient"],
|
|
[
|
|
dict(
|
|
email="aaron@example.com",
|
|
full_name="Aaron Smith",
|
|
id=999,
|
|
is_mirror_dummy=False,
|
|
),
|
|
dict(
|
|
email=cordelia.email,
|
|
full_name=cordelia.full_name,
|
|
id=cordelia.id,
|
|
is_mirror_dummy=False,
|
|
),
|
|
],
|
|
)
|
|
self.assertEqual(obj["type"], "private")
|
|
|
|
def test_messages_for_ids(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
cordelia = self.example_user("cordelia")
|
|
|
|
stream_name = "test stream"
|
|
self.subscribe(cordelia, stream_name)
|
|
|
|
old_message_id = self.send_stream_message(cordelia, stream_name, content="foo")
|
|
|
|
self.subscribe(hamlet, stream_name)
|
|
|
|
content = "hello @**King Hamlet**"
|
|
new_message_id = self.send_stream_message(cordelia, stream_name, content=content)
|
|
|
|
user_message_flags = {
|
|
old_message_id: ["read", "historical"],
|
|
new_message_id: ["mentioned"],
|
|
}
|
|
|
|
messages = messages_for_ids(
|
|
message_ids=[old_message_id, new_message_id],
|
|
user_message_flags=user_message_flags,
|
|
search_fields={},
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
allow_edit_history=False,
|
|
)
|
|
|
|
self.assert_length(messages, 2)
|
|
|
|
for message in messages:
|
|
if message["id"] == old_message_id:
|
|
old_message = message
|
|
elif message["id"] == new_message_id:
|
|
new_message = message
|
|
|
|
self.assertEqual(old_message["content"], "<p>foo</p>")
|
|
self.assertEqual(old_message["flags"], ["read", "historical"])
|
|
|
|
self.assertIn('class="user-mention"', new_message["content"])
|
|
self.assertEqual(new_message["flags"], ["mentioned"])
|
|
|
|
def test_display_recipient_up_to_date(self) -> None:
|
|
"""
|
|
This is a test for a bug where due to caching of message_dicts,
|
|
after updating a user's information, fetching those cached messages
|
|
via messages_for_ids would return message_dicts with display_recipient
|
|
still having the old information. The returned message_dicts should have
|
|
up-to-date display_recipients and we check for that here.
|
|
"""
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
cordelia = self.example_user("cordelia")
|
|
message_id = self.send_personal_message(hamlet, cordelia, "test")
|
|
|
|
cordelia_recipient = cordelia.recipient
|
|
# Cause the display_recipient to get cached:
|
|
get_display_recipient(cordelia_recipient)
|
|
|
|
# Change cordelia's email:
|
|
cordelia_new_email = "new-cordelia@zulip.com"
|
|
cordelia.email = cordelia_new_email
|
|
cordelia.save()
|
|
|
|
# Local display_recipient cache needs to be flushed.
|
|
# flush_per_request_caches() is called after every request,
|
|
# so it makes sense to run it here.
|
|
flush_per_request_caches()
|
|
|
|
messages = messages_for_ids(
|
|
message_ids=[message_id],
|
|
user_message_flags={message_id: ["read"]},
|
|
search_fields={},
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
allow_edit_history=False,
|
|
)
|
|
message = messages[0]
|
|
|
|
# Find which display_recipient in the list is cordelia:
|
|
for display_recipient in message["display_recipient"]:
|
|
if display_recipient["id"] == cordelia.id:
|
|
cordelia_display_recipient = display_recipient
|
|
|
|
# Make sure the email is up-to-date.
|
|
self.assertEqual(cordelia_display_recipient["email"], cordelia_new_email)
|
|
|
|
|
|
class TestMessageForIdsDisplayRecipientFetching(ZulipTestCase):
|
|
def _verify_display_recipient(
|
|
self,
|
|
display_recipient: DisplayRecipientT,
|
|
expected_recipient_objects: Union[Stream, List[UserProfile]],
|
|
) -> None:
|
|
if isinstance(expected_recipient_objects, Stream):
|
|
self.assertEqual(display_recipient, expected_recipient_objects.name)
|
|
|
|
else:
|
|
for user_profile in expected_recipient_objects:
|
|
recipient_dict: UserDisplayRecipient = {
|
|
"email": user_profile.email,
|
|
"full_name": user_profile.full_name,
|
|
"id": user_profile.id,
|
|
"is_mirror_dummy": user_profile.is_mirror_dummy,
|
|
}
|
|
self.assertTrue(recipient_dict in display_recipient)
|
|
|
|
def test_display_recipient_personal(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
cordelia = self.example_user("cordelia")
|
|
othello = self.example_user("othello")
|
|
message_ids = [
|
|
self.send_personal_message(hamlet, cordelia, "test"),
|
|
self.send_personal_message(cordelia, othello, "test"),
|
|
]
|
|
|
|
messages = messages_for_ids(
|
|
message_ids=message_ids,
|
|
user_message_flags={message_id: ["read"] for message_id in message_ids},
|
|
search_fields={},
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
allow_edit_history=False,
|
|
)
|
|
|
|
self._verify_display_recipient(messages[0]["display_recipient"], [hamlet, cordelia])
|
|
self._verify_display_recipient(messages[1]["display_recipient"], [cordelia, othello])
|
|
|
|
def test_display_recipient_stream(self) -> None:
|
|
cordelia = self.example_user("cordelia")
|
|
message_ids = [
|
|
self.send_stream_message(cordelia, "Verona", content="test"),
|
|
self.send_stream_message(cordelia, "Denmark", content="test"),
|
|
]
|
|
|
|
messages = messages_for_ids(
|
|
message_ids=message_ids,
|
|
user_message_flags={message_id: ["read"] for message_id in message_ids},
|
|
search_fields={},
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
allow_edit_history=False,
|
|
)
|
|
|
|
self._verify_display_recipient(
|
|
messages[0]["display_recipient"], get_stream("Verona", cordelia.realm)
|
|
)
|
|
self._verify_display_recipient(
|
|
messages[1]["display_recipient"], get_stream("Denmark", cordelia.realm)
|
|
)
|
|
|
|
def test_display_recipient_huddle(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
cordelia = self.example_user("cordelia")
|
|
othello = self.example_user("othello")
|
|
iago = self.example_user("iago")
|
|
message_ids = [
|
|
self.send_huddle_message(hamlet, [cordelia, othello], "test"),
|
|
self.send_huddle_message(cordelia, [hamlet, othello, iago], "test"),
|
|
]
|
|
|
|
messages = messages_for_ids(
|
|
message_ids=message_ids,
|
|
user_message_flags={message_id: ["read"] for message_id in message_ids},
|
|
search_fields={},
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
allow_edit_history=False,
|
|
)
|
|
|
|
self._verify_display_recipient(
|
|
messages[0]["display_recipient"], [hamlet, cordelia, othello]
|
|
)
|
|
self._verify_display_recipient(
|
|
messages[1]["display_recipient"], [hamlet, cordelia, othello, iago]
|
|
)
|
|
|
|
def test_display_recipient_various_types(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
cordelia = self.example_user("cordelia")
|
|
othello = self.example_user("othello")
|
|
iago = self.example_user("iago")
|
|
message_ids = [
|
|
self.send_huddle_message(hamlet, [cordelia, othello], "test"),
|
|
self.send_stream_message(cordelia, "Verona", content="test"),
|
|
self.send_personal_message(hamlet, cordelia, "test"),
|
|
self.send_stream_message(cordelia, "Denmark", content="test"),
|
|
self.send_huddle_message(cordelia, [hamlet, othello, iago], "test"),
|
|
self.send_personal_message(cordelia, othello, "test"),
|
|
]
|
|
|
|
messages = messages_for_ids(
|
|
message_ids=message_ids,
|
|
user_message_flags={message_id: ["read"] for message_id in message_ids},
|
|
search_fields={},
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
allow_edit_history=False,
|
|
)
|
|
|
|
self._verify_display_recipient(
|
|
messages[0]["display_recipient"], [hamlet, cordelia, othello]
|
|
)
|
|
self._verify_display_recipient(
|
|
messages[1]["display_recipient"], get_stream("Verona", hamlet.realm)
|
|
)
|
|
self._verify_display_recipient(messages[2]["display_recipient"], [hamlet, cordelia])
|
|
self._verify_display_recipient(
|
|
messages[3]["display_recipient"], get_stream("Denmark", hamlet.realm)
|
|
)
|
|
self._verify_display_recipient(
|
|
messages[4]["display_recipient"], [hamlet, cordelia, othello, iago]
|
|
)
|
|
self._verify_display_recipient(messages[5]["display_recipient"], [cordelia, othello])
|
|
|
|
|
|
class SewMessageAndReactionTest(ZulipTestCase):
|
|
def test_sew_messages_and_reaction(self) -> None:
|
|
sender = self.example_user("othello")
|
|
receiver = self.example_user("hamlet")
|
|
pm_recipient = Recipient.objects.get(type_id=receiver.id, type=Recipient.PERSONAL)
|
|
stream_name = "Çiğdem"
|
|
stream = self.make_stream(stream_name)
|
|
stream_recipient = Recipient.objects.get(type_id=stream.id, type=Recipient.STREAM)
|
|
sending_client = make_client(name="test suite")
|
|
|
|
needed_ids = []
|
|
for i in range(5):
|
|
for recipient in [pm_recipient, stream_recipient]:
|
|
message = Message(
|
|
sender=sender,
|
|
recipient=recipient,
|
|
content=f"whatever {i}",
|
|
date_sent=timezone_now(),
|
|
sending_client=sending_client,
|
|
last_edit_time=timezone_now(),
|
|
edit_history="[]",
|
|
)
|
|
message.set_topic_name("whatever")
|
|
message.save()
|
|
needed_ids.append(message.id)
|
|
reaction = Reaction(user_profile=sender, message=message, emoji_name="simple_smile")
|
|
reaction.save()
|
|
|
|
messages = Message.objects.filter(id__in=needed_ids).values(*["id", "content"])
|
|
reactions = Reaction.get_raw_db_rows(needed_ids)
|
|
tied_data = sew_messages_and_reactions(messages, reactions)
|
|
for data in tied_data:
|
|
self.assert_length(data["reactions"], 1)
|
|
self.assertEqual(data["reactions"][0]["emoji_name"], "simple_smile")
|
|
self.assertTrue(data["id"])
|
|
self.assertTrue(data["content"])
|