2016-09-16 15:25:04 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2017-03-03 19:01:52 +01:00
|
|
|
from typing import Any, Callable, Dict, Iterable, List, Tuple
|
2016-09-16 15:25:04 +02:00
|
|
|
|
2017-01-24 07:54:18 +01:00
|
|
|
from django.test import override_settings
|
2016-11-10 19:30:09 +01:00
|
|
|
from zerver.lib.test_classes import (
|
2016-09-16 15:25:04 +02:00
|
|
|
ZulipTestCase,
|
|
|
|
)
|
|
|
|
from zerver.lib.utils import statsd
|
|
|
|
|
|
|
|
import mock
|
|
|
|
import ujson
|
|
|
|
|
|
|
|
def fix_params(raw_params):
|
|
|
|
# type: (Dict[str, Any]) -> Dict[str, str]
|
|
|
|
# A few of our few legacy endpoints need their
|
|
|
|
# individual parameters serialized as JSON.
|
|
|
|
return {k: ujson.dumps(v) for k, v in raw_params.items()}
|
|
|
|
|
2017-11-05 11:49:43 +01:00
|
|
|
class StatsMock:
|
2016-09-16 15:25:04 +02:00
|
|
|
def __init__(self, settings):
|
2017-11-02 17:26:38 +01:00
|
|
|
# type: (Callable[..., Any]) -> None
|
2016-09-16 15:25:04 +02:00
|
|
|
self.settings = settings
|
|
|
|
self.real_impl = statsd
|
2017-05-07 20:03:06 +02:00
|
|
|
self.func_calls = [] # type: List[Tuple[str, Iterable[Any]]]
|
2016-09-16 15:25:04 +02:00
|
|
|
|
|
|
|
def __getattr__(self, name):
|
2017-11-02 17:26:38 +01:00
|
|
|
# type: (str) -> Callable[..., Any]
|
2016-09-16 15:25:04 +02:00
|
|
|
def f(*args):
|
|
|
|
# type: (*Any) -> None
|
|
|
|
with self.settings(STATSD_HOST=''):
|
|
|
|
getattr(self.real_impl, name)(*args)
|
|
|
|
self.func_calls.append((name, args))
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
|
|
|
class TestReport(ZulipTestCase):
|
|
|
|
def test_send_time(self):
|
|
|
|
# type: () -> None
|
2017-05-24 05:08:49 +02:00
|
|
|
email = self.example_email('hamlet')
|
2016-09-16 15:25:04 +02:00
|
|
|
self.login(email)
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
time=5,
|
|
|
|
received=6,
|
|
|
|
displayed=7,
|
|
|
|
locally_echoed='true',
|
|
|
|
rendered_content_disparity='true',
|
|
|
|
)
|
|
|
|
|
|
|
|
stats_mock = StatsMock(self.settings)
|
|
|
|
with mock.patch('zerver.views.report.statsd', wraps=stats_mock):
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/send_times", params)
|
2016-09-16 15:25:04 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
expected_calls = [
|
2017-03-13 17:50:28 +01:00
|
|
|
('timing', ('endtoend.send_time.zulip', 5)),
|
|
|
|
('timing', ('endtoend.receive_time.zulip', 6)),
|
|
|
|
('timing', ('endtoend.displayed_time.zulip', 7)),
|
2016-09-16 15:25:04 +02:00
|
|
|
('incr', ('locally_echoed',)),
|
|
|
|
('incr', ('render_disparity',)),
|
|
|
|
]
|
|
|
|
self.assertEqual(stats_mock.func_calls, expected_calls)
|
|
|
|
|
|
|
|
def test_narrow_time(self):
|
|
|
|
# type: () -> None
|
2017-05-24 05:08:49 +02:00
|
|
|
email = self.example_email('hamlet')
|
2016-09-16 15:25:04 +02:00
|
|
|
self.login(email)
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
initial_core=5,
|
|
|
|
initial_free=6,
|
|
|
|
network=7,
|
|
|
|
)
|
|
|
|
|
|
|
|
stats_mock = StatsMock(self.settings)
|
|
|
|
with mock.patch('zerver.views.report.statsd', wraps=stats_mock):
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/narrow_times", params)
|
2016-09-16 15:25:04 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
expected_calls = [
|
2017-03-13 17:50:28 +01:00
|
|
|
('timing', ('narrow.initial_core.zulip', 5)),
|
|
|
|
('timing', ('narrow.initial_free.zulip', 6)),
|
|
|
|
('timing', ('narrow.network.zulip', 7)),
|
2016-09-16 15:25:04 +02:00
|
|
|
]
|
|
|
|
self.assertEqual(stats_mock.func_calls, expected_calls)
|
|
|
|
|
|
|
|
def test_unnarrow_time(self):
|
|
|
|
# type: () -> None
|
2017-05-24 05:08:49 +02:00
|
|
|
email = self.example_email('hamlet')
|
2016-09-16 15:25:04 +02:00
|
|
|
self.login(email)
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
initial_core=5,
|
|
|
|
initial_free=6,
|
|
|
|
)
|
|
|
|
|
|
|
|
stats_mock = StatsMock(self.settings)
|
|
|
|
with mock.patch('zerver.views.report.statsd', wraps=stats_mock):
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/unnarrow_times", params)
|
2016-09-16 15:25:04 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
expected_calls = [
|
2017-03-13 17:50:28 +01:00
|
|
|
('timing', ('unnarrow.initial_core.zulip', 5)),
|
|
|
|
('timing', ('unnarrow.initial_free.zulip', 6)),
|
2016-09-16 15:25:04 +02:00
|
|
|
]
|
|
|
|
self.assertEqual(stats_mock.func_calls, expected_calls)
|
|
|
|
|
2017-01-24 07:54:18 +01:00
|
|
|
@override_settings(BROWSER_ERROR_REPORTING=True)
|
2016-09-16 15:25:04 +02:00
|
|
|
def test_report_error(self):
|
|
|
|
# type: () -> None
|
2017-05-24 05:08:49 +02:00
|
|
|
email = self.example_email('hamlet')
|
2016-09-16 15:25:04 +02:00
|
|
|
self.login(email)
|
|
|
|
|
|
|
|
params = fix_params(dict(
|
|
|
|
message='hello',
|
|
|
|
stacktrace='trace',
|
|
|
|
ui_message=True,
|
|
|
|
user_agent='agent',
|
|
|
|
href='href',
|
|
|
|
log='log',
|
2017-10-12 03:43:34 +02:00
|
|
|
more_info=dict(foo='bar', draft_content="**draft**"),
|
2016-09-16 15:25:04 +02:00
|
|
|
))
|
|
|
|
|
|
|
|
publish_mock = mock.patch('zerver.views.report.queue_json_publish')
|
|
|
|
subprocess_mock = mock.patch(
|
|
|
|
'zerver.views.report.subprocess.check_output',
|
|
|
|
side_effect=KeyError('foo')
|
|
|
|
)
|
|
|
|
with publish_mock as m, subprocess_mock:
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/error", params)
|
2016-09-16 15:25:04 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
report = m.call_args[0][1]['report']
|
|
|
|
for k in set(params) - set(['ui_message', 'more_info']):
|
|
|
|
self.assertEqual(report[k], params[k])
|
|
|
|
|
2017-10-12 03:43:34 +02:00
|
|
|
self.assertEqual(report['more_info'], dict(foo='bar', draft_content="'**xxxxx**'"))
|
2016-09-16 15:25:04 +02:00
|
|
|
self.assertEqual(report['user_email'], email)
|
|
|
|
|
2017-10-13 02:22:47 +02:00
|
|
|
# Teset with no more_info
|
|
|
|
del params['more_info']
|
|
|
|
with publish_mock as m, subprocess_mock:
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/error", params)
|
2017-10-13 02:22:47 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2017-01-24 07:54:18 +01:00
|
|
|
with self.settings(BROWSER_ERROR_REPORTING=False):
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/error", params)
|
2016-09-16 15:25:04 +02:00
|
|
|
self.assert_json_success(result)
|
2017-03-01 04:19:56 +01:00
|
|
|
|
|
|
|
# If js_source_map is present, then the stack trace should be annotated.
|
2017-03-01 06:42:31 +01:00
|
|
|
# DEVELOPMENT=False and TEST_SUITE=False are necessary to ensure that
|
2017-03-01 04:19:56 +01:00
|
|
|
# js_source_map actually gets instantiated.
|
|
|
|
with \
|
2017-03-01 06:42:31 +01:00
|
|
|
self.settings(DEVELOPMENT=False, TEST_SUITE=False), \
|
2017-03-01 04:19:56 +01:00
|
|
|
mock.patch('zerver.lib.unminify.SourceMap.annotate_stacktrace') as annotate:
|
2017-10-16 22:07:19 +02:00
|
|
|
result = self.client_post("/json/report/error", params)
|
2017-03-01 04:19:56 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
# fix_params (see above) adds quotes when JSON encoding.
|
|
|
|
annotate.assert_called_once_with('"trace"')
|