mirror of https://github.com/zulip/zulip.git
1377 lines
53 KiB
Python
1377 lines
53 KiB
Python
import time
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
from unittest import mock
|
|
from urllib.parse import urlsplit
|
|
|
|
import orjson
|
|
from django.conf import settings
|
|
from django.http import HttpRequest, HttpResponse
|
|
from django.test import override_settings
|
|
from django.utils.timezone import now as timezone_now
|
|
from typing_extensions import override
|
|
|
|
from zerver.actions.custom_profile_fields import try_update_realm_custom_profile_field
|
|
from zerver.actions.message_send import check_send_message
|
|
from zerver.actions.presence import do_update_user_presence
|
|
from zerver.actions.user_settings import do_change_user_setting
|
|
from zerver.actions.users import do_change_user_role
|
|
from zerver.lib.event_schema import check_web_reload_client_event
|
|
from zerver.lib.events import fetch_initial_state_data, post_process_state
|
|
from zerver.lib.exceptions import AccessDeniedError
|
|
from zerver.lib.request import RequestVariableMissingError
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
from zerver.lib.test_helpers import (
|
|
HostRequestMock,
|
|
dummy_handler,
|
|
reset_email_visibility_to_everyone_in_zulip_realm,
|
|
stub_event_queue_user_events,
|
|
)
|
|
from zerver.lib.users import get_api_key, get_users_for_api
|
|
from zerver.models import CustomProfileField, UserMessage, UserPresence, UserProfile
|
|
from zerver.models.clients import get_client
|
|
from zerver.models.realms import get_realm, get_realm_with_settings
|
|
from zerver.models.streams import get_stream
|
|
from zerver.models.users import get_system_bot
|
|
from zerver.tornado.event_queue import (
|
|
allocate_client_descriptor,
|
|
clear_client_event_queues_for_testing,
|
|
get_client_info_for_message_event,
|
|
mark_clients_to_reload,
|
|
process_message_event,
|
|
send_web_reload_client_events,
|
|
)
|
|
from zerver.tornado.exceptions import BadEventQueueIdError
|
|
from zerver.tornado.views import get_events
|
|
from zerver.views.events_register import _default_all_public_streams, _default_narrow
|
|
|
|
|
|
class EventsEndpointTest(ZulipTestCase):
|
|
def test_events_register_without_user_agent(self) -> None:
|
|
result = self.client_post("/json/register", skip_user_agent=True)
|
|
self.assert_json_success(result)
|
|
|
|
def test_narrows(self) -> None:
|
|
user = self.example_user("hamlet")
|
|
with mock.patch("zerver.lib.events.request_event_queue", return_value=None) as m:
|
|
munge = lambda obj: orjson.dumps(obj).decode()
|
|
narrow = [["stream", "devel"], ["is", "mentioned"]]
|
|
payload = dict(narrow=munge(narrow))
|
|
result = self.api_post(user, "/api/v1/register", payload)
|
|
|
|
# We want the test to abort before actually fetching data.
|
|
self.assert_json_error(result, "Could not allocate event queue")
|
|
|
|
self.assertEqual(m.call_args.kwargs["narrow"], [["stream", "devel"], ["is", "mentioned"]])
|
|
|
|
def test_events_register_endpoint(self) -> None:
|
|
# This test is intended to get minimal coverage on the
|
|
# events_register code paths
|
|
user = self.example_user("hamlet")
|
|
with mock.patch("zerver.views.events_register.do_events_register", return_value={}):
|
|
result = self.api_post(user, "/api/v1/register")
|
|
self.assert_json_success(result)
|
|
|
|
with mock.patch("zerver.lib.events.request_event_queue", return_value=None):
|
|
result = self.api_post(user, "/api/v1/register")
|
|
self.assert_json_error(result, "Could not allocate event queue")
|
|
|
|
return_event_queue = "15:11"
|
|
return_user_events: list[dict[str, Any]] = []
|
|
|
|
# We choose realm_emoji somewhat randomly--we want
|
|
# a "boring" event type for the purpose of this test.
|
|
event_type = "realm_emoji"
|
|
empty_realm_emoji_dict: dict[str, Any] = {}
|
|
test_event = dict(id=6, type=event_type, realm_emoji=empty_realm_emoji_dict)
|
|
|
|
# Test that call is made to deal with a returning soft deactivated user.
|
|
with (
|
|
mock.patch("zerver.lib.events.reactivate_user_if_soft_deactivated") as fa,
|
|
stub_event_queue_user_events(return_event_queue, return_user_events),
|
|
):
|
|
result = self.api_post(
|
|
user, "/api/v1/register", dict(event_types=orjson.dumps([event_type]).decode())
|
|
)
|
|
self.assertEqual(fa.call_count, 1)
|
|
|
|
with stub_event_queue_user_events(return_event_queue, return_user_events):
|
|
result = self.api_post(
|
|
user, "/api/v1/register", dict(event_types=orjson.dumps([event_type]).decode())
|
|
)
|
|
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertEqual(result_dict["last_event_id"], -1)
|
|
self.assertEqual(result_dict["queue_id"], "15:11")
|
|
|
|
# Now start simulating returning actual data
|
|
return_event_queue = "15:12"
|
|
return_user_events = [test_event]
|
|
|
|
with stub_event_queue_user_events(return_event_queue, return_user_events):
|
|
result = self.api_post(
|
|
user, "/api/v1/register", dict(event_types=orjson.dumps([event_type]).decode())
|
|
)
|
|
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertEqual(result_dict["last_event_id"], 6)
|
|
self.assertEqual(result_dict["queue_id"], "15:12")
|
|
|
|
# sanity check the data relevant to our event
|
|
self.assertEqual(result_dict["realm_emoji"], {})
|
|
|
|
# Now test with `fetch_event_types` not matching the event
|
|
return_event_queue = "15:13"
|
|
with stub_event_queue_user_events(return_event_queue, return_user_events):
|
|
result = self.api_post(
|
|
user,
|
|
"/api/v1/register",
|
|
dict(
|
|
event_types=orjson.dumps([event_type]).decode(),
|
|
fetch_event_types=orjson.dumps(["message"]).decode(),
|
|
),
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertEqual(result_dict["last_event_id"], 6)
|
|
# Check that the message event types data is in there
|
|
self.assertIn("max_message_id", result_dict)
|
|
|
|
# Check that our original event type is not there.
|
|
self.assertNotIn(event_type, result_dict)
|
|
self.assertEqual(result_dict["queue_id"], "15:13")
|
|
|
|
# Now test with `fetch_event_types` matching the event
|
|
with stub_event_queue_user_events(return_event_queue, return_user_events):
|
|
result = self.api_post(
|
|
user,
|
|
"/api/v1/register",
|
|
dict(
|
|
fetch_event_types=orjson.dumps([event_type]).decode(),
|
|
event_types=orjson.dumps(["message"]).decode(),
|
|
),
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertEqual(result_dict["last_event_id"], 6)
|
|
# Check that we didn't fetch the messages data
|
|
self.assertNotIn("max_message_id", result_dict)
|
|
|
|
# Check that the realm_emoji data is in there.
|
|
self.assertIn("realm_emoji", result_dict)
|
|
self.assertEqual(result_dict["realm_emoji"], {})
|
|
self.assertEqual(result_dict["queue_id"], "15:13")
|
|
|
|
def test_events_register_spectators(self) -> None:
|
|
# Verify that POST /register works for spectators, but not for
|
|
# normal users.
|
|
with self.settings(WEB_PUBLIC_STREAMS_ENABLED=False):
|
|
result = self.client_post("/json/register")
|
|
self.assert_json_error(
|
|
result,
|
|
"Not logged in: API authentication or user session required",
|
|
status_code=401,
|
|
)
|
|
|
|
result = self.client_post("/json/register")
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertEqual(result_dict["queue_id"], None)
|
|
self.assertEqual(result_dict["realm_url"], "http://zulip.testserver")
|
|
self.assertEqual(result_dict["realm_uri"], "http://zulip.testserver")
|
|
|
|
result = self.client_post("/json/register")
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
result = self.client_post("/json/register", dict(client_gravatar="false"))
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
result = self.client_post("/json/register", dict(client_gravatar="true"))
|
|
self.assert_json_error(
|
|
result,
|
|
"Invalid 'client_gravatar' parameter for anonymous request",
|
|
status_code=400,
|
|
)
|
|
|
|
result = self.client_post("/json/register", dict(include_subscribers="true"))
|
|
self.assert_json_error(
|
|
result,
|
|
"Invalid 'include_subscribers' parameter for anonymous request",
|
|
status_code=400,
|
|
)
|
|
|
|
def test_events_register_endpoint_all_public_streams_access(self) -> None:
|
|
guest_user = self.example_user("polonius")
|
|
normal_user = self.example_user("hamlet")
|
|
self.assertEqual(guest_user.role, UserProfile.ROLE_GUEST)
|
|
self.assertEqual(normal_user.role, UserProfile.ROLE_MEMBER)
|
|
|
|
with mock.patch("zerver.views.events_register.do_events_register", return_value={}):
|
|
result = self.api_post(normal_user, "/api/v1/register", dict(all_public_streams="true"))
|
|
self.assert_json_success(result)
|
|
|
|
with mock.patch("zerver.views.events_register.do_events_register", return_value={}):
|
|
result = self.api_post(guest_user, "/api/v1/register", dict(all_public_streams="true"))
|
|
self.assert_json_error(result, "User not authorized for this query")
|
|
|
|
def test_events_get_events_endpoint_guest_cant_use_all_public_streams_param(self) -> None:
|
|
"""
|
|
This test is meant to execute the very beginning of the codepath
|
|
to ensure guest users are immediately disallowed to use the
|
|
all_public_streams param. Deeper testing is hard (and not necessary for this case)
|
|
due to the codepath expecting AsyncDjangoHandler to be attached to the request,
|
|
which doesn't happen in our test setup.
|
|
"""
|
|
|
|
guest_user = self.example_user("polonius")
|
|
self.assertEqual(guest_user.role, UserProfile.ROLE_GUEST)
|
|
|
|
result = self.api_get(guest_user, "/api/v1/events", dict(all_public_streams="true"))
|
|
self.assert_json_error(result, "User not authorized for this query")
|
|
|
|
def test_tornado_endpoint(self) -> None:
|
|
# This test is mostly intended to get minimal coverage on the
|
|
# /api/internal/notify_tornado endpoint (only used in
|
|
# puppeteer tests), so we can have 100% URL coverage, but it
|
|
# does exercise a little bit of the codepath.
|
|
post_data = dict(
|
|
data=orjson.dumps(
|
|
dict(
|
|
event=dict(
|
|
type="other",
|
|
),
|
|
users=[self.example_user("hamlet").id],
|
|
),
|
|
).decode(),
|
|
)
|
|
req = HostRequestMock(post_data)
|
|
req.META["REMOTE_ADDR"] = "127.0.0.1"
|
|
with self.assertRaises(RequestVariableMissingError) as context:
|
|
result = self.client_post_request("/api/internal/notify_tornado", req)
|
|
self.assertEqual(str(context.exception), "Missing 'secret' argument")
|
|
self.assertEqual(context.exception.http_status_code, 400)
|
|
|
|
post_data["secret"] = "random"
|
|
req = HostRequestMock(post_data, user_profile=None)
|
|
req.META["REMOTE_ADDR"] = "127.0.0.1"
|
|
with self.assertRaises(AccessDeniedError) as access_denied_error:
|
|
result = self.client_post_request("/api/internal/notify_tornado", req)
|
|
self.assertEqual(str(access_denied_error.exception), "Access denied")
|
|
self.assertEqual(access_denied_error.exception.http_status_code, 403)
|
|
|
|
post_data["secret"] = settings.SHARED_SECRET
|
|
req = HostRequestMock(post_data, tornado_handler=dummy_handler)
|
|
req.META["REMOTE_ADDR"] = "127.0.0.1"
|
|
result = self.client_post_request("/api/internal/notify_tornado", req)
|
|
self.assert_json_success(result)
|
|
|
|
post_data = dict(secret=settings.SHARED_SECRET)
|
|
req = HostRequestMock(post_data, tornado_handler=dummy_handler)
|
|
req.META["REMOTE_ADDR"] = "127.0.0.1"
|
|
with self.assertRaises(RequestVariableMissingError) as context:
|
|
result = self.client_post_request("/api/internal/notify_tornado", req)
|
|
self.assertEqual(str(context.exception), "Missing 'data' argument")
|
|
self.assertEqual(context.exception.http_status_code, 400)
|
|
|
|
def test_web_reload_clients(self) -> None:
|
|
# Minimal testing of the /api/internal/web_reload_clients endpoint
|
|
post_data = {
|
|
"client_count": "1",
|
|
"immediate": orjson.dumps(False).decode(),
|
|
"secret": settings.SHARED_SECRET,
|
|
}
|
|
req = HostRequestMock(post_data, tornado_handler=dummy_handler)
|
|
req.META["REMOTE_ADDR"] = "127.0.0.1"
|
|
result = self.client_post_request("/api/internal/web_reload_clients", req)
|
|
self.assert_json_success(result)
|
|
self.assertEqual(orjson.loads(result.content)["sent_events"], 0)
|
|
|
|
|
|
class GetEventsTest(ZulipTestCase):
|
|
def tornado_call(
|
|
self,
|
|
view_func: Callable[[HttpRequest, UserProfile], HttpResponse],
|
|
user_profile: UserProfile,
|
|
post_data: dict[str, Any],
|
|
) -> HttpResponse:
|
|
request = HostRequestMock(post_data, user_profile, tornado_handler=dummy_handler)
|
|
return view_func(request, user_profile)
|
|
|
|
def test_get_events(self) -> None:
|
|
user_profile = self.example_user("hamlet")
|
|
email = user_profile.email
|
|
recipient_user_profile = self.example_user("othello")
|
|
recipient_email = recipient_user_profile.email
|
|
self.login_user(user_profile)
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"apply_markdown": orjson.dumps(True).decode(),
|
|
"client_gravatar": orjson.dumps(True).decode(),
|
|
"event_types": orjson.dumps(["message"]).decode(),
|
|
"user_client": "website",
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
self.assert_json_success(result)
|
|
queue_id = orjson.loads(result.content)["queue_id"]
|
|
|
|
recipient_result = self.tornado_call(
|
|
get_events,
|
|
recipient_user_profile,
|
|
{
|
|
"apply_markdown": orjson.dumps(True).decode(),
|
|
"client_gravatar": orjson.dumps(True).decode(),
|
|
"event_types": orjson.dumps(["message"]).decode(),
|
|
"user_client": "website",
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
self.assert_json_success(recipient_result)
|
|
recipient_queue_id = orjson.loads(recipient_result.content)["queue_id"]
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"queue_id": queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
events = orjson.loads(result.content)["events"]
|
|
self.assert_json_success(result)
|
|
self.assert_length(events, 0)
|
|
|
|
local_id = "10.01"
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
check_send_message(
|
|
sender=user_profile,
|
|
client=get_client("whatever"),
|
|
recipient_type_name="private",
|
|
message_to=[recipient_email],
|
|
topic_name=None,
|
|
message_content="hello",
|
|
local_id=local_id,
|
|
sender_queue_id=queue_id,
|
|
)
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"queue_id": queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
events = orjson.loads(result.content)["events"]
|
|
self.assert_json_success(result)
|
|
self.assert_length(events, 1)
|
|
self.assertEqual(events[0]["type"], "message")
|
|
self.assertEqual(events[0]["message"]["sender_email"], email)
|
|
self.assertEqual(events[0]["local_message_id"], local_id)
|
|
self.assertEqual(events[0]["message"]["display_recipient"][0]["is_mirror_dummy"], False)
|
|
self.assertEqual(events[0]["message"]["display_recipient"][1]["is_mirror_dummy"], False)
|
|
|
|
last_event_id = events[0]["id"]
|
|
local_id = "10.02"
|
|
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
check_send_message(
|
|
sender=user_profile,
|
|
client=get_client("whatever"),
|
|
recipient_type_name="private",
|
|
message_to=[recipient_email],
|
|
topic_name=None,
|
|
message_content="hello",
|
|
local_id=local_id,
|
|
sender_queue_id=queue_id,
|
|
)
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"queue_id": queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": last_event_id,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
events = orjson.loads(result.content)["events"]
|
|
self.assert_json_success(result)
|
|
self.assert_length(events, 1)
|
|
self.assertEqual(events[0]["type"], "message")
|
|
self.assertEqual(events[0]["message"]["sender_email"], email)
|
|
self.assertEqual(events[0]["local_message_id"], local_id)
|
|
|
|
# Test that the received message in the receiver's event queue
|
|
# exists and does not contain a local id
|
|
recipient_result = self.tornado_call(
|
|
get_events,
|
|
recipient_user_profile,
|
|
{
|
|
"queue_id": recipient_queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
recipient_events = orjson.loads(recipient_result.content)["events"]
|
|
self.assert_json_success(recipient_result)
|
|
self.assert_length(recipient_events, 2)
|
|
self.assertEqual(recipient_events[0]["type"], "message")
|
|
self.assertEqual(recipient_events[0]["message"]["sender_email"], email)
|
|
self.assertTrue("local_message_id" not in recipient_events[0])
|
|
self.assertEqual(recipient_events[1]["type"], "message")
|
|
self.assertEqual(recipient_events[1]["message"]["sender_email"], email)
|
|
self.assertTrue("local_message_id" not in recipient_events[1])
|
|
|
|
def test_get_events_narrow(self) -> None:
|
|
user_profile = self.example_user("hamlet")
|
|
self.login_user(user_profile)
|
|
|
|
def get_message(apply_markdown: bool, client_gravatar: bool) -> dict[str, Any]:
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
dict(
|
|
apply_markdown=orjson.dumps(apply_markdown).decode(),
|
|
client_gravatar=orjson.dumps(client_gravatar).decode(),
|
|
event_types=orjson.dumps(["message"]).decode(),
|
|
narrow=orjson.dumps([["stream", "denmark"]]).decode(),
|
|
user_client="website",
|
|
dont_block=orjson.dumps(True).decode(),
|
|
),
|
|
)
|
|
|
|
self.assert_json_success(result)
|
|
queue_id = orjson.loads(result.content)["queue_id"]
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"queue_id": queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
events = orjson.loads(result.content)["events"]
|
|
self.assert_json_success(result)
|
|
self.assert_length(events, 0)
|
|
|
|
self.send_personal_message(user_profile, self.example_user("othello"), "hello")
|
|
self.send_stream_message(user_profile, "Denmark", "**hello**")
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"queue_id": queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
events = orjson.loads(result.content)["events"]
|
|
self.assert_json_success(result)
|
|
self.assert_length(events, 1)
|
|
self.assertEqual(events[0]["type"], "message")
|
|
return events[0]["message"]
|
|
|
|
message = get_message(apply_markdown=False, client_gravatar=False)
|
|
self.assertEqual(message["display_recipient"], "Denmark")
|
|
self.assertEqual(message["content"], "**hello**")
|
|
self.assertEqual(urlsplit(message["avatar_url"]).hostname, "secure.gravatar.com")
|
|
|
|
message = get_message(apply_markdown=True, client_gravatar=False)
|
|
self.assertEqual(message["display_recipient"], "Denmark")
|
|
self.assertEqual(message["content"], "<p><strong>hello</strong></p>")
|
|
self.assertIn("gravatar.com", message["avatar_url"])
|
|
|
|
do_change_user_setting(
|
|
user_profile,
|
|
"email_address_visibility",
|
|
UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
|
|
acting_user=None,
|
|
)
|
|
|
|
message = get_message(apply_markdown=False, client_gravatar=True)
|
|
self.assertEqual(message["display_recipient"], "Denmark")
|
|
self.assertEqual(message["content"], "**hello**")
|
|
self.assertEqual(message["avatar_url"], None)
|
|
|
|
message = get_message(apply_markdown=True, client_gravatar=True)
|
|
self.assertEqual(message["display_recipient"], "Denmark")
|
|
self.assertEqual(message["content"], "<p><strong>hello</strong></p>")
|
|
self.assertEqual(message["avatar_url"], None)
|
|
|
|
def test_bogus_queue_id(self) -> None:
|
|
user = self.example_user("hamlet")
|
|
|
|
with self.assertRaises(BadEventQueueIdError):
|
|
self.tornado_call(
|
|
get_events,
|
|
user,
|
|
{
|
|
"queue_id": "hamster",
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
|
|
def test_wrong_user_queue_id(self) -> None:
|
|
user = self.example_user("hamlet")
|
|
wrong_user = self.example_user("othello")
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user,
|
|
{
|
|
"apply_markdown": orjson.dumps(True).decode(),
|
|
"client_gravatar": orjson.dumps(True).decode(),
|
|
"event_types": orjson.dumps(["message"]).decode(),
|
|
"user_client": "website",
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
self.assert_json_success(result)
|
|
queue_id = orjson.loads(result.content)["queue_id"]
|
|
|
|
with self.assertLogs(level="WARNING") as cm, self.assertRaises(BadEventQueueIdError):
|
|
self.tornado_call(
|
|
get_events,
|
|
wrong_user,
|
|
{
|
|
"queue_id": queue_id,
|
|
"user_client": "website",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
self.assertIn("not authorized for queue", cm.output[0])
|
|
|
|
def test_get_events_custom_profile_fields(self) -> None:
|
|
user_profile = self.example_user("iago")
|
|
self.login_user(user_profile)
|
|
profile_field = CustomProfileField.objects.get(realm=user_profile.realm, name="Pronouns")
|
|
|
|
def check_pronouns_type_field_supported(
|
|
pronouns_field_type_supported: bool, new_name: str
|
|
) -> None:
|
|
clear_client_event_queues_for_testing()
|
|
|
|
queue_data = dict(
|
|
apply_markdown=True,
|
|
all_public_streams=True,
|
|
client_type_name="ZulipMobile",
|
|
event_types=["custom_profile_fields"],
|
|
last_connection_time=time.time(),
|
|
queue_timeout=0,
|
|
realm_id=user_profile.realm.id,
|
|
user_profile_id=user_profile.id,
|
|
pronouns_field_type_supported=pronouns_field_type_supported,
|
|
)
|
|
|
|
client = allocate_client_descriptor(queue_data)
|
|
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
try_update_realm_custom_profile_field(
|
|
realm=user_profile.realm, field=profile_field, name=new_name
|
|
)
|
|
|
|
result = self.tornado_call(
|
|
get_events,
|
|
user_profile,
|
|
{
|
|
"queue_id": client.event_queue.id,
|
|
"user_client": "ZulipAndroid",
|
|
"last_event_id": -1,
|
|
"dont_block": orjson.dumps(True).decode(),
|
|
},
|
|
)
|
|
events = orjson.loads(result.content)["events"]
|
|
self.assert_json_success(result)
|
|
self.assert_length(events, 1)
|
|
|
|
[pronouns_field] = (
|
|
field for field in events[0]["fields"] if field["id"] == profile_field.id
|
|
)
|
|
if pronouns_field_type_supported:
|
|
expected_type = CustomProfileField.PRONOUNS
|
|
else:
|
|
expected_type = CustomProfileField.SHORT_TEXT
|
|
self.assertEqual(pronouns_field["type"], expected_type)
|
|
|
|
check_pronouns_type_field_supported(False, "Pronouns field")
|
|
check_pronouns_type_field_supported(True, "Pronouns")
|
|
|
|
|
|
class FetchInitialStateDataTest(ZulipTestCase):
|
|
# Non-admin users don't have access to all bots
|
|
def test_realm_bots_non_admin(self) -> None:
|
|
user_profile = self.example_user("cordelia")
|
|
self.assertFalse(user_profile.is_realm_admin)
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
self.assert_length(result["realm_bots"], 0)
|
|
|
|
# additionally the API key for a random bot is not present in the data
|
|
api_key = get_api_key(self.notification_bot(user_profile.realm))
|
|
self.assertNotIn(api_key, str(result))
|
|
|
|
# Admin users have access to all bots in the realm_bots field
|
|
def test_realm_bots_admin(self) -> None:
|
|
user_profile = self.example_user("hamlet")
|
|
do_change_user_role(user_profile, UserProfile.ROLE_REALM_ADMINISTRATOR, acting_user=None)
|
|
self.assertTrue(user_profile.is_realm_admin)
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
self.assertGreater(len(result["realm_bots"]), 2)
|
|
|
|
def test_max_message_id_with_no_history(self) -> None:
|
|
user_profile = self.example_user("aaron")
|
|
# Delete all historical messages for this user
|
|
UserMessage.objects.filter(user_profile=user_profile).delete()
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
self.assertEqual(result["max_message_id"], -1)
|
|
|
|
def test_delivery_email_presence_for_non_admins(self) -> None:
|
|
user_profile = self.example_user("aaron")
|
|
hamlet = self.example_user("hamlet")
|
|
self.assertFalse(user_profile.is_realm_admin)
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
do_change_user_setting(
|
|
hamlet,
|
|
"email_address_visibility",
|
|
UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
|
|
acting_user=None,
|
|
)
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
|
|
(hamlet_obj,) = (value for key, value in result["raw_users"].items() if key == hamlet.id)
|
|
self.assertEqual(hamlet_obj["delivery_email"], hamlet.delivery_email)
|
|
|
|
do_change_user_setting(
|
|
hamlet,
|
|
"email_address_visibility",
|
|
UserProfile.EMAIL_ADDRESS_VISIBILITY_ADMINS,
|
|
acting_user=None,
|
|
)
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
|
|
(hamlet_obj,) = (value for key, value in result["raw_users"].items() if key == hamlet.id)
|
|
self.assertIsNone(hamlet_obj["delivery_email"])
|
|
|
|
def test_delivery_email_presence_for_admins(self) -> None:
|
|
user_profile = self.example_user("iago")
|
|
hamlet = self.example_user("hamlet")
|
|
self.assertTrue(user_profile.is_realm_admin)
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
do_change_user_setting(
|
|
hamlet,
|
|
"email_address_visibility",
|
|
UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
|
|
acting_user=None,
|
|
)
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
|
|
(hamlet_obj,) = (value for key, value in result["raw_users"].items() if key == hamlet.id)
|
|
self.assertEqual(hamlet_obj["delivery_email"], hamlet.delivery_email)
|
|
|
|
do_change_user_setting(
|
|
hamlet,
|
|
"email_address_visibility",
|
|
UserProfile.EMAIL_ADDRESS_VISIBILITY_ADMINS,
|
|
acting_user=None,
|
|
)
|
|
result = fetch_initial_state_data(user_profile, realm=user_profile.realm)
|
|
(hamlet_obj,) = (value for key, value in result["raw_users"].items() if key == hamlet.id)
|
|
self.assertIn("delivery_email", hamlet_obj)
|
|
|
|
def test_user_avatar_url_field_optional(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
users = [
|
|
self.example_user("iago"),
|
|
self.example_user("cordelia"),
|
|
self.example_user("ZOE"),
|
|
self.example_user("othello"),
|
|
]
|
|
|
|
for user in users:
|
|
user.long_term_idle = True
|
|
user.save()
|
|
|
|
long_term_idle_users_ids = [user.id for user in users]
|
|
|
|
result = fetch_initial_state_data(
|
|
user_profile=hamlet,
|
|
realm=hamlet.realm,
|
|
user_avatar_url_field_optional=True,
|
|
)
|
|
|
|
raw_users = result["raw_users"]
|
|
|
|
for user_dict in raw_users.values():
|
|
if user_dict["user_id"] in long_term_idle_users_ids:
|
|
self.assertFalse("avatar_url" in user_dict)
|
|
else:
|
|
self.assertIsNotNone(user_dict["avatar_url"])
|
|
|
|
gravatar_users_id = [
|
|
user_dict["user_id"]
|
|
for user_dict in raw_users.values()
|
|
if "avatar_url" in user_dict
|
|
and urlsplit(user_dict["avatar_url"]).hostname == "secure.gravatar.com"
|
|
]
|
|
|
|
reset_email_visibility_to_everyone_in_zulip_realm()
|
|
|
|
# Test again with client_gravatar = True
|
|
result = fetch_initial_state_data(
|
|
user_profile=hamlet,
|
|
realm=hamlet.realm,
|
|
client_gravatar=True,
|
|
user_avatar_url_field_optional=True,
|
|
)
|
|
|
|
raw_users = result["raw_users"]
|
|
|
|
for user_dict in raw_users.values():
|
|
if user_dict["user_id"] in gravatar_users_id:
|
|
self.assertIsNone(user_dict["avatar_url"])
|
|
else:
|
|
self.assertFalse("avatar_url" in user_dict)
|
|
|
|
def test_user_settings_based_on_client_capabilities(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
result = fetch_initial_state_data(
|
|
user_profile=hamlet,
|
|
realm=hamlet.realm,
|
|
user_settings_object=True,
|
|
)
|
|
self.assertIn("user_settings", result)
|
|
for prop in UserProfile.property_types:
|
|
self.assertNotIn(prop, result)
|
|
self.assertIn(prop, result["user_settings"])
|
|
|
|
result = fetch_initial_state_data(
|
|
user_profile=hamlet,
|
|
realm=hamlet.realm,
|
|
user_settings_object=False,
|
|
)
|
|
self.assertIn("user_settings", result)
|
|
for prop in UserProfile.property_types:
|
|
if prop in {
|
|
**UserProfile.display_settings_legacy,
|
|
**UserProfile.notification_settings_legacy,
|
|
}:
|
|
# Only legacy settings are included in the top level.
|
|
self.assertIn(prop, result)
|
|
self.assertIn(prop, result["user_settings"])
|
|
|
|
def test_realm_linkifiers_based_on_client_capabilities(self) -> None:
|
|
user = self.example_user("iago")
|
|
self.login_user(user)
|
|
|
|
data = {
|
|
"pattern": "#(?P<id>[123])",
|
|
"url_template": "https://realm.com/my_realm_filter/{id}",
|
|
}
|
|
post_result = self.client_post("/json/realm/filters", info=data)
|
|
self.assert_json_success(post_result)
|
|
|
|
result = fetch_initial_state_data(
|
|
user_profile=user,
|
|
realm=user.realm,
|
|
linkifier_url_template=True,
|
|
)
|
|
self.assertEqual(result["realm_filters"], [])
|
|
self.assertEqual(result["realm_linkifiers"][-1]["pattern"], "#(?P<id>[123])")
|
|
self.assertEqual(
|
|
result["realm_linkifiers"][-1]["url_template"],
|
|
"https://realm.com/my_realm_filter/{id}",
|
|
)
|
|
|
|
# The default behavior should be `linkifier_url_template=False`
|
|
result = fetch_initial_state_data(
|
|
user_profile=user,
|
|
realm=user.realm,
|
|
)
|
|
self.assertEqual(result["realm_filters"], [])
|
|
self.assertEqual(result["realm_linkifiers"], [])
|
|
|
|
def test_pronouns_field_type_support(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
result = fetch_initial_state_data(
|
|
user_profile=hamlet,
|
|
realm=hamlet.realm,
|
|
pronouns_field_type_supported=False,
|
|
)
|
|
self.assertIn("custom_profile_fields", result)
|
|
custom_profile_fields = result["custom_profile_fields"]
|
|
[pronouns_field] = (field for field in custom_profile_fields if field["name"] == "Pronouns")
|
|
self.assertEqual(pronouns_field["type"], CustomProfileField.SHORT_TEXT)
|
|
|
|
result = fetch_initial_state_data(
|
|
user_profile=hamlet,
|
|
realm=hamlet.realm,
|
|
pronouns_field_type_supported=True,
|
|
)
|
|
self.assertIn("custom_profile_fields", result)
|
|
custom_profile_fields = result["custom_profile_fields"]
|
|
[pronouns_field] = (field for field in custom_profile_fields if field["name"] == "Pronouns")
|
|
self.assertEqual(pronouns_field["type"], CustomProfileField.PRONOUNS)
|
|
|
|
def test_unreads_case_insensitive_topics(self) -> None:
|
|
sender = self.example_user("hamlet")
|
|
self.login_user(sender)
|
|
self.send_stream_message(sender, "Denmark", "**hello**", topic_name="case DOES not MATTER")
|
|
self.send_stream_message(sender, "Denmark", "**bye**", topic_name="CASE does NOT matter")
|
|
|
|
reader = self.example_user("othello")
|
|
result = fetch_initial_state_data(
|
|
user_profile=reader,
|
|
realm=reader.realm,
|
|
)
|
|
post_process_state(reader, result, False)
|
|
self.assert_length(result["unread_msgs"]["streams"], 1)
|
|
self.assertEqual(result["unread_msgs"]["streams"][0]["topic"], "case DOES not MATTER")
|
|
self.assert_length(result["unread_msgs"]["streams"][0]["unread_message_ids"], 2)
|
|
|
|
|
|
class ClientDescriptorsTest(ZulipTestCase):
|
|
def test_get_client_info_for_all_public_streams(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
realm = hamlet.realm
|
|
|
|
queue_data = dict(
|
|
all_public_streams=True,
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
client_type_name="website",
|
|
event_types=["message"],
|
|
last_connection_time=time.time(),
|
|
queue_timeout=0,
|
|
realm_id=realm.id,
|
|
user_profile_id=hamlet.id,
|
|
)
|
|
|
|
client = allocate_client_descriptor(queue_data)
|
|
|
|
message_event = dict(
|
|
realm_id=realm.id,
|
|
stream_name="whatever",
|
|
)
|
|
|
|
client_info = get_client_info_for_message_event(
|
|
message_event,
|
|
users=[],
|
|
)
|
|
|
|
self.assert_length(client_info, 1)
|
|
|
|
dct = client_info[client.event_queue.id]
|
|
self.assertEqual(dct["client"].apply_markdown, True)
|
|
self.assertEqual(dct["client"].client_gravatar, True)
|
|
self.assertEqual(dct["client"].user_profile_id, hamlet.id)
|
|
self.assertEqual(dct["flags"], [])
|
|
self.assertEqual(dct["is_sender"], False)
|
|
|
|
message_event = dict(
|
|
realm_id=realm.id,
|
|
stream_name="whatever",
|
|
sender_queue_id=client.event_queue.id,
|
|
)
|
|
|
|
client_info = get_client_info_for_message_event(
|
|
message_event,
|
|
users=[],
|
|
)
|
|
dct = client_info[client.event_queue.id]
|
|
self.assertEqual(dct["is_sender"], True)
|
|
|
|
def test_get_client_info_for_normal_users(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
cordelia = self.example_user("cordelia")
|
|
realm = hamlet.realm
|
|
|
|
def test_get_info(apply_markdown: bool, client_gravatar: bool) -> None:
|
|
clear_client_event_queues_for_testing()
|
|
|
|
queue_data = dict(
|
|
all_public_streams=False,
|
|
apply_markdown=apply_markdown,
|
|
client_gravatar=client_gravatar,
|
|
client_type_name="website",
|
|
event_types=["message"],
|
|
last_connection_time=time.time(),
|
|
queue_timeout=0,
|
|
realm_id=realm.id,
|
|
user_profile_id=hamlet.id,
|
|
)
|
|
|
|
client = allocate_client_descriptor(queue_data)
|
|
message_event = dict(
|
|
realm_id=realm.id,
|
|
stream_name="whatever",
|
|
)
|
|
|
|
client_info = get_client_info_for_message_event(
|
|
message_event,
|
|
users=[
|
|
dict(id=cordelia.id),
|
|
],
|
|
)
|
|
|
|
self.assert_length(client_info, 0)
|
|
|
|
client_info = get_client_info_for_message_event(
|
|
message_event,
|
|
users=[
|
|
dict(id=cordelia.id),
|
|
dict(id=hamlet.id, flags=["mentioned"]),
|
|
],
|
|
)
|
|
self.assert_length(client_info, 1)
|
|
|
|
dct = client_info[client.event_queue.id]
|
|
self.assertEqual(dct["client"].apply_markdown, apply_markdown)
|
|
self.assertEqual(dct["client"].client_gravatar, client_gravatar)
|
|
self.assertEqual(dct["client"].user_profile_id, hamlet.id)
|
|
self.assertEqual(dct["flags"], ["mentioned"])
|
|
self.assertEqual(dct["is_sender"], False)
|
|
|
|
test_get_info(apply_markdown=False, client_gravatar=False)
|
|
test_get_info(apply_markdown=True, client_gravatar=False)
|
|
|
|
test_get_info(apply_markdown=False, client_gravatar=True)
|
|
test_get_info(apply_markdown=True, client_gravatar=True)
|
|
|
|
def test_process_message_event_with_mocked_client_info(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
class MockClient:
|
|
def __init__(
|
|
self, user_profile_id: int, apply_markdown: bool, client_gravatar: bool
|
|
) -> None:
|
|
self.user_profile_id = user_profile_id
|
|
self.apply_markdown = apply_markdown
|
|
self.client_gravatar = client_gravatar
|
|
self.client_type_name = "whatever"
|
|
self.events: list[dict[str, Any]] = []
|
|
|
|
def accepts_messages(self) -> bool:
|
|
return True
|
|
|
|
def accepts_event(self, event: dict[str, Any]) -> bool:
|
|
assert event["type"] == "message"
|
|
return True
|
|
|
|
def add_event(self, event: dict[str, Any]) -> None:
|
|
self.events.append(event)
|
|
|
|
client1 = MockClient(
|
|
user_profile_id=hamlet.id,
|
|
apply_markdown=True,
|
|
client_gravatar=False,
|
|
)
|
|
|
|
client2 = MockClient(
|
|
user_profile_id=hamlet.id,
|
|
apply_markdown=False,
|
|
client_gravatar=False,
|
|
)
|
|
|
|
client3 = MockClient(
|
|
user_profile_id=hamlet.id,
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
)
|
|
|
|
client4 = MockClient(
|
|
user_profile_id=hamlet.id,
|
|
apply_markdown=False,
|
|
client_gravatar=True,
|
|
)
|
|
|
|
client_info = {
|
|
"client:1": dict(
|
|
client=client1,
|
|
flags=["starred"],
|
|
),
|
|
"client:2": dict(
|
|
client=client2,
|
|
flags=["has_alert_word"],
|
|
),
|
|
"client:3": dict(
|
|
client=client3,
|
|
flags=[],
|
|
),
|
|
"client:4": dict(
|
|
client=client4,
|
|
flags=[],
|
|
),
|
|
}
|
|
|
|
sender = hamlet
|
|
|
|
message_event = dict(
|
|
message_dict=dict(
|
|
id=999,
|
|
content="**hello**",
|
|
rendered_content="<b>hello</b>",
|
|
sender_id=sender.id,
|
|
type="stream",
|
|
client="website",
|
|
# NOTE: Some of these fields are clutter, but some
|
|
# will be useful when we let clients specify
|
|
# that they can compute their own gravatar URLs.
|
|
sender_email=sender.email,
|
|
sender_delivery_email=sender.delivery_email,
|
|
sender_realm_id=sender.realm_id,
|
|
sender_avatar_source=UserProfile.AVATAR_FROM_GRAVATAR,
|
|
sender_avatar_version=1,
|
|
sender_is_mirror_dummy=None,
|
|
sender_email_address_visibility=UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
|
|
recipient_type=None,
|
|
recipient_type_id=None,
|
|
),
|
|
)
|
|
|
|
# Setting users to `[]` bypasses code we don't care about
|
|
# for this test--we assume client_info is correct in our mocks,
|
|
# and we are interested in how messages are put on event queue.
|
|
users: list[dict[str, Any]] = []
|
|
|
|
with mock.patch(
|
|
"zerver.tornado.event_queue.get_client_info_for_message_event", return_value=client_info
|
|
):
|
|
process_message_event(message_event, users)
|
|
|
|
# We are not closely examining avatar_url at this point, so
|
|
# just sanity check them and then delete the keys so that
|
|
# upcoming comparisons work.
|
|
for client in [client1, client2]:
|
|
message = client.events[0]["message"]
|
|
self.assertIn("gravatar.com", message["avatar_url"])
|
|
message.pop("avatar_url")
|
|
|
|
self.assertEqual(
|
|
client1.events,
|
|
[
|
|
dict(
|
|
type="message",
|
|
message=dict(
|
|
type="stream",
|
|
sender_id=sender.id,
|
|
sender_email=sender.email,
|
|
id=999,
|
|
content="<b>hello</b>",
|
|
content_type="text/html",
|
|
client="website",
|
|
),
|
|
flags=["starred"],
|
|
),
|
|
],
|
|
)
|
|
|
|
self.assertEqual(
|
|
client2.events,
|
|
[
|
|
dict(
|
|
type="message",
|
|
message=dict(
|
|
type="stream",
|
|
sender_id=sender.id,
|
|
sender_email=sender.email,
|
|
id=999,
|
|
content="**hello**",
|
|
content_type="text/x-markdown",
|
|
client="website",
|
|
),
|
|
flags=["has_alert_word"],
|
|
),
|
|
],
|
|
)
|
|
|
|
self.assertEqual(
|
|
client3.events,
|
|
[
|
|
dict(
|
|
type="message",
|
|
message=dict(
|
|
type="stream",
|
|
sender_id=sender.id,
|
|
sender_email=sender.email,
|
|
avatar_url=None,
|
|
id=999,
|
|
content="<b>hello</b>",
|
|
content_type="text/html",
|
|
client="website",
|
|
),
|
|
flags=[],
|
|
),
|
|
],
|
|
)
|
|
|
|
self.assertEqual(
|
|
client4.events,
|
|
[
|
|
dict(
|
|
type="message",
|
|
message=dict(
|
|
type="stream",
|
|
sender_id=sender.id,
|
|
sender_email=sender.email,
|
|
avatar_url=None,
|
|
id=999,
|
|
content="**hello**",
|
|
content_type="text/x-markdown",
|
|
client="website",
|
|
),
|
|
flags=[],
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
class ReloadWebClientsTest(ZulipTestCase):
|
|
def test_web_reload_clients(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
realm = hamlet.realm
|
|
|
|
clear_client_event_queues_for_testing()
|
|
|
|
queue_data = dict(
|
|
all_public_streams=False,
|
|
apply_markdown=True,
|
|
client_gravatar=True,
|
|
client_type_name="website",
|
|
event_types=None,
|
|
last_connection_time=time.time(),
|
|
queue_timeout=0,
|
|
realm_id=realm.id,
|
|
user_profile_id=hamlet.id,
|
|
)
|
|
client = allocate_client_descriptor(queue_data)
|
|
|
|
send_web_reload_client_events()
|
|
self.assert_length(client.event_queue.queue, 0)
|
|
|
|
mark_clients_to_reload([client.event_queue.id])
|
|
send_web_reload_client_events()
|
|
self.assert_length(client.event_queue.queue, 1)
|
|
reload_event = client.event_queue.queue[0]
|
|
|
|
check_web_reload_client_event("web_reload_client_event", reload_event)
|
|
self.assertEqual(
|
|
reload_event,
|
|
dict(
|
|
type="web_reload_client",
|
|
immediate=False,
|
|
id=0,
|
|
),
|
|
)
|
|
|
|
|
|
class FetchQueriesTest(ZulipTestCase):
|
|
def test_queries(self) -> None:
|
|
user = self.example_user("hamlet")
|
|
|
|
self.login_user(user)
|
|
|
|
# Fetch realm like it is done when calling fetch_initial_state_data
|
|
# in production to match the query counts with the actual query
|
|
# count in production.
|
|
realm = get_realm_with_settings(realm_id=user.realm_id)
|
|
|
|
with (
|
|
self.assert_database_query_count(40),
|
|
mock.patch("zerver.lib.events.always_want") as want_mock,
|
|
):
|
|
fetch_initial_state_data(user, realm=realm)
|
|
|
|
expected_counts = dict(
|
|
alert_words=1,
|
|
custom_profile_fields=1,
|
|
default_streams=1,
|
|
default_stream_groups=1,
|
|
drafts=1,
|
|
message=1,
|
|
muted_topics=1,
|
|
muted_users=1,
|
|
onboarding_steps=1,
|
|
presence=1,
|
|
realm=1,
|
|
realm_bot=1,
|
|
realm_domains=1,
|
|
realm_embedded_bots=0,
|
|
realm_incoming_webhook_bots=0,
|
|
realm_emoji=1,
|
|
realm_filters=0,
|
|
realm_linkifiers=0,
|
|
realm_playgrounds=1,
|
|
realm_user=4,
|
|
realm_user_groups=3,
|
|
realm_user_settings_defaults=1,
|
|
recent_private_conversations=1,
|
|
saved_snippets=1,
|
|
scheduled_messages=1,
|
|
starred_messages=1,
|
|
stream=3,
|
|
stop_words=0,
|
|
subscription=4,
|
|
update_display_settings=0,
|
|
update_global_notifications=0,
|
|
update_message_flags=5,
|
|
user_settings=0,
|
|
user_status=1,
|
|
user_topic=1,
|
|
video_calls=0,
|
|
giphy=0,
|
|
)
|
|
|
|
wanted_event_types = {item[0][0] for item in want_mock.call_args_list}
|
|
|
|
self.assertEqual(wanted_event_types, set(expected_counts))
|
|
|
|
# Fetch realm again here so that the cached foreign key fields
|
|
# while testing the above case does not reduce the query count
|
|
# and we test the actual query count for each event type.
|
|
realm = get_realm_with_settings(realm_id=user.realm_id)
|
|
|
|
for event_type in sorted(wanted_event_types):
|
|
count = expected_counts[event_type]
|
|
with self.assert_database_query_count(count):
|
|
if event_type == "update_message_flags":
|
|
event_types = ["update_message_flags", "message"]
|
|
else:
|
|
event_types = [event_type]
|
|
|
|
fetch_initial_state_data(user, realm=realm, event_types=event_types)
|
|
|
|
|
|
class TestEventsRegisterAllPublicStreamsDefaults(ZulipTestCase):
|
|
@override
|
|
def setUp(self) -> None:
|
|
super().setUp()
|
|
self.user_profile = self.example_user("hamlet")
|
|
self.email = self.user_profile.email
|
|
|
|
def test_use_passed_all_public_true_default_false(self) -> None:
|
|
self.user_profile.default_all_public_streams = False
|
|
self.user_profile.save()
|
|
result = _default_all_public_streams(self.user_profile, True)
|
|
self.assertTrue(result)
|
|
|
|
def test_use_passed_all_public_true_default(self) -> None:
|
|
self.user_profile.default_all_public_streams = True
|
|
self.user_profile.save()
|
|
result = _default_all_public_streams(self.user_profile, True)
|
|
self.assertTrue(result)
|
|
|
|
def test_use_passed_all_public_false_default_false(self) -> None:
|
|
self.user_profile.default_all_public_streams = False
|
|
self.user_profile.save()
|
|
result = _default_all_public_streams(self.user_profile, False)
|
|
self.assertFalse(result)
|
|
|
|
def test_use_passed_all_public_false_default_true(self) -> None:
|
|
self.user_profile.default_all_public_streams = True
|
|
self.user_profile.save()
|
|
result = _default_all_public_streams(self.user_profile, False)
|
|
self.assertFalse(result)
|
|
|
|
def test_use_true_default_for_none(self) -> None:
|
|
self.user_profile.default_all_public_streams = True
|
|
self.user_profile.save()
|
|
result = _default_all_public_streams(self.user_profile, None)
|
|
self.assertTrue(result)
|
|
|
|
def test_use_false_default_for_none(self) -> None:
|
|
self.user_profile.default_all_public_streams = False
|
|
self.user_profile.save()
|
|
result = _default_all_public_streams(self.user_profile, None)
|
|
self.assertFalse(result)
|
|
|
|
|
|
class TestEventsRegisterNarrowDefaults(ZulipTestCase):
|
|
@override
|
|
def setUp(self) -> None:
|
|
super().setUp()
|
|
self.user_profile = self.example_user("hamlet")
|
|
self.email = self.user_profile.email
|
|
self.stream = get_stream("Verona", self.user_profile.realm)
|
|
|
|
def test_use_passed_narrow_no_default(self) -> None:
|
|
self.user_profile.default_events_register_stream_id = None
|
|
self.user_profile.save()
|
|
result = _default_narrow(self.user_profile, [["stream", "my_stream"]])
|
|
self.assertEqual(result, [["stream", "my_stream"]])
|
|
|
|
def test_use_passed_narrow_with_default(self) -> None:
|
|
self.user_profile.default_events_register_stream_id = self.stream.id
|
|
self.user_profile.save()
|
|
result = _default_narrow(self.user_profile, [["stream", "my_stream"]])
|
|
self.assertEqual(result, [["stream", "my_stream"]])
|
|
|
|
def test_use_default_if_narrow_is_empty(self) -> None:
|
|
self.user_profile.default_events_register_stream_id = self.stream.id
|
|
self.user_profile.save()
|
|
result = _default_narrow(self.user_profile, [])
|
|
self.assertEqual(result, [["stream", "Verona"]])
|
|
|
|
def test_use_narrow_if_default_is_none(self) -> None:
|
|
self.user_profile.default_events_register_stream_id = None
|
|
self.user_profile.save()
|
|
result = _default_narrow(self.user_profile, [])
|
|
self.assertEqual(result, [])
|
|
|
|
|
|
class TestGetUserAPIDataSystemBotRealm(ZulipTestCase):
|
|
def test_get_users_api_data_on_system_bot_realm(self) -> None:
|
|
realm = get_realm(settings.SYSTEM_BOT_REALM)
|
|
result = get_users_for_api(
|
|
realm,
|
|
self.example_user("hamlet"),
|
|
client_gravatar=True,
|
|
user_avatar_url_field_optional=True,
|
|
)
|
|
|
|
for bot_email in settings.CROSS_REALM_BOT_EMAILS:
|
|
bot_profile = get_system_bot(bot_email, realm.id)
|
|
self.assertTrue(bot_profile.id in result)
|
|
self.assertTrue(result[bot_profile.id]["is_system_bot"])
|
|
|
|
|
|
class TestUserPresenceUpdatesDisabled(ZulipTestCase):
|
|
# For this test, we verify do_update_user_presence doesn't send
|
|
# events for organizations with more than
|
|
# USER_LIMIT_FOR_SENDING_PRESENCE_UPDATE_EVENTS users, unless
|
|
# force_send_update is passed.
|
|
@override_settings(USER_LIMIT_FOR_SENDING_PRESENCE_UPDATE_EVENTS=3)
|
|
def test_presence_events_disabled_on_larger_realm(self) -> None:
|
|
with self.capture_send_event_calls(expected_num_events=1):
|
|
do_update_user_presence(
|
|
self.example_user("cordelia"),
|
|
get_client("website"),
|
|
timezone_now(),
|
|
UserPresence.LEGACY_STATUS_ACTIVE_INT,
|
|
force_send_update=True,
|
|
)
|
|
|
|
with self.capture_send_event_calls(expected_num_events=0):
|
|
do_update_user_presence(
|
|
self.example_user("hamlet"),
|
|
get_client("website"),
|
|
timezone_now(),
|
|
UserPresence.LEGACY_STATUS_ACTIVE_INT,
|
|
force_send_update=False,
|
|
)
|