Added more googlesearch tests
ADD
zulip_bots/zulip_bots/bots/googlesearch/fixtures/test_attribute_error.json
+{
+ "request": {
+ "api_url": "http://www.google.com/search",
+ "params": {
+ "q": "test"
+ }
+ },
+ "response": "<head></head><body><div id='foo'></div></body>",
+ "response-headers": {
+ "status": 200,
+ "content-type": "text/html; charset=utf-8"
+ }
+}

ADD
zulip_bots/zulip_bots/bots/googlesearch/fixtures/test_ignore_links.json
+{
+ "request": {
+ "api_url": "http://www.google.com/search",
+ "params": {
+ "q": "zulip"
+ }
+ },
+ "response": "<head></head><body><div id='search'><a href='/url?url=webcache.googleusercontent.com/foo/bar'>Cached</a><a href='/?url'></a><a href='foo bar'></a><a></a><a href='/url?url=https%3A%2F%2Fzulipchat.com%2F'>Zulip</a></div></body>",
+ "response-headers": {
+ "status": 200,
+ "content-type": "text/html; charset=utf-8"
+ }
+}

MODIFY
zulip_bots/zulip_bots/bots/googlesearch/googlesearch.py
zulip_bots/zulip_bots/bots/googlesearch/googlesearch.py
@@ -27,12 +27,10 @@ def google_search(keywords: str) -> List[Dict[str, str]]:
except KeyError:
continue
# Link must start with '/url?', as these are the search result links
- if (not link.startswith('/url?')):
+ if not link.startswith('/url?'):
continue
# Makes sure a hidden 'cached' result isn't displayed
- if (a.text.strip() == 'Cached' and 'webcache.googleusercontent.com'):
- continue
- if (a.text.strip() == ''):
+ if a.text.strip() == 'Cached' and 'webcache.googleusercontent.com' in a['href']:
continue
# a.text: The name of the page
result = {'url': "https://www.google.com{}".format(link),
@@ -62,20 +60,8 @@ def get_google_result(search_keywords: str) -> str:
if (len(results) == 0):
return "Found no results."
return "Found Result: [{}]({})".format(results[0]['name'], results[0]['url'])
- except ConnectionError as c_err:
- return "Error: Failed to connect. {}.".format(c_err)
- except AttributeError as a_err:
- # google.search query failed and urls is of object
- # 'NoneType'
- logging.exception(str(a_err))
- return "Error: Google search failed with a NoneType result. {}.".format(a_err)
- except TypeError as t_err:
- # google.search query failed and returned None
- # This technically should not happen but the prior
- # error check assumed this behavior
- logging.exception(str(t_err))
- return "Error: Google search function failed. {}.".format(t_err)
except Exception as e:
+ logging.exception(str(e))
return 'Error: Search failed. {}.'.format(e)
class GoogleSearchHandler(object):

MODIFY
zulip_bots/zulip_bots/bots/googlesearch/test_googlesearch.py
zulip_bots/zulip_bots/bots/googlesearch/test_googlesearch.py
from zulip_bots.test_lib import StubBotTestCase
+from unittest.mock import patch
+
class TestGoogleSearchBot(StubBotTestCase):
bot_name = 'googlesearch'
@@ -28,3 +30,19 @@ class TestGoogleSearchBot(StubBotTestCase):
def test_bot_no_results(self) -> None:
with self.mock_http_conversation('test_no_result'):
self.verify_reply('no res', 'Found no results.')
+
+ def test_attribute_error(self) -> None:
+ with self.mock_http_conversation('test_attribute_error'), \
+ patch('logging.exception'):
+ self.verify_reply('test', 'Error: Search failed. \'NoneType\' object has no attribute \'findAll\'.')
+
+ # Makes sure cached results, irrelevant links, or empty results are not displayed
+ def test_ignore_links(self) -> None:
+ with self.mock_http_conversation('test_ignore_links'):
+ # The bot should ignore all links, apart from the zulip link at the end (googlesearch.py lines 23-38)
+ # Then it should send the zulip link
+ # See test_ignore_links.json
+ self.verify_reply(
+ 'zulip',
+ 'Found Result: [Zulip](https://www.google.com/url?url=https%3A%2F%2Fzulipchat.com%2F)'
+ )

Added more googlesearch tests