mirror of
https://github.com/zulip/zulip.git
synced 2025-11-18 12:54:58 +00:00
tests: Move StreamMessagesTest to test_message_send.py.
StreamMessagesTest test stuff after message is sent to a stream, so moving it out from test_messages.py to test_message_send.py.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from typing import Any, Optional
|
import time
|
||||||
|
from typing import Any, Optional, Set
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import ujson
|
import ujson
|
||||||
@@ -8,23 +9,38 @@ from django.utils.timezone import now as timezone_now
|
|||||||
|
|
||||||
from zerver.decorator import JsonableError
|
from zerver.decorator import JsonableError
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
|
check_send_stream_message,
|
||||||
|
do_change_is_api_super_user,
|
||||||
do_change_stream_post_policy,
|
do_change_stream_post_policy,
|
||||||
do_create_user,
|
do_create_user,
|
||||||
do_deactivate_user,
|
do_deactivate_user,
|
||||||
|
do_send_messages,
|
||||||
do_set_realm_property,
|
do_set_realm_property,
|
||||||
internal_send_stream_message,
|
internal_send_stream_message,
|
||||||
)
|
)
|
||||||
from zerver.lib.message import get_recent_private_conversations
|
from zerver.lib.cache import cache_delete, get_stream_cache_key
|
||||||
|
from zerver.lib.message import MessageDict, get_raw_unread_data, get_recent_private_conversations
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.lib.test_helpers import reset_emails_in_zulip_realm
|
from zerver.lib.test_helpers import (
|
||||||
|
make_client,
|
||||||
|
message_stream_count,
|
||||||
|
most_recent_message,
|
||||||
|
most_recent_usermessage,
|
||||||
|
queries_captured,
|
||||||
|
reset_emails_in_zulip_realm,
|
||||||
|
)
|
||||||
from zerver.lib.timestamp import convert_to_UTC, datetime_to_timestamp
|
from zerver.lib.timestamp import convert_to_UTC, datetime_to_timestamp
|
||||||
from zerver.lib.timezone import get_timezone
|
from zerver.lib.timezone import get_timezone
|
||||||
from zerver.models import (
|
from zerver.models import (
|
||||||
MAX_MESSAGE_LENGTH,
|
MAX_MESSAGE_LENGTH,
|
||||||
MAX_TOPIC_NAME_LENGTH,
|
MAX_TOPIC_NAME_LENGTH,
|
||||||
|
Message,
|
||||||
ScheduledMessage,
|
ScheduledMessage,
|
||||||
Stream,
|
Stream,
|
||||||
|
Subscription,
|
||||||
|
UserMessage,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
|
flush_per_request_caches,
|
||||||
get_huddle_recipient,
|
get_huddle_recipient,
|
||||||
get_realm,
|
get_realm,
|
||||||
get_stream,
|
get_stream,
|
||||||
@@ -1018,3 +1034,349 @@ class ScheduledMessageTest(ZulipTestCase):
|
|||||||
result = self.do_schedule_message('stream', 'Verona',
|
result = self.do_schedule_message('stream', 'Verona',
|
||||||
content + ' 1')
|
content + ' 1')
|
||||||
self.assert_json_error(result, 'Missing deliver_at in a request for delayed message delivery')
|
self.assert_json_error(result, 'Missing deliver_at in a request for delayed message delivery')
|
||||||
|
|
||||||
|
class StreamMessagesTest(ZulipTestCase):
|
||||||
|
|
||||||
|
def assert_stream_message(self, stream_name: str, topic_name: str="test topic",
|
||||||
|
content: str="test content") -> None:
|
||||||
|
"""
|
||||||
|
Check that messages sent to a stream reach all subscribers to that stream.
|
||||||
|
"""
|
||||||
|
realm = get_realm('zulip')
|
||||||
|
subscribers = self.users_subscribed_to_stream(stream_name, realm)
|
||||||
|
|
||||||
|
# Outgoing webhook bots don't store UserMessage rows; they will be processed later.
|
||||||
|
subscribers = [subscriber for subscriber in subscribers
|
||||||
|
if subscriber.bot_type != UserProfile.OUTGOING_WEBHOOK_BOT]
|
||||||
|
|
||||||
|
old_subscriber_messages = []
|
||||||
|
for subscriber in subscribers:
|
||||||
|
old_subscriber_messages.append(message_stream_count(subscriber))
|
||||||
|
|
||||||
|
non_subscribers = [user_profile for user_profile in UserProfile.objects.all()
|
||||||
|
if user_profile not in subscribers]
|
||||||
|
old_non_subscriber_messages = []
|
||||||
|
for non_subscriber in non_subscribers:
|
||||||
|
old_non_subscriber_messages.append(message_stream_count(non_subscriber))
|
||||||
|
|
||||||
|
non_bot_subscribers = [user_profile for user_profile in subscribers
|
||||||
|
if not user_profile.is_bot]
|
||||||
|
a_subscriber = non_bot_subscribers[0]
|
||||||
|
self.login_user(a_subscriber)
|
||||||
|
self.send_stream_message(a_subscriber, stream_name,
|
||||||
|
content=content, topic_name=topic_name)
|
||||||
|
|
||||||
|
# Did all of the subscribers get the message?
|
||||||
|
new_subscriber_messages = []
|
||||||
|
for subscriber in subscribers:
|
||||||
|
new_subscriber_messages.append(message_stream_count(subscriber))
|
||||||
|
|
||||||
|
# Did non-subscribers not get the message?
|
||||||
|
new_non_subscriber_messages = []
|
||||||
|
for non_subscriber in non_subscribers:
|
||||||
|
new_non_subscriber_messages.append(message_stream_count(non_subscriber))
|
||||||
|
|
||||||
|
self.assertEqual(old_non_subscriber_messages, new_non_subscriber_messages)
|
||||||
|
self.assertEqual(new_subscriber_messages, [elt + 1 for elt in old_subscriber_messages])
|
||||||
|
|
||||||
|
def test_performance(self) -> None:
|
||||||
|
'''
|
||||||
|
This test is part of the automated test suite, but
|
||||||
|
it is more intended as an aid to measuring the
|
||||||
|
performance of do_send_messages() with consistent
|
||||||
|
data setup across different commits. You can modify
|
||||||
|
the values below and run just this test, and then
|
||||||
|
comment out the print statement toward the bottom.
|
||||||
|
'''
|
||||||
|
num_messages = 2
|
||||||
|
num_extra_users = 10
|
||||||
|
|
||||||
|
sender = self.example_user('cordelia')
|
||||||
|
realm = sender.realm
|
||||||
|
message_content = 'whatever'
|
||||||
|
stream = get_stream('Denmark', realm)
|
||||||
|
topic_name = 'lunch'
|
||||||
|
recipient = stream.recipient
|
||||||
|
sending_client = make_client(name="test suite")
|
||||||
|
|
||||||
|
for i in range(num_extra_users):
|
||||||
|
# Make every other user be idle.
|
||||||
|
long_term_idle = i % 2 > 0
|
||||||
|
|
||||||
|
email = f'foo{i}@example.com'
|
||||||
|
user = UserProfile.objects.create(
|
||||||
|
realm=realm,
|
||||||
|
email=email,
|
||||||
|
long_term_idle=long_term_idle,
|
||||||
|
)
|
||||||
|
Subscription.objects.create(
|
||||||
|
user_profile=user,
|
||||||
|
recipient=recipient,
|
||||||
|
)
|
||||||
|
|
||||||
|
def send_test_message() -> None:
|
||||||
|
message = Message(
|
||||||
|
sender=sender,
|
||||||
|
recipient=recipient,
|
||||||
|
content=message_content,
|
||||||
|
date_sent=timezone_now(),
|
||||||
|
sending_client=sending_client,
|
||||||
|
)
|
||||||
|
message.set_topic_name(topic_name)
|
||||||
|
do_send_messages([dict(message=message)])
|
||||||
|
|
||||||
|
before_um_count = UserMessage.objects.count()
|
||||||
|
|
||||||
|
t = time.time()
|
||||||
|
for i in range(num_messages):
|
||||||
|
send_test_message()
|
||||||
|
|
||||||
|
delay = time.time() - t
|
||||||
|
assert(delay) # quiet down lint
|
||||||
|
# print(delay)
|
||||||
|
|
||||||
|
after_um_count = UserMessage.objects.count()
|
||||||
|
ums_created = after_um_count - before_um_count
|
||||||
|
|
||||||
|
num_active_users = num_extra_users / 2
|
||||||
|
self.assertTrue(ums_created > (num_active_users * num_messages))
|
||||||
|
|
||||||
|
def test_not_too_many_queries(self) -> None:
|
||||||
|
recipient_list = [self.example_user("hamlet"), self.example_user("iago"),
|
||||||
|
self.example_user("cordelia"), self.example_user("othello")]
|
||||||
|
for user_profile in recipient_list:
|
||||||
|
self.subscribe(user_profile, "Denmark")
|
||||||
|
|
||||||
|
sender = self.example_user('hamlet')
|
||||||
|
sending_client = make_client(name="test suite")
|
||||||
|
stream_name = 'Denmark'
|
||||||
|
topic_name = 'foo'
|
||||||
|
content = 'whatever'
|
||||||
|
realm = sender.realm
|
||||||
|
|
||||||
|
# To get accurate count of the queries, we should make sure that
|
||||||
|
# caches don't come into play. If we count queries while caches are
|
||||||
|
# filled, we will get a lower count. Caches are not supposed to be
|
||||||
|
# persistent, so our test can also fail if cache is invalidated
|
||||||
|
# during the course of the unit test.
|
||||||
|
flush_per_request_caches()
|
||||||
|
cache_delete(get_stream_cache_key(stream_name, realm.id))
|
||||||
|
with queries_captured() as queries:
|
||||||
|
check_send_stream_message(
|
||||||
|
sender=sender,
|
||||||
|
client=sending_client,
|
||||||
|
stream_name=stream_name,
|
||||||
|
topic=topic_name,
|
||||||
|
body=content,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_length(queries, 14)
|
||||||
|
|
||||||
|
def test_stream_message_dict(self) -> None:
|
||||||
|
user_profile = self.example_user('iago')
|
||||||
|
self.subscribe(user_profile, "Denmark")
|
||||||
|
self.send_stream_message(self.example_user("hamlet"), "Denmark",
|
||||||
|
content="whatever", topic_name="my topic")
|
||||||
|
message = most_recent_message(user_profile)
|
||||||
|
row = MessageDict.get_raw_db_rows([message.id])[0]
|
||||||
|
dct = MessageDict.build_dict_from_raw_db_row(row)
|
||||||
|
MessageDict.post_process_dicts([dct], apply_markdown=True, client_gravatar=False)
|
||||||
|
self.assertEqual(dct['display_recipient'], 'Denmark')
|
||||||
|
|
||||||
|
stream = get_stream('Denmark', user_profile.realm)
|
||||||
|
self.assertEqual(dct['stream_id'], stream.id)
|
||||||
|
|
||||||
|
def test_stream_message_unicode(self) -> None:
|
||||||
|
receiving_user_profile = self.example_user('iago')
|
||||||
|
sender = self.example_user('hamlet')
|
||||||
|
self.subscribe(receiving_user_profile, "Denmark")
|
||||||
|
self.send_stream_message(sender, "Denmark",
|
||||||
|
content="whatever", topic_name="my topic")
|
||||||
|
message = most_recent_message(receiving_user_profile)
|
||||||
|
self.assertEqual(str(message),
|
||||||
|
'<Message: Denmark / my topic / '
|
||||||
|
'<UserProfile: {} {}>>'.format(sender.email, sender.realm))
|
||||||
|
|
||||||
|
def test_message_mentions(self) -> None:
|
||||||
|
user_profile = self.example_user('iago')
|
||||||
|
self.subscribe(user_profile, "Denmark")
|
||||||
|
self.send_stream_message(self.example_user("hamlet"), "Denmark",
|
||||||
|
content="test @**Iago** rules")
|
||||||
|
message = most_recent_message(user_profile)
|
||||||
|
assert(UserMessage.objects.get(user_profile=user_profile, message=message).flags.mentioned.is_set)
|
||||||
|
|
||||||
|
def test_is_private_flag(self) -> None:
|
||||||
|
user_profile = self.example_user('iago')
|
||||||
|
self.subscribe(user_profile, "Denmark")
|
||||||
|
|
||||||
|
self.send_stream_message(self.example_user("hamlet"), "Denmark",
|
||||||
|
content="test")
|
||||||
|
message = most_recent_message(user_profile)
|
||||||
|
self.assertFalse(UserMessage.objects.get(user_profile=user_profile, message=message).flags.is_private.is_set)
|
||||||
|
|
||||||
|
self.send_personal_message(self.example_user("hamlet"), user_profile,
|
||||||
|
content="test")
|
||||||
|
message = most_recent_message(user_profile)
|
||||||
|
self.assertTrue(UserMessage.objects.get(user_profile=user_profile, message=message).flags.is_private.is_set)
|
||||||
|
|
||||||
|
def _send_stream_message(self, user: UserProfile, stream_name: str, content: str) -> Set[int]:
|
||||||
|
with mock.patch('zerver.lib.actions.send_event') as m:
|
||||||
|
self.send_stream_message(
|
||||||
|
user,
|
||||||
|
stream_name,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
self.assertEqual(m.call_count, 1)
|
||||||
|
users = m.call_args[0][2]
|
||||||
|
user_ids = {u['id'] for u in users}
|
||||||
|
return user_ids
|
||||||
|
|
||||||
|
def test_unsub_mention(self) -> None:
|
||||||
|
cordelia = self.example_user('cordelia')
|
||||||
|
hamlet = self.example_user('hamlet')
|
||||||
|
|
||||||
|
stream_name = 'Test Stream'
|
||||||
|
|
||||||
|
self.subscribe(hamlet, stream_name)
|
||||||
|
|
||||||
|
UserMessage.objects.filter(
|
||||||
|
user_profile=cordelia,
|
||||||
|
).delete()
|
||||||
|
|
||||||
|
def mention_cordelia() -> Set[int]:
|
||||||
|
content = 'test @**Cordelia Lear** rules'
|
||||||
|
|
||||||
|
user_ids = self._send_stream_message(
|
||||||
|
user=hamlet,
|
||||||
|
stream_name=stream_name,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
return user_ids
|
||||||
|
|
||||||
|
def num_cordelia_messages() -> int:
|
||||||
|
return UserMessage.objects.filter(
|
||||||
|
user_profile=cordelia,
|
||||||
|
).count()
|
||||||
|
|
||||||
|
user_ids = mention_cordelia()
|
||||||
|
self.assertEqual(0, num_cordelia_messages())
|
||||||
|
self.assertNotIn(cordelia.id, user_ids)
|
||||||
|
|
||||||
|
# Make sure test isn't too brittle-subscribing
|
||||||
|
# Cordelia and mentioning her should give her a
|
||||||
|
# message.
|
||||||
|
self.subscribe(cordelia, stream_name)
|
||||||
|
user_ids = mention_cordelia()
|
||||||
|
self.assertIn(cordelia.id, user_ids)
|
||||||
|
self.assertEqual(1, num_cordelia_messages())
|
||||||
|
|
||||||
|
def test_message_bot_mentions(self) -> None:
|
||||||
|
cordelia = self.example_user('cordelia')
|
||||||
|
hamlet = self.example_user('hamlet')
|
||||||
|
realm = hamlet.realm
|
||||||
|
|
||||||
|
stream_name = 'Test Stream'
|
||||||
|
|
||||||
|
self.subscribe(hamlet, stream_name)
|
||||||
|
|
||||||
|
normal_bot = do_create_user(
|
||||||
|
email='normal-bot@zulip.com',
|
||||||
|
password='',
|
||||||
|
realm=realm,
|
||||||
|
full_name='Normal Bot',
|
||||||
|
short_name='',
|
||||||
|
bot_type=UserProfile.DEFAULT_BOT,
|
||||||
|
bot_owner=cordelia,
|
||||||
|
)
|
||||||
|
|
||||||
|
content = 'test @**Normal Bot** rules'
|
||||||
|
|
||||||
|
user_ids = self._send_stream_message(
|
||||||
|
user=hamlet,
|
||||||
|
stream_name=stream_name,
|
||||||
|
content=content,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn(normal_bot.id, user_ids)
|
||||||
|
user_message = most_recent_usermessage(normal_bot)
|
||||||
|
self.assertEqual(user_message.message.content, content)
|
||||||
|
self.assertTrue(user_message.flags.mentioned)
|
||||||
|
|
||||||
|
def test_stream_message_mirroring(self) -> None:
|
||||||
|
user = self.mit_user('starnine')
|
||||||
|
self.subscribe(user, 'Verona')
|
||||||
|
|
||||||
|
do_change_is_api_super_user(user, True)
|
||||||
|
result = self.api_post(user, "/api/v1/messages", {"type": "stream",
|
||||||
|
"to": "Verona",
|
||||||
|
"sender": self.mit_email("sipbtest"),
|
||||||
|
"client": "zephyr_mirror",
|
||||||
|
"topic": "announcement",
|
||||||
|
"content": "Everyone knows Iago rules",
|
||||||
|
"forged": "true"},
|
||||||
|
subdomain="zephyr")
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
do_change_is_api_super_user(user, False)
|
||||||
|
result = self.api_post(user, "/api/v1/messages", {"type": "stream",
|
||||||
|
"to": "Verona",
|
||||||
|
"sender": self.mit_email("sipbtest"),
|
||||||
|
"client": "zephyr_mirror",
|
||||||
|
"topic": "announcement",
|
||||||
|
"content": "Everyone knows Iago rules",
|
||||||
|
"forged": "true"},
|
||||||
|
subdomain="zephyr")
|
||||||
|
self.assert_json_error(result, "User not authorized for this query")
|
||||||
|
|
||||||
|
def test_message_to_stream(self) -> None:
|
||||||
|
"""
|
||||||
|
If you send a message to a stream, everyone subscribed to the stream
|
||||||
|
receives the messages.
|
||||||
|
"""
|
||||||
|
self.assert_stream_message("Scotland")
|
||||||
|
|
||||||
|
def test_non_ascii_stream_message(self) -> None:
|
||||||
|
"""
|
||||||
|
Sending a stream message containing non-ASCII characters in the stream
|
||||||
|
name, topic, or message body succeeds.
|
||||||
|
"""
|
||||||
|
self.login('hamlet')
|
||||||
|
|
||||||
|
# Subscribe everyone to a stream with non-ASCII characters.
|
||||||
|
non_ascii_stream_name = "hümbüǵ"
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
stream = self.make_stream(non_ascii_stream_name)
|
||||||
|
for user_profile in UserProfile.objects.filter(is_active=True, is_bot=False,
|
||||||
|
realm=realm)[0:3]:
|
||||||
|
self.subscribe(user_profile, stream.name)
|
||||||
|
|
||||||
|
self.assert_stream_message(non_ascii_stream_name, topic_name="hümbüǵ",
|
||||||
|
content="hümbüǵ")
|
||||||
|
|
||||||
|
def test_get_raw_unread_data_for_huddle_messages(self) -> None:
|
||||||
|
users = [
|
||||||
|
self.example_user('hamlet'),
|
||||||
|
self.example_user('cordelia'),
|
||||||
|
self.example_user('iago'),
|
||||||
|
self.example_user('prospero'),
|
||||||
|
self.example_user('othello'),
|
||||||
|
]
|
||||||
|
|
||||||
|
message1_id = self.send_huddle_message(users[0], users, "test content 1")
|
||||||
|
message2_id = self.send_huddle_message(users[0], users, "test content 2")
|
||||||
|
|
||||||
|
msg_data = get_raw_unread_data(users[1])
|
||||||
|
|
||||||
|
# both the messages are present in msg_data
|
||||||
|
self.assertIn(message1_id, msg_data["huddle_dict"].keys())
|
||||||
|
self.assertIn(message2_id, msg_data["huddle_dict"].keys())
|
||||||
|
|
||||||
|
# only these two messages are present in msg_data
|
||||||
|
self.assertEqual(len(msg_data["huddle_dict"].keys()), 2)
|
||||||
|
|
||||||
|
recent_conversations = get_recent_private_conversations(users[1])
|
||||||
|
self.assertEqual(len(recent_conversations), 1)
|
||||||
|
recent_conversation = list(recent_conversations.values())[0]
|
||||||
|
self.assertEqual(set(recent_conversation['user_ids']), {user.id for user in users if
|
||||||
|
user != users[1]})
|
||||||
|
self.assertEqual(recent_conversation['max_message_id'], message2_id)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
from typing import Any, Dict, List, Set, Union
|
from typing import Any, Dict, List, Union
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import ujson
|
import ujson
|
||||||
@@ -15,13 +15,10 @@ from analytics.models import RealmCount
|
|||||||
from zerver.decorator import JsonableError
|
from zerver.decorator import JsonableError
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
check_message,
|
check_message,
|
||||||
check_send_stream_message,
|
|
||||||
do_add_alert_words,
|
do_add_alert_words,
|
||||||
do_change_is_api_super_user,
|
|
||||||
do_change_stream_invite_only,
|
do_change_stream_invite_only,
|
||||||
do_claim_attachments,
|
do_claim_attachments,
|
||||||
do_create_user,
|
do_create_user,
|
||||||
do_send_messages,
|
|
||||||
do_set_realm_property,
|
do_set_realm_property,
|
||||||
do_update_message,
|
do_update_message,
|
||||||
extract_private_recipients,
|
extract_private_recipients,
|
||||||
@@ -39,15 +36,13 @@ from zerver.lib.actions import (
|
|||||||
send_rate_limited_pm_notification_to_bot_owner,
|
send_rate_limited_pm_notification_to_bot_owner,
|
||||||
)
|
)
|
||||||
from zerver.lib.addressee import Addressee
|
from zerver.lib.addressee import Addressee
|
||||||
from zerver.lib.cache import cache_delete, get_stream_cache_key, to_dict_cache_key_id
|
from zerver.lib.cache import cache_delete, to_dict_cache_key_id
|
||||||
from zerver.lib.markdown import MentionData
|
from zerver.lib.markdown import MentionData
|
||||||
from zerver.lib.markdown import version as markdown_version
|
from zerver.lib.markdown import version as markdown_version
|
||||||
from zerver.lib.message import (
|
from zerver.lib.message import (
|
||||||
MessageDict,
|
MessageDict,
|
||||||
bulk_access_messages,
|
bulk_access_messages,
|
||||||
get_first_visible_message_id,
|
get_first_visible_message_id,
|
||||||
get_raw_unread_data,
|
|
||||||
get_recent_private_conversations,
|
|
||||||
maybe_update_first_visible_message_id,
|
maybe_update_first_visible_message_id,
|
||||||
messages_for_ids,
|
messages_for_ids,
|
||||||
render_markdown,
|
render_markdown,
|
||||||
@@ -651,352 +646,6 @@ class PersonalMessagesTest(ZulipTestCase):
|
|||||||
content="hümbüǵ",
|
content="hümbüǵ",
|
||||||
)
|
)
|
||||||
|
|
||||||
class StreamMessagesTest(ZulipTestCase):
|
|
||||||
|
|
||||||
def assert_stream_message(self, stream_name: str, topic_name: str="test topic",
|
|
||||||
content: str="test content") -> None:
|
|
||||||
"""
|
|
||||||
Check that messages sent to a stream reach all subscribers to that stream.
|
|
||||||
"""
|
|
||||||
realm = get_realm('zulip')
|
|
||||||
subscribers = self.users_subscribed_to_stream(stream_name, realm)
|
|
||||||
|
|
||||||
# Outgoing webhook bots don't store UserMessage rows; they will be processed later.
|
|
||||||
subscribers = [subscriber for subscriber in subscribers
|
|
||||||
if subscriber.bot_type != UserProfile.OUTGOING_WEBHOOK_BOT]
|
|
||||||
|
|
||||||
old_subscriber_messages = []
|
|
||||||
for subscriber in subscribers:
|
|
||||||
old_subscriber_messages.append(message_stream_count(subscriber))
|
|
||||||
|
|
||||||
non_subscribers = [user_profile for user_profile in UserProfile.objects.all()
|
|
||||||
if user_profile not in subscribers]
|
|
||||||
old_non_subscriber_messages = []
|
|
||||||
for non_subscriber in non_subscribers:
|
|
||||||
old_non_subscriber_messages.append(message_stream_count(non_subscriber))
|
|
||||||
|
|
||||||
non_bot_subscribers = [user_profile for user_profile in subscribers
|
|
||||||
if not user_profile.is_bot]
|
|
||||||
a_subscriber = non_bot_subscribers[0]
|
|
||||||
self.login_user(a_subscriber)
|
|
||||||
self.send_stream_message(a_subscriber, stream_name,
|
|
||||||
content=content, topic_name=topic_name)
|
|
||||||
|
|
||||||
# Did all of the subscribers get the message?
|
|
||||||
new_subscriber_messages = []
|
|
||||||
for subscriber in subscribers:
|
|
||||||
new_subscriber_messages.append(message_stream_count(subscriber))
|
|
||||||
|
|
||||||
# Did non-subscribers not get the message?
|
|
||||||
new_non_subscriber_messages = []
|
|
||||||
for non_subscriber in non_subscribers:
|
|
||||||
new_non_subscriber_messages.append(message_stream_count(non_subscriber))
|
|
||||||
|
|
||||||
self.assertEqual(old_non_subscriber_messages, new_non_subscriber_messages)
|
|
||||||
self.assertEqual(new_subscriber_messages, [elt + 1 for elt in old_subscriber_messages])
|
|
||||||
|
|
||||||
def test_performance(self) -> None:
|
|
||||||
'''
|
|
||||||
This test is part of the automated test suite, but
|
|
||||||
it is more intended as an aid to measuring the
|
|
||||||
performance of do_send_messages() with consistent
|
|
||||||
data setup across different commits. You can modify
|
|
||||||
the values below and run just this test, and then
|
|
||||||
comment out the print statement toward the bottom.
|
|
||||||
'''
|
|
||||||
num_messages = 2
|
|
||||||
num_extra_users = 10
|
|
||||||
|
|
||||||
sender = self.example_user('cordelia')
|
|
||||||
realm = sender.realm
|
|
||||||
message_content = 'whatever'
|
|
||||||
stream = get_stream('Denmark', realm)
|
|
||||||
topic_name = 'lunch'
|
|
||||||
recipient = stream.recipient
|
|
||||||
sending_client = make_client(name="test suite")
|
|
||||||
|
|
||||||
for i in range(num_extra_users):
|
|
||||||
# Make every other user be idle.
|
|
||||||
long_term_idle = i % 2 > 0
|
|
||||||
|
|
||||||
email = f'foo{i}@example.com'
|
|
||||||
user = UserProfile.objects.create(
|
|
||||||
realm=realm,
|
|
||||||
email=email,
|
|
||||||
long_term_idle=long_term_idle,
|
|
||||||
)
|
|
||||||
Subscription.objects.create(
|
|
||||||
user_profile=user,
|
|
||||||
recipient=recipient,
|
|
||||||
)
|
|
||||||
|
|
||||||
def send_test_message() -> None:
|
|
||||||
message = Message(
|
|
||||||
sender=sender,
|
|
||||||
recipient=recipient,
|
|
||||||
content=message_content,
|
|
||||||
date_sent=timezone_now(),
|
|
||||||
sending_client=sending_client,
|
|
||||||
)
|
|
||||||
message.set_topic_name(topic_name)
|
|
||||||
do_send_messages([dict(message=message)])
|
|
||||||
|
|
||||||
before_um_count = UserMessage.objects.count()
|
|
||||||
|
|
||||||
t = time.time()
|
|
||||||
for i in range(num_messages):
|
|
||||||
send_test_message()
|
|
||||||
|
|
||||||
delay = time.time() - t
|
|
||||||
assert(delay) # quiet down lint
|
|
||||||
# print(delay)
|
|
||||||
|
|
||||||
after_um_count = UserMessage.objects.count()
|
|
||||||
ums_created = after_um_count - before_um_count
|
|
||||||
|
|
||||||
num_active_users = num_extra_users / 2
|
|
||||||
self.assertTrue(ums_created > (num_active_users * num_messages))
|
|
||||||
|
|
||||||
def test_not_too_many_queries(self) -> None:
|
|
||||||
recipient_list = [self.example_user("hamlet"), self.example_user("iago"),
|
|
||||||
self.example_user("cordelia"), self.example_user("othello")]
|
|
||||||
for user_profile in recipient_list:
|
|
||||||
self.subscribe(user_profile, "Denmark")
|
|
||||||
|
|
||||||
sender = self.example_user('hamlet')
|
|
||||||
sending_client = make_client(name="test suite")
|
|
||||||
stream_name = 'Denmark'
|
|
||||||
topic_name = 'foo'
|
|
||||||
content = 'whatever'
|
|
||||||
realm = sender.realm
|
|
||||||
|
|
||||||
# To get accurate count of the queries, we should make sure that
|
|
||||||
# caches don't come into play. If we count queries while caches are
|
|
||||||
# filled, we will get a lower count. Caches are not supposed to be
|
|
||||||
# persistent, so our test can also fail if cache is invalidated
|
|
||||||
# during the course of the unit test.
|
|
||||||
flush_per_request_caches()
|
|
||||||
cache_delete(get_stream_cache_key(stream_name, realm.id))
|
|
||||||
with queries_captured() as queries:
|
|
||||||
check_send_stream_message(
|
|
||||||
sender=sender,
|
|
||||||
client=sending_client,
|
|
||||||
stream_name=stream_name,
|
|
||||||
topic=topic_name,
|
|
||||||
body=content,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assert_length(queries, 14)
|
|
||||||
|
|
||||||
def test_stream_message_dict(self) -> None:
|
|
||||||
user_profile = self.example_user('iago')
|
|
||||||
self.subscribe(user_profile, "Denmark")
|
|
||||||
self.send_stream_message(self.example_user("hamlet"), "Denmark",
|
|
||||||
content="whatever", topic_name="my topic")
|
|
||||||
message = most_recent_message(user_profile)
|
|
||||||
row = MessageDict.get_raw_db_rows([message.id])[0]
|
|
||||||
dct = MessageDict.build_dict_from_raw_db_row(row)
|
|
||||||
MessageDict.post_process_dicts([dct], apply_markdown=True, client_gravatar=False)
|
|
||||||
self.assertEqual(dct['display_recipient'], 'Denmark')
|
|
||||||
|
|
||||||
stream = get_stream('Denmark', user_profile.realm)
|
|
||||||
self.assertEqual(dct['stream_id'], stream.id)
|
|
||||||
|
|
||||||
def test_stream_message_unicode(self) -> None:
|
|
||||||
receiving_user_profile = self.example_user('iago')
|
|
||||||
sender = self.example_user('hamlet')
|
|
||||||
self.subscribe(receiving_user_profile, "Denmark")
|
|
||||||
self.send_stream_message(sender, "Denmark",
|
|
||||||
content="whatever", topic_name="my topic")
|
|
||||||
message = most_recent_message(receiving_user_profile)
|
|
||||||
self.assertEqual(str(message),
|
|
||||||
'<Message: Denmark / my topic / '
|
|
||||||
'<UserProfile: {} {}>>'.format(sender.email, sender.realm))
|
|
||||||
|
|
||||||
def test_message_mentions(self) -> None:
|
|
||||||
user_profile = self.example_user('iago')
|
|
||||||
self.subscribe(user_profile, "Denmark")
|
|
||||||
self.send_stream_message(self.example_user("hamlet"), "Denmark",
|
|
||||||
content="test @**Iago** rules")
|
|
||||||
message = most_recent_message(user_profile)
|
|
||||||
assert(UserMessage.objects.get(user_profile=user_profile, message=message).flags.mentioned.is_set)
|
|
||||||
|
|
||||||
def test_is_private_flag(self) -> None:
|
|
||||||
user_profile = self.example_user('iago')
|
|
||||||
self.subscribe(user_profile, "Denmark")
|
|
||||||
|
|
||||||
self.send_stream_message(self.example_user("hamlet"), "Denmark",
|
|
||||||
content="test")
|
|
||||||
message = most_recent_message(user_profile)
|
|
||||||
self.assertFalse(UserMessage.objects.get(user_profile=user_profile, message=message).flags.is_private.is_set)
|
|
||||||
|
|
||||||
self.send_personal_message(self.example_user("hamlet"), user_profile,
|
|
||||||
content="test")
|
|
||||||
message = most_recent_message(user_profile)
|
|
||||||
self.assertTrue(UserMessage.objects.get(user_profile=user_profile, message=message).flags.is_private.is_set)
|
|
||||||
|
|
||||||
def _send_stream_message(self, user: UserProfile, stream_name: str, content: str) -> Set[int]:
|
|
||||||
with mock.patch('zerver.lib.actions.send_event') as m:
|
|
||||||
self.send_stream_message(
|
|
||||||
user,
|
|
||||||
stream_name,
|
|
||||||
content=content,
|
|
||||||
)
|
|
||||||
self.assertEqual(m.call_count, 1)
|
|
||||||
users = m.call_args[0][2]
|
|
||||||
user_ids = {u['id'] for u in users}
|
|
||||||
return user_ids
|
|
||||||
|
|
||||||
def test_unsub_mention(self) -> None:
|
|
||||||
cordelia = self.example_user('cordelia')
|
|
||||||
hamlet = self.example_user('hamlet')
|
|
||||||
|
|
||||||
stream_name = 'Test Stream'
|
|
||||||
|
|
||||||
self.subscribe(hamlet, stream_name)
|
|
||||||
|
|
||||||
UserMessage.objects.filter(
|
|
||||||
user_profile=cordelia,
|
|
||||||
).delete()
|
|
||||||
|
|
||||||
def mention_cordelia() -> Set[int]:
|
|
||||||
content = 'test @**Cordelia Lear** rules'
|
|
||||||
|
|
||||||
user_ids = self._send_stream_message(
|
|
||||||
user=hamlet,
|
|
||||||
stream_name=stream_name,
|
|
||||||
content=content,
|
|
||||||
)
|
|
||||||
return user_ids
|
|
||||||
|
|
||||||
def num_cordelia_messages() -> int:
|
|
||||||
return UserMessage.objects.filter(
|
|
||||||
user_profile=cordelia,
|
|
||||||
).count()
|
|
||||||
|
|
||||||
user_ids = mention_cordelia()
|
|
||||||
self.assertEqual(0, num_cordelia_messages())
|
|
||||||
self.assertNotIn(cordelia.id, user_ids)
|
|
||||||
|
|
||||||
# Make sure test isn't too brittle-subscribing
|
|
||||||
# Cordelia and mentioning her should give her a
|
|
||||||
# message.
|
|
||||||
self.subscribe(cordelia, stream_name)
|
|
||||||
user_ids = mention_cordelia()
|
|
||||||
self.assertIn(cordelia.id, user_ids)
|
|
||||||
self.assertEqual(1, num_cordelia_messages())
|
|
||||||
|
|
||||||
def test_message_bot_mentions(self) -> None:
|
|
||||||
cordelia = self.example_user('cordelia')
|
|
||||||
hamlet = self.example_user('hamlet')
|
|
||||||
realm = hamlet.realm
|
|
||||||
|
|
||||||
stream_name = 'Test Stream'
|
|
||||||
|
|
||||||
self.subscribe(hamlet, stream_name)
|
|
||||||
|
|
||||||
normal_bot = do_create_user(
|
|
||||||
email='normal-bot@zulip.com',
|
|
||||||
password='',
|
|
||||||
realm=realm,
|
|
||||||
full_name='Normal Bot',
|
|
||||||
short_name='',
|
|
||||||
bot_type=UserProfile.DEFAULT_BOT,
|
|
||||||
bot_owner=cordelia,
|
|
||||||
)
|
|
||||||
|
|
||||||
content = 'test @**Normal Bot** rules'
|
|
||||||
|
|
||||||
user_ids = self._send_stream_message(
|
|
||||||
user=hamlet,
|
|
||||||
stream_name=stream_name,
|
|
||||||
content=content,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertIn(normal_bot.id, user_ids)
|
|
||||||
user_message = most_recent_usermessage(normal_bot)
|
|
||||||
self.assertEqual(user_message.message.content, content)
|
|
||||||
self.assertTrue(user_message.flags.mentioned)
|
|
||||||
|
|
||||||
def test_stream_message_mirroring(self) -> None:
|
|
||||||
user = self.mit_user('starnine')
|
|
||||||
self.subscribe(user, 'Verona')
|
|
||||||
|
|
||||||
do_change_is_api_super_user(user, True)
|
|
||||||
result = self.api_post(user, "/api/v1/messages", {"type": "stream",
|
|
||||||
"to": "Verona",
|
|
||||||
"sender": self.mit_email("sipbtest"),
|
|
||||||
"client": "zephyr_mirror",
|
|
||||||
"topic": "announcement",
|
|
||||||
"content": "Everyone knows Iago rules",
|
|
||||||
"forged": "true"},
|
|
||||||
subdomain="zephyr")
|
|
||||||
self.assert_json_success(result)
|
|
||||||
|
|
||||||
do_change_is_api_super_user(user, False)
|
|
||||||
result = self.api_post(user, "/api/v1/messages", {"type": "stream",
|
|
||||||
"to": "Verona",
|
|
||||||
"sender": self.mit_email("sipbtest"),
|
|
||||||
"client": "zephyr_mirror",
|
|
||||||
"topic": "announcement",
|
|
||||||
"content": "Everyone knows Iago rules",
|
|
||||||
"forged": "true"},
|
|
||||||
subdomain="zephyr")
|
|
||||||
self.assert_json_error(result, "User not authorized for this query")
|
|
||||||
|
|
||||||
def test_message_to_stream(self) -> None:
|
|
||||||
"""
|
|
||||||
If you send a message to a stream, everyone subscribed to the stream
|
|
||||||
receives the messages.
|
|
||||||
"""
|
|
||||||
self.assert_stream_message("Scotland")
|
|
||||||
|
|
||||||
def test_non_ascii_stream_message(self) -> None:
|
|
||||||
"""
|
|
||||||
Sending a stream message containing non-ASCII characters in the stream
|
|
||||||
name, topic, or message body succeeds.
|
|
||||||
"""
|
|
||||||
self.login('hamlet')
|
|
||||||
|
|
||||||
# Subscribe everyone to a stream with non-ASCII characters.
|
|
||||||
non_ascii_stream_name = "hümbüǵ"
|
|
||||||
realm = get_realm("zulip")
|
|
||||||
stream = self.make_stream(non_ascii_stream_name)
|
|
||||||
for user_profile in UserProfile.objects.filter(is_active=True, is_bot=False,
|
|
||||||
realm=realm)[0:3]:
|
|
||||||
self.subscribe(user_profile, stream.name)
|
|
||||||
|
|
||||||
self.assert_stream_message(non_ascii_stream_name, topic_name="hümbüǵ",
|
|
||||||
content="hümbüǵ")
|
|
||||||
|
|
||||||
def test_get_raw_unread_data_for_huddle_messages(self) -> None:
|
|
||||||
users = [
|
|
||||||
self.example_user('hamlet'),
|
|
||||||
self.example_user('cordelia'),
|
|
||||||
self.example_user('iago'),
|
|
||||||
self.example_user('prospero'),
|
|
||||||
self.example_user('othello'),
|
|
||||||
]
|
|
||||||
|
|
||||||
message1_id = self.send_huddle_message(users[0], users, "test content 1")
|
|
||||||
message2_id = self.send_huddle_message(users[0], users, "test content 2")
|
|
||||||
|
|
||||||
msg_data = get_raw_unread_data(users[1])
|
|
||||||
|
|
||||||
# both the messages are present in msg_data
|
|
||||||
self.assertIn(message1_id, msg_data["huddle_dict"].keys())
|
|
||||||
self.assertIn(message2_id, msg_data["huddle_dict"].keys())
|
|
||||||
|
|
||||||
# only these two messages are present in msg_data
|
|
||||||
self.assertEqual(len(msg_data["huddle_dict"].keys()), 2)
|
|
||||||
|
|
||||||
recent_conversations = get_recent_private_conversations(users[1])
|
|
||||||
self.assertEqual(len(recent_conversations), 1)
|
|
||||||
recent_conversation = list(recent_conversations.values())[0]
|
|
||||||
self.assertEqual(set(recent_conversation['user_ids']), {user.id for user in users if
|
|
||||||
user != users[1]})
|
|
||||||
self.assertEqual(recent_conversation['max_message_id'], message2_id)
|
|
||||||
|
|
||||||
class MessageDictTest(ZulipTestCase):
|
class MessageDictTest(ZulipTestCase):
|
||||||
def test_both_codepaths(self) -> None:
|
def test_both_codepaths(self) -> None:
|
||||||
'''
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user