diff --git a/zerver/lib/bugdown/testing_mocks.py b/zerver/lib/bugdown/testing_mocks.py index 43813b73e1..31c8ebcb90 100644 --- a/zerver/lib/bugdown/testing_mocks.py +++ b/zerver/lib/bugdown/testing_mocks.py @@ -192,10 +192,3 @@ def twitter(tweet_id): return ujson.loads(MEDIA_TWEET) else: return None - - -def fake_urlembed_data(): - # type: () -> Dict[text_type, text_type] - return { - 'title': 'Test', - 'description': 'Short description'} diff --git a/zerver/lib/test_helpers.py b/zerver/lib/test_helpers.py index d811bd3714..1056df136f 100644 --- a/zerver/lib/test_helpers.py +++ b/zerver/lib/test_helpers.py @@ -216,6 +216,17 @@ class HostRequestMock(object): # type: () -> text_type return self.host +class MockPythonResponse(object): + def __init__(self, text, status_code): + # type: (text_type, int) -> None + self.text = text + self.status_code = status_code + + @property + def ok(self): + # type: () -> bool + return self.status_code == 200 + INSTRUMENTING = os.environ.get('TEST_INSTRUMENT_URL_COVERAGE', '') == 'TRUE' INSTRUMENTED_CALLS = [] # type: List[Dict[str, Any]] diff --git a/zerver/lib/url_preview/preview.py b/zerver/lib/url_preview/preview.py index e9e5209ed5..b8d245e270 100644 --- a/zerver/lib/url_preview/preview.py +++ b/zerver/lib/url_preview/preview.py @@ -6,9 +6,7 @@ from six import text_type from typing import Any, Optional from typing.re import Match import requests -from django.conf import settings from zerver.lib.cache import cache_with_key, get_cache_with_key -from zerver.lib.bugdown import testing_mocks from zerver.lib.url_preview.oembed import get_oembed_data from zerver.lib.url_preview.parsers import OpenGraphParser, GenericParser @@ -38,8 +36,6 @@ def get_link_embed_data(url, maxwidth=640, maxheight=480): # type: (text_type, Optional[int], Optional[int]) -> Any if not is_link(url): return None - if settings.TEST_SUITE: - return testing_mocks.fake_urlembed_data() # Fetch information from URL. # We are using three sources in next order: # 1. OEmbed diff --git a/zerver/tests/test_link_embed.py b/zerver/tests/test_link_embed.py index b0982895e5..aeee5e6e10 100644 --- a/zerver/tests/test_link_embed.py +++ b/zerver/tests/test_link_embed.py @@ -5,14 +5,30 @@ from __future__ import print_function import mock import ujson from typing import Any +from requests.exceptions import ConnectionError from django.test import override_settings +from zerver.models import Recipient, Message from zerver.lib.test_classes import ZulipTestCase +from zerver.lib.test_helpers import MockPythonResponse +from zerver.worker.queue_processors import FetchLinksEmbedData +from zerver.lib.url_preview.preview import get_link_embed_data from zerver.lib.url_preview.oembed import get_oembed_data from zerver.lib.url_preview.parsers import ( OpenGraphParser, GenericParser) +TEST_CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + 'LOCATION': 'default', + }, + 'database': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + 'LOCATION': 'url-preview', + } +} + @override_settings(INLINE_URL_EMBED_PREVIEW=True) class OembedTestCase(ZulipTestCase): @mock.patch('pyoembed.requests.get') @@ -84,3 +100,117 @@ class GenericParserTestCase(ZulipTestCase): result = parser.extract_data() self.assertEqual(result.get('title'), 'Test title') self.assertEqual(result.get('description'), 'Description text') + + def test_extract_image(self): + # type: () -> None + html = """ + + +

Main header

+ +
+

Description text

+
+ + + """ + parser = GenericParser(html) + result = parser.extract_data() + self.assertEqual(result.get('title'), 'Main header') + self.assertEqual(result.get('description'), 'Description text') + self.assertEqual(result.get('image'), 'http://test.com/test.jpg') + + def test_extract_description(self): + # type: () -> None + html = """ + + +
+
+

Description text

+
+
+ + + """ + parser = GenericParser(html) + result = parser.extract_data() + self.assertEqual(result.get('description'), 'Description text') + + html = """ + + + + + """ + parser = GenericParser(html) + result = parser.extract_data() + self.assertEqual(result.get('description'), 'description 123') + + html = "" + parser = GenericParser(html) + result = parser.extract_data() + self.assertIsNone(result.get('description')) + + +class PreviewTestCase(ZulipTestCase): + def test_get_link_embed_data(self): + # type: () -> None + html = """ + + + Test title + + + + + + +

Main header

+

Description text

+ + + """ + url = 'http://test.org/' + msg_id = self.send_message( + "hamlet@zulip.com", "cordelia@zulip.com", + Recipient.PERSONAL, subject="url", content=url) + response = MockPythonResponse(html, 200) + mocked_response = mock.Mock( + side_effect=lambda k: {url: response}.get(k, MockPythonResponse('', 404))) + event = { + 'message_id': msg_id, + 'urls': [url], + 'message_content': url} + with self.settings(INLINE_URL_EMBED_PREVIEW=True, TEST_SUITE=False, CACHES=TEST_CACHES): + with mock.patch('requests.get', mocked_response): + FetchLinksEmbedData().consume(event) + msg = Message.objects.get(id=msg_id) + self.assertIn( + 'The Rock'.format(url), + msg.rendered_content) + + def test_http_error_get_data(self): + # type: () -> None + url = 'http://test.org/' + msg_id = self.send_message( + "hamlet@zulip.com", "cordelia@zulip.com", + Recipient.PERSONAL, subject="url", content=url) + event = { + 'message_id': msg_id, + 'urls': [url], + 'message_content': url} + with self.settings(INLINE_URL_EMBED_PREVIEW=True, TEST_SUITE=False, CACHES=TEST_CACHES): + with mock.patch('requests.get', mock.Mock(side_effect=ConnectionError())): + with mock.patch('logging.error') as error_mock: + FetchLinksEmbedData().consume(event) + self.assertEqual(error_mock.call_count, 1) + msg = Message.objects.get(id=msg_id) + self.assertEqual( + '

http://test.org/

', + msg.rendered_content) + + def test_invalid_link(self): + # type: () -> None + with self.settings(INLINE_URL_EMBED_PREVIEW=True, TEST_SUITE=False, CACHES=TEST_CACHES): + self.assertIsNone(get_link_embed_data('com.notvalidlink'))