Merge lp:~facundo/ubuntu-rest-scopes/corrupt-reddit-response into lp:ubuntu-rest-scopes

Proposed by Facundo Batista
Status: Merged
Approved by: Facundo Batista
Approved revision: 529
Merged at revision: 529
Proposed branch: lp:~facundo/ubuntu-rest-scopes/corrupt-reddit-response
Merge into: lp:ubuntu-rest-scopes
Diff against target: 187 lines (+43/-22)
2 files modified
src/scopes/reddit.py (+19/-10)
src/scopes/tests/test_reddit.py (+24/-12)
To merge this branch: bzr merge lp:~facundo/ubuntu-rest-scopes/corrupt-reddit-response
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+299700@code.launchpad.net

Commit message

Support corrupt/broken responses from reddit.

Description of the change

Support corrupt/broken responses from reddit.

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

Code LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/scopes/reddit.py'
2--- src/scopes/reddit.py 2016-06-07 14:20:44 +0000
3+++ src/scopes/reddit.py 2016-07-11 14:30:27 +0000
4@@ -1,10 +1,11 @@
5-# Copyright 2014-2015 Canonical
6+# Copyright 2014-2016 Canonical
7 # All Rights Reserved
8
9 """The Reddit scope."""
10
11 import urllib
12 import json
13+import logging
14
15 from ..scopes import SimpleApp
16 from ..translator import translator
17@@ -13,6 +14,8 @@
18 # this module is generated by a "make build"
19 from versioninfo import version_info
20
21+logger = logging.getLogger("restscopes.reddit")
22+
23
24 # the different URIs to get info from Reddit
25 POPULAR_SUBREDDITS = 'http://www.reddit.com/subreddits/popular.json?limit=50'
26@@ -176,9 +179,15 @@
27 def _get_results(self, url):
28 """Call the Reddit API."""
29 hdr = {'User-Agent': "Reddit Ubuntu Rest Scope " + str(version_info['revno'])}
30- response = self.urlread(url, headers=hdr)
31- results = json.loads(response.decode('utf-8'))
32- return results
33+ try:
34+ response = self.urlread(url, headers=hdr)
35+ results = json.loads(response.decode('utf-8'))
36+ except Exception as err:
37+ logger.debug("Error %s(%s) when hitting: %r", err.__class__.__name__, err, url)
38+ return []
39+
40+ children = results['data']['children']
41+ return children
42
43 def _get_available_departments(self, department, locale):
44 """Use popular subreddits to build the departments list."""
45@@ -188,7 +197,7 @@
46 current['label'] = translator('Front page', locale)
47 current['has_subdepartments'] = True
48 # Departments for reddit are a flat list, always display them
49- for r in self._get_results(POPULAR_SUBREDDITS)['data']['children']:
50+ for r in self._get_results(POPULAR_SUBREDDITS):
51 sub = {}
52 name = r['data']['display_name']
53 sub['label'] = name
54@@ -221,14 +230,14 @@
55 uri = SURFACING_DEP_URI % dict(dep=department, limit=limit)
56 yield dict(category=localized_category(THREAD_CATEGORY,
57 locale))
58- for post in self._get_results(uri)['data']['children']:
59+ for post in self._get_results(uri):
60 yield dict(result=_parse_post(post, query,
61 locale, platform))
62 else:
63 uri = SURFACING_URI % dict(limit=limit)
64 yield dict(category=localized_category(THREAD_CATEGORY,
65 locale))
66- for post in self._get_results(uri)['data']['children']:
67+ for post in self._get_results(uri):
68 yield dict(result=_parse_post(post, query,
69 locale, platform))
70 else:
71@@ -238,14 +247,14 @@
72 subs_uri = SUBREDDIT_SEARCH_URI % dict(query=query_cleaned,
73 limit=limit)
74 yield dict(category=localized_category(SUBREDDIT_CATEGORY, locale))
75- for subreddit in self._get_results(subs_uri)['data']['children']:
76+ for subreddit in self._get_results(subs_uri):
77 yield dict(result=_parse_subreddit(subreddit, query, locale))
78
79 # Search posts
80 posts_uri = POST_SEARCH_URI % dict(query=query_cleaned,
81 limit=limit)
82 yield dict(category=localized_category(S_THREAD_CATEGORY, locale))
83- for post in self._get_results(posts_uri)['data']['children']:
84+ for post in self._get_results(posts_uri):
85 yield dict(result=_parse_post(post, query,
86 locale, platform))
87
88@@ -301,7 +310,7 @@
89 'id': 'image',
90 'type': 'image',
91 'source': result['art'],
92- })
93+ })
94 # create a 'header' widget
95 header = dict(widget={
96 'id': 'header',
97
98=== modified file 'src/scopes/tests/test_reddit.py'
99--- src/scopes/tests/test_reddit.py 2016-03-14 07:51:29 +0000
100+++ src/scopes/tests/test_reddit.py 2016-07-11 14:30:27 +0000
101@@ -1,6 +1,6 @@
102 # -*- coding: utf-8 -*-
103
104-# Copyright 2014-2015 Canonical
105+# Copyright 2014-2016 Canonical
106 # All Rights Reserved
107
108 """Tests for the Simple App base stuff."""
109@@ -11,7 +11,7 @@
110 from mock import patch
111
112 from src.scopes import reddit
113-from src.scopes.tests import get_fixture
114+from src.scopes.tests import get_fixture, SetupLogChecker
115
116 from versioninfo import version_info
117
118@@ -22,22 +22,34 @@
119 class SearchTestCase(TestCase):
120 """Tests for the search function."""
121
122- def test_result_retrieval(self):
123+ def setUp(self):
124+ super(SearchTestCase, self).setUp()
125+ SetupLogChecker(self, 'restscopes')
126+
127+ def test_result_retrieval_ok(self):
128 app = reddit.App(CONFIG)
129- fake_data = {'test': 123}
130+ fake_data = {'data': {'children': ['test1', 'test2']}}
131 with patch.object(app, 'urlread') as mock_urlread:
132 mock_urlread.return_value = json.dumps(fake_data)
133 resp = app._get_results('test url')
134- self.assertEqual(resp, fake_data)
135+ self.assertEqual(resp, ['test1', 'test2'])
136 ua = "Reddit Ubuntu Rest Scope " + str(version_info['revno'])
137 mock_urlread.assert_called_with('test url', headers={'User-Agent': ua})
138
139+ def test_result_retrieval_broken(self):
140+ app = reddit.App(CONFIG)
141+ with patch.object(app, 'urlread') as mock_urlread:
142+ mock_urlread.return_value = "not a json"
143+ resp = app._get_results('test url')
144+ self.assertEqual(resp, [])
145+ self.assertLogged("Error", "when hitting", "test url", "ValueError")
146+
147 def test_surfacing(self):
148 app = reddit.App(CONFIG)
149+ results_data = json.loads(get_fixture('reddit-front.json'))['data']['children']
150 with patch.object(app, '_get_available_departments') as mockdep:
151 with patch.object(app, '_get_results') as mock:
152- mock.return_value = json.loads(
153- get_fixture('reddit-front.json'))
154+ mock.return_value = results_data
155 mockdep.return_value = {}
156 response = list(app.search(query='',
157 platform='desktop',
158@@ -139,14 +151,14 @@
159 'attributes': [
160 {'style': 'highlighted', 'value': '171'},
161 {'style': 'default', 'value': '242 comments'}]
162- }
163+ }
164 self.assertEqual(response, should)
165
166 def test_available_departments(self):
167 app = reddit.App(CONFIG)
168+ results_data = json.loads(get_fixture('reddit-departments.json'))['data']['children']
169 with patch.object(app, '_get_results') as mock:
170- mock.return_value = json.loads(
171- get_fixture('reddit-departments.json'))
172+ mock.return_value = results_data
173 response = app._get_available_departments(None, 'EN')
174
175 should = {'canned_query': 'scope://com.canonical.scopes.reddit',
176@@ -169,9 +181,9 @@
177
178 def test_available_departments_with_new_dep(self):
179 app = reddit.App(CONFIG)
180+ results_data = json.loads(get_fixture('reddit-departments.json'))['data']['children']
181 with patch.object(app, '_get_results') as mock:
182- mock.return_value = json.loads(
183- get_fixture('reddit-departments.json'))
184+ mock.return_value = results_data
185 response = app._get_available_departments('halflife3', 'EN')
186
187 should = {'canned_query': 'scope://com.canonical.scopes.reddit',

Subscribers

People subscribed via source and target branches