zulip/zerver/tests/test_submessage.py

235 lines
7.6 KiB
Python
Raw Normal View History

from typing import Any
from unittest import mock
2018-02-12 10:53:36 +01:00
from zerver.actions.submessage import do_add_submessage
from zerver.lib.message_cache import MessageDict
2018-02-11 14:08:01 +01:00
from zerver.lib.test_classes import ZulipTestCase
from zerver.models import Message, SubMessage
2018-02-11 14:08:01 +01:00
class TestBasics(ZulipTestCase):
def test_get_raw_db_rows(self) -> None:
cordelia = self.example_user("cordelia")
hamlet = self.example_user("hamlet")
stream_name = "Verona"
2018-02-11 14:08:01 +01:00
message_id = self.send_stream_message(
sender=cordelia,
2018-02-11 14:08:01 +01:00
stream_name=stream_name,
)
def get_raw_rows() -> list[dict[str, Any]]:
2018-02-11 14:08:01 +01:00
query = SubMessage.get_raw_db_rows([message_id])
rows = list(query)
return rows
rows = get_raw_rows()
self.assertEqual(rows, [])
sm1 = SubMessage.objects.create(
msg_type="whatever",
content="stuff1",
2018-02-11 14:08:01 +01:00
message_id=message_id,
sender=cordelia,
)
sm2 = SubMessage.objects.create(
msg_type="whatever",
content="stuff2",
2018-02-11 14:08:01 +01:00
message_id=message_id,
sender=hamlet,
)
expected_data = [
dict(
id=sm1.id,
message_id=message_id,
sender_id=cordelia.id,
msg_type="whatever",
content="stuff1",
2018-02-11 14:08:01 +01:00
),
dict(
id=sm2.id,
message_id=message_id,
sender_id=hamlet.id,
msg_type="whatever",
content="stuff2",
2018-02-11 14:08:01 +01:00
),
]
self.assertEqual(get_raw_rows(), expected_data)
2018-02-11 14:09:17 +01:00
message = Message.objects.get(id=message_id)
message_json = MessageDict.wide_dict(message)
rows = message_json["submessages"]
rows.sort(key=lambda r: r["id"])
2018-02-11 14:09:17 +01:00
self.assertEqual(rows, expected_data)
msg_rows = MessageDict.ids_to_dict([message_id])
rows = msg_rows[0]["submessages"]
rows.sort(key=lambda r: r["id"])
2018-02-11 14:09:17 +01:00
self.assertEqual(rows, expected_data)
2018-02-12 10:53:36 +01:00
def test_endpoint_errors(self) -> None:
cordelia = self.example_user("cordelia")
stream_name = "Verona"
2018-02-12 10:53:36 +01:00
message_id = self.send_stream_message(
sender=cordelia,
2018-02-12 10:53:36 +01:00
stream_name=stream_name,
)
self.login_user(cordelia)
2018-02-12 10:53:36 +01:00
payload = dict(
message_id=message_id,
msg_type="whatever",
content="not json",
2018-02-12 10:53:36 +01:00
)
result = self.client_post("/json/submessage", payload)
self.assert_json_error(result, "Invalid json for submessage")
2018-02-12 10:53:36 +01:00
hamlet = self.example_user("hamlet")
2018-02-12 10:53:36 +01:00
bad_message_id = self.send_personal_message(
from_user=hamlet,
to_user=hamlet,
2018-02-12 10:53:36 +01:00
)
payload = dict(
message_id=bad_message_id,
msg_type="whatever",
content="does not matter",
2018-02-12 10:53:36 +01:00
)
result = self.client_post("/json/submessage", payload)
self.assert_json_error(result, "Invalid message(s)")
2018-02-12 10:53:36 +01:00
def test_original_sender_enforced(self) -> None:
cordelia = self.example_user("cordelia")
hamlet = self.example_user("hamlet")
stream_name = "Verona"
message_id = self.send_stream_message(
sender=cordelia,
stream_name=stream_name,
)
self.login_user(hamlet)
payload = dict(
message_id=message_id,
msg_type="whatever",
content="{}",
)
# Hamlet can't just go attaching submessages to Cordelia's
# message, even though he does have read access here to the
# message itself.
result = self.client_post("/json/submessage", payload)
self.assert_json_error(result, "You cannot attach a submessage to this message.")
2021-10-18 16:30:46 +02:00
# Since Hamlet is actually subscribed to the stream, he is welcome
# to send submessages to Cordelia once she initiates the "subconversation".
do_add_submessage(
realm=cordelia.realm,
sender_id=cordelia.id,
message_id=message_id,
msg_type="whatever",
content="whatever",
)
result = self.client_post("/json/submessage", payload)
self.assert_json_success(result)
2018-02-12 10:53:36 +01:00
def test_endpoint_success(self) -> None:
cordelia = self.example_user("cordelia")
hamlet = self.example_user("hamlet")
stream_name = "Verona"
2018-02-12 10:53:36 +01:00
message_id = self.send_stream_message(
sender=cordelia,
2018-02-12 10:53:36 +01:00
stream_name=stream_name,
)
self.login_user(cordelia)
2018-02-12 10:53:36 +01:00
payload = dict(
message_id=message_id,
msg_type="whatever",
content='{"name": "alice", "salary": 20}',
2018-02-12 10:53:36 +01:00
)
with self.capture_send_event_calls(expected_num_events=1) as events:
result = self.client_post("/json/submessage", payload)
2018-02-12 10:53:36 +01:00
self.assert_json_success(result)
submessage = SubMessage.objects.get(message_id=message_id)
2018-02-12 10:53:36 +01:00
expected_data = dict(
message_id=message_id,
submessage_id=submessage.id,
content=payload["content"],
msg_type="whatever",
2018-02-12 10:53:36 +01:00
sender_id=cordelia.id,
type="submessage",
2018-02-12 10:53:36 +01:00
)
data = events[0]["event"]
2018-02-12 10:53:36 +01:00
self.assertEqual(data, expected_data)
users = events[0]["users"]
2018-02-12 10:53:36 +01:00
self.assertIn(cordelia.id, users)
self.assertIn(hamlet.id, users)
rows = SubMessage.get_raw_db_rows([message_id])
self.assert_length(rows, 1)
2018-02-12 10:53:36 +01:00
row = rows[0]
expected_data = dict(
id=row["id"],
2018-02-12 10:53:36 +01:00
message_id=message_id,
content='{"name": "alice", "salary": 20}',
msg_type="whatever",
2018-02-12 10:53:36 +01:00
sender_id=cordelia.id,
)
self.assertEqual(row, expected_data)
def test_submessage_event_sent_after_transaction_commits(self) -> None:
"""
Tests that `send_event` is hooked to `transaction.on_commit`. This is important, because
we don't want to end up holding locks on message rows for too long if the event queue runs
into a problem.
"""
hamlet = self.example_user("hamlet")
tests: Ensure stream senders get a UserMessage row. We now complain if a test author sends a stream message that does not result in the sender getting a UserMessage row for the message. This is basically 100% equivalent to complaining that the author failed to subscribe the sender to the stream as part of the test setup, as far as I can tell, so the AssertionError instructs the author to subscribe the sender to the stream. We exempt bots from this check, although it is plausible we should only exempt the system bots like the notification bot. I considered auto-subscribing the sender to the stream, but that can be a little more expensive than the current check, and we generally want test setup to be explicit. If there is some legitimate way than a subscribed human sender can't get a UserMessage, then we probably want an explicit test for that, or we may want to change the backend to just write a UserMessage row in that hypothetical situation. For most tests, including almost all the ones fixed here, the author just wants their test setup to realistically reflect normal operation, and often devs may not realize that Cordelia is not subscribed to Denmark or not realize that Hamlet is not subscribed to Scotland. Some of us don't remember our Shakespeare from high school, and our stream subscriptions don't even necessarily reflect which countries the Bard placed his characters in. There may also be some legitimate use case where an author wants to simulate sending a message to an unsubscribed stream, but for those edge cases, they can always set allow_unsubscribed_sender to True.
2021-12-10 13:55:48 +01:00
message_id = self.send_stream_message(hamlet, "Denmark")
with (
self.capture_send_event_calls(expected_num_events=1),
mock.patch("zerver.tornado.django_api.queue_json_publish") as m,
):
m.side_effect = AssertionError(
"Events should be sent only after the transaction commits."
)
do_add_submessage(hamlet.realm, hamlet.id, message_id, "whatever", "whatever")
def test_fetch_message_containing_submessages(self) -> None:
cordelia = self.example_user("cordelia")
stream_name = "Verona"
message_id = self.send_stream_message(
sender=cordelia,
stream_name=stream_name,
)
self.login_user(cordelia)
payload = dict(
message_id=message_id,
msg_type="whatever",
content='{"name": "alice", "salary": 20}',
)
self.assert_json_success(self.client_post("/json/submessage", payload))
result = self.client_get(f"/json/messages/{message_id}")
response_dict = self.assert_json_success(result)
self.assert_length(response_dict["message"]["submessages"], 1)
submessage = response_dict["message"]["submessages"][0]
expected_data = dict(
id=submessage["id"],
message_id=message_id,
content='{"name": "alice", "salary": 20}',
msg_type="whatever",
sender_id=cordelia.id,
)
self.assertEqual(submessage, expected_data)