Files
zulip/zerver/tests/test_middleware.py
Tim Abbott 9c3f38a564 docs: Automatically construct OpenAPI metadata for help center.
This is somewhat hacky, in that in order to do what we're doing, we
need to parse the HTML of the rendered page to extract the first
paragraph to include in the open graph description field.  But
BeautifulSoup does a good job of it.

This carries a nontrivial performance penalty for loading these pages,
but overall /help/ is a low-traffic site compared to the main app, so
it doesn't matter much.

(As a sidenote, it wouldn't be a bad idea to cache this stuff).

There's lots of things we can improve in this, largely through editing
the articles, but we can deal with that over time.

Thanks to Rishi for writing all the tests.
2018-12-19 10:18:20 -08:00

115 lines
5.6 KiB
Python

import time
from django.http import HttpResponse
from django.test import override_settings
from unittest.mock import Mock, patch
from zerver.lib.test_classes import ZulipTestCase
from zerver.middleware import is_slow_query
from zerver.middleware import write_log_line
class SlowQueryTest(ZulipTestCase):
SLOW_QUERY_TIME = 10
log_data = {'extra': '[transport=websocket]',
'time_started': 0,
'bugdown_requests_start': 0,
'bugdown_time_start': 0,
'remote_cache_time_start': 0,
'remote_cache_requests_start': 0}
def test_is_slow_query(self) -> None:
self.assertFalse(is_slow_query(1.1, '/some/random/url'))
self.assertTrue(is_slow_query(2, '/some/random/url'))
self.assertTrue(is_slow_query(5.1, '/activity'))
self.assertFalse(is_slow_query(2, '/activity'))
self.assertFalse(is_slow_query(2, '/json/report/error'))
self.assertFalse(is_slow_query(2, '/api/v1/deployments/report_error'))
self.assertFalse(is_slow_query(2, '/realm_activity/whatever'))
self.assertFalse(is_slow_query(2, '/user_activity/whatever'))
self.assertFalse(is_slow_query(9, '/accounts/webathena_kerberos_login/'))
self.assertTrue(is_slow_query(11, '/accounts/webathena_kerberos_login/'))
@override_settings(SLOW_QUERY_LOGS_STREAM="logs")
@patch('logging.info')
def test_slow_query_log(self, mock_logging_info: Mock) -> None:
self.log_data['time_started'] = time.time() - self.SLOW_QUERY_TIME
write_log_line(self.log_data, path='/socket/open', method='SOCKET',
remote_ip='123.456.789.012', email='unknown', client_name='?')
last_message = self.get_last_message()
self.assertEqual(last_message.sender.email, "error-bot@zulip.com")
self.assertIn("logs", str(last_message.recipient))
self.assertEqual(last_message.topic_name(), "testserver: slow queries")
self.assertRegexpMatches(last_message.content,
r"123\.456\.789\.012 SOCKET 200 10\.\ds .*")
@override_settings(ERROR_BOT=None)
@patch('logging.info')
@patch('zerver.lib.actions.internal_send_message')
def test_slow_query_log_without_error_bot(self, mock_internal_send_message: Mock,
mock_logging_info: Mock) -> None:
self.log_data['time_started'] = time.time() - self.SLOW_QUERY_TIME
write_log_line(self.log_data, path='/socket/open', method='SOCKET',
remote_ip='123.456.789.012', email='unknown', client_name='?')
mock_internal_send_message.assert_not_called()
class OpenGraphTest(ZulipTestCase):
def check_title_and_description(self, path: str, title: str, description: str) -> None:
response = self.client_get(path)
self.assert_in_success_response([
# Open graph
'<meta property="og:title" content="{}">'.format(title),
'<meta property="og:description" content="{}">'.format(description),
# Twitter
'<meta property="twitter:title" content="{}">'.format(title),
'<meta name="twitter:description" content="{}">'.format(description),
], response)
def test_admonition_and_link(self) -> None:
# disable-message-edit-history starts with an {!admin-only.md!}, and has a link
# in the first paragraph.
self.check_title_and_description(
'/help/disable-message-edit-history',
"Disable message edit history (Zulip Help Center)",
"By default, Zulip displays messages that have been edited with an EDITED tag, " +
"and users can view the edit history of a message.")
def test_settings_tab(self) -> None:
# deactivate-your-account starts with {settings_tab|your-account}
self.check_title_and_description(
'/help/deactivate-your-account',
"Deactivate your account (Zulip Help Center)",
# Ideally, we'd grab the second and third paragraphs as well, if
# the first paragraph is this short
"Go to Your account.")
def test_tabs(self) -> None:
# logging-out starts with {start_tabs}
self.check_title_and_description(
'/help/logging-out',
"Logging out (Zulip Help Center)",
# Ideally we'd do something better here
"")
def test_index_pages(self) -> None:
self.check_title_and_description(
'/help/',
"Zulip Help Center",
("Zulip is a group chat app. Its most distinctive characteristic is that "
"conversation within an organization is divided into “streams” and further "
"subdivided into “topics”, so that much finer-grained conversations are possible "
"than with IRC or other chat tools."))
self.check_title_and_description(
'/api/',
"Zulip API Documentation",
("Zulip's APIs allow you to integrate other services with Zulip. This "
"guide should help you find the API you need:"))
def test_nonexistent_page(self) -> None:
response = self.client_get('/help/not-a-real-page')
# Test that our open graph logic doesn't throw a 500
self.assertEqual(response.status_code, 404)
self.assert_in_response(
# Probably we should make this "Zulip Help Center"
'<meta property="og:title" content="No such article. (Zulip Help Center)">', response)
self.assert_in_response('<meta property="og:description" content="No such article.">', response)