Status: | Merged |
---|---|
Merged at revision: | 2713 |
Proposed branch: | lp:~trb143/openlp/httpfixes |
Merge into: | lp:openlp |
Diff against target: |
1185 lines (+543/-512) 8 files modified
openlp/core/common/httputils.py (+255/-0) openlp/core/lib/webpagereader.py (+0/-182) openlp/core/ui/firsttimeform.py (+12/-81) openlp/plugins/bibles/lib/importers/http.py (+1/-1) tests/functional/openlp_core_common/test_httputils.py (+274/-0) tests/functional/openlp_core_lib/test_webpagereader.py (+0/-229) tests/functional/openlp_core_ui/test_first_time.py (+1/-1) tests/functional/openlp_core_ui/test_firsttimeform.py (+0/-18) |
To merge this branch: | bzr merge lp:~trb143/openlp/httpfixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tomas Groth | Approve | ||
Review via email: mp+313691@code.launchpad.net |
This proposal supersedes a proposal from 2016-12-21.
Commit message
Description of the change
Move some http code around to allow it to be reused in the remote updates.
lp:~trb143/openlp/httpfixes (revision 2718)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'openlp/core/common/httputils.py' |
2 | --- openlp/core/common/httputils.py 1970-01-01 00:00:00 +0000 |
3 | +++ openlp/core/common/httputils.py 2016-12-21 12:50:44 +0000 |
4 | @@ -0,0 +1,255 @@ |
5 | +# -*- coding: utf-8 -*- |
6 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
7 | + |
8 | +############################################################################### |
9 | +# OpenLP - Open Source Lyrics Projection # |
10 | +# --------------------------------------------------------------------------- # |
11 | +# Copyright (c) 2008-2016 OpenLP Developers # |
12 | +# --------------------------------------------------------------------------- # |
13 | +# This program is free software; you can redistribute it and/or modify it # |
14 | +# under the terms of the GNU General Public License as published by the Free # |
15 | +# Software Foundation; version 2 of the License. # |
16 | +# # |
17 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
18 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
19 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
20 | +# more details. # |
21 | +# # |
22 | +# You should have received a copy of the GNU General Public License along # |
23 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
24 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
25 | +############################################################################### |
26 | +""" |
27 | +The :mod:`openlp.core.utils` module provides the utility libraries for OpenLP. |
28 | +""" |
29 | +import hashlib |
30 | +import logging |
31 | +import os |
32 | +import socket |
33 | +import sys |
34 | +import time |
35 | +import urllib.error |
36 | +import urllib.parse |
37 | +import urllib.request |
38 | +from http.client import HTTPException |
39 | +from random import randint |
40 | + |
41 | +from openlp.core.common import Registry, trace_error_handler |
42 | + |
43 | +log = logging.getLogger(__name__ + '.__init__') |
44 | + |
45 | +USER_AGENTS = { |
46 | + 'win32': [ |
47 | + 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36', |
48 | + 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36', |
49 | + 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36' |
50 | + ], |
51 | + 'darwin': [ |
52 | + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) ' |
53 | + 'Chrome/26.0.1410.43 Safari/537.31', |
54 | + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) ' |
55 | + 'Chrome/20.0.1132.57 Safari/536.11', |
56 | + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) ' |
57 | + 'Chrome/20.0.1132.47 Safari/536.11', |
58 | + ], |
59 | + 'linux2': [ |
60 | + 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 ' |
61 | + 'Chrome/25.0.1364.160 Safari/537.22', |
62 | + 'Mozilla/5.0 (X11; CrOS armv7l 2913.260.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.99 ' |
63 | + 'Safari/537.11', |
64 | + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.27 (KHTML, like Gecko) Chrome/26.0.1389.0 Safari/537.27' |
65 | + ], |
66 | + 'default': [ |
67 | + 'Mozilla/5.0 (X11; NetBSD amd64; rv:18.0) Gecko/20130120 Firefox/18.0' |
68 | + ] |
69 | +} |
70 | +CONNECTION_TIMEOUT = 30 |
71 | +CONNECTION_RETRIES = 2 |
72 | + |
73 | + |
74 | +class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler): |
75 | + """ |
76 | + Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248 |
77 | + (Redirecting to urls with special chars) |
78 | + """ |
79 | + def redirect_request(self, req, fp, code, msg, headers, new_url): |
80 | + # |
81 | + """ |
82 | + Test if the new_url can be decoded to ascii |
83 | + |
84 | + :param req: |
85 | + :param fp: |
86 | + :param code: |
87 | + :param msg: |
88 | + :param headers: |
89 | + :param new_url: |
90 | + :return: |
91 | + """ |
92 | + try: |
93 | + new_url.encode('latin1').decode('ascii') |
94 | + fixed_url = new_url |
95 | + except Exception: |
96 | + # The url could not be decoded to ascii, so we do some url encoding |
97 | + fixed_url = urllib.parse.quote(new_url.encode('latin1').decode('utf-8', 'replace'), safe='/:') |
98 | + return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url) |
99 | + |
100 | + |
101 | +def get_user_agent(): |
102 | + """ |
103 | + Return a user agent customised for the platform the user is on. |
104 | + """ |
105 | + browser_list = USER_AGENTS.get(sys.platform, None) |
106 | + if not browser_list: |
107 | + browser_list = USER_AGENTS['default'] |
108 | + random_index = randint(0, len(browser_list) - 1) |
109 | + return browser_list[random_index] |
110 | + |
111 | + |
112 | +def get_web_page(url, header=None, update_openlp=False): |
113 | + """ |
114 | + Attempts to download the webpage at url and returns that page or None. |
115 | + |
116 | + :param url: The URL to be downloaded. |
117 | + :param header: An optional HTTP header to pass in the request to the web server. |
118 | + :param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded. |
119 | + Defaults to False. |
120 | + """ |
121 | + # TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a |
122 | + # proxy_handler, build into an opener and install the opener into urllib2. |
123 | + # http://docs.python.org/library/urllib2.html |
124 | + if not url: |
125 | + return None |
126 | + # This is needed to work around http://bugs.python.org/issue22248 and https://bugs.launchpad.net/openlp/+bug/1251437 |
127 | + opener = urllib.request.build_opener(HTTPRedirectHandlerFixed()) |
128 | + urllib.request.install_opener(opener) |
129 | + req = urllib.request.Request(url) |
130 | + if not header or header[0].lower() != 'user-agent': |
131 | + user_agent = get_user_agent() |
132 | + req.add_header('User-Agent', user_agent) |
133 | + if header: |
134 | + req.add_header(header[0], header[1]) |
135 | + log.debug('Downloading URL = %s' % url) |
136 | + retries = 0 |
137 | + while retries <= CONNECTION_RETRIES: |
138 | + retries += 1 |
139 | + time.sleep(0.1) |
140 | + try: |
141 | + page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT) |
142 | + log.debug('Downloaded page {text}'.format(text=page.geturl())) |
143 | + break |
144 | + except urllib.error.URLError as err: |
145 | + log.exception('URLError on {text}'.format(text=url)) |
146 | + log.exception('URLError: {text}'.format(text=err.reason)) |
147 | + page = None |
148 | + if retries > CONNECTION_RETRIES: |
149 | + raise |
150 | + except socket.timeout: |
151 | + log.exception('Socket timeout: {text}'.format(text=url)) |
152 | + page = None |
153 | + if retries > CONNECTION_RETRIES: |
154 | + raise |
155 | + except socket.gaierror: |
156 | + log.exception('Socket gaierror: {text}'.format(text=url)) |
157 | + page = None |
158 | + if retries > CONNECTION_RETRIES: |
159 | + raise |
160 | + except ConnectionRefusedError: |
161 | + log.exception('ConnectionRefused: {text}'.format(text=url)) |
162 | + page = None |
163 | + if retries > CONNECTION_RETRIES: |
164 | + raise |
165 | + break |
166 | + except ConnectionError: |
167 | + log.exception('Connection error: {text}'.format(text=url)) |
168 | + page = None |
169 | + if retries > CONNECTION_RETRIES: |
170 | + raise |
171 | + except HTTPException: |
172 | + log.exception('HTTPException error: {text}'.format(text=url)) |
173 | + page = None |
174 | + if retries > CONNECTION_RETRIES: |
175 | + raise |
176 | + except: |
177 | + # Don't know what's happening, so reraise the original |
178 | + raise |
179 | + if update_openlp: |
180 | + Registry().get('application').process_events() |
181 | + if not page: |
182 | + log.exception('{text} could not be downloaded'.format(text=url)) |
183 | + return None |
184 | + log.debug(page) |
185 | + return page |
186 | + |
187 | + |
188 | +def get_url_file_size(url): |
189 | + """ |
190 | + Get the size of a file. |
191 | + |
192 | + :param url: The URL of the file we want to download. |
193 | + """ |
194 | + retries = 0 |
195 | + while True: |
196 | + try: |
197 | + site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) |
198 | + meta = site.info() |
199 | + return int(meta.get("Content-Length")) |
200 | + except urllib.error.URLError: |
201 | + if retries > CONNECTION_RETRIES: |
202 | + raise |
203 | + else: |
204 | + retries += 1 |
205 | + time.sleep(0.1) |
206 | + continue |
207 | + |
208 | + |
209 | +def url_get_file(callback, url, f_path, sha256=None): |
210 | + """" |
211 | + Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any |
212 | + point. Returns False on download error. |
213 | + |
214 | + :param callback: the class which needs to be updated |
215 | + :param url: URL to download |
216 | + :param f_path: Destination file |
217 | + :param sha256: The check sum value to be checked against the download value |
218 | + """ |
219 | + block_count = 0 |
220 | + block_size = 4096 |
221 | + retries = 0 |
222 | + while True: |
223 | + try: |
224 | + filename = open(f_path, "wb") |
225 | + url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) |
226 | + if sha256: |
227 | + hasher = hashlib.sha256() |
228 | + # Download until finished or canceled. |
229 | + while not callback.was_cancelled: |
230 | + data = url_file.read(block_size) |
231 | + if not data: |
232 | + break |
233 | + filename.write(data) |
234 | + if sha256: |
235 | + hasher.update(data) |
236 | + block_count += 1 |
237 | + callback._download_progress(block_count, block_size) |
238 | + filename.close() |
239 | + if sha256 and hasher.hexdigest() != sha256: |
240 | + log.error('sha256 sums did not match for file: {file}'.format(file=f_path)) |
241 | + os.remove(f_path) |
242 | + return False |
243 | + except (urllib.error.URLError, socket.timeout) as err: |
244 | + trace_error_handler(log) |
245 | + filename.close() |
246 | + os.remove(f_path) |
247 | + if retries > CONNECTION_RETRIES: |
248 | + return False |
249 | + else: |
250 | + retries += 1 |
251 | + time.sleep(0.1) |
252 | + continue |
253 | + break |
254 | + # Delete file if cancelled, it may be a partial file. |
255 | + if callback.was_cancelled: |
256 | + os.remove(f_path) |
257 | + return True |
258 | + |
259 | +__all__ = ['get_web_page'] |
260 | |
261 | === removed file 'openlp/core/lib/webpagereader.py' |
262 | --- openlp/core/lib/webpagereader.py 2016-07-01 21:17:20 +0000 |
263 | +++ openlp/core/lib/webpagereader.py 1970-01-01 00:00:00 +0000 |
264 | @@ -1,182 +0,0 @@ |
265 | -# -*- coding: utf-8 -*- |
266 | -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
267 | - |
268 | -############################################################################### |
269 | -# OpenLP - Open Source Lyrics Projection # |
270 | -# --------------------------------------------------------------------------- # |
271 | -# Copyright (c) 2008-2016 OpenLP Developers # |
272 | -# --------------------------------------------------------------------------- # |
273 | -# This program is free software; you can redistribute it and/or modify it # |
274 | -# under the terms of the GNU General Public License as published by the Free # |
275 | -# Software Foundation; version 2 of the License. # |
276 | -# # |
277 | -# This program is distributed in the hope that it will be useful, but WITHOUT # |
278 | -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
279 | -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
280 | -# more details. # |
281 | -# # |
282 | -# You should have received a copy of the GNU General Public License along # |
283 | -# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
284 | -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
285 | -############################################################################### |
286 | -""" |
287 | -The :mod:`openlp.core.utils` module provides the utility libraries for OpenLP. |
288 | -""" |
289 | -import logging |
290 | -import socket |
291 | -import sys |
292 | -import time |
293 | -import urllib.error |
294 | -import urllib.parse |
295 | -import urllib.request |
296 | -from http.client import HTTPException |
297 | -from random import randint |
298 | - |
299 | -from openlp.core.common import Registry |
300 | - |
301 | -log = logging.getLogger(__name__ + '.__init__') |
302 | - |
303 | -USER_AGENTS = { |
304 | - 'win32': [ |
305 | - 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36', |
306 | - 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36', |
307 | - 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36' |
308 | - ], |
309 | - 'darwin': [ |
310 | - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) ' |
311 | - 'Chrome/26.0.1410.43 Safari/537.31', |
312 | - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) ' |
313 | - 'Chrome/20.0.1132.57 Safari/536.11', |
314 | - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) ' |
315 | - 'Chrome/20.0.1132.47 Safari/536.11', |
316 | - ], |
317 | - 'linux2': [ |
318 | - 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 ' |
319 | - 'Chrome/25.0.1364.160 Safari/537.22', |
320 | - 'Mozilla/5.0 (X11; CrOS armv7l 2913.260.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.99 ' |
321 | - 'Safari/537.11', |
322 | - 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.27 (KHTML, like Gecko) Chrome/26.0.1389.0 Safari/537.27' |
323 | - ], |
324 | - 'default': [ |
325 | - 'Mozilla/5.0 (X11; NetBSD amd64; rv:18.0) Gecko/20130120 Firefox/18.0' |
326 | - ] |
327 | -} |
328 | -CONNECTION_TIMEOUT = 30 |
329 | -CONNECTION_RETRIES = 2 |
330 | - |
331 | - |
332 | -class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler): |
333 | - """ |
334 | - Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248 |
335 | - (Redirecting to urls with special chars) |
336 | - """ |
337 | - def redirect_request(self, req, fp, code, msg, headers, new_url): |
338 | - # |
339 | - """ |
340 | - Test if the new_url can be decoded to ascii |
341 | - |
342 | - :param req: |
343 | - :param fp: |
344 | - :param code: |
345 | - :param msg: |
346 | - :param headers: |
347 | - :param new_url: |
348 | - :return: |
349 | - """ |
350 | - try: |
351 | - new_url.encode('latin1').decode('ascii') |
352 | - fixed_url = new_url |
353 | - except Exception: |
354 | - # The url could not be decoded to ascii, so we do some url encoding |
355 | - fixed_url = urllib.parse.quote(new_url.encode('latin1').decode('utf-8', 'replace'), safe='/:') |
356 | - return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url) |
357 | - |
358 | - |
359 | -def _get_user_agent(): |
360 | - """ |
361 | - Return a user agent customised for the platform the user is on. |
362 | - """ |
363 | - browser_list = USER_AGENTS.get(sys.platform, None) |
364 | - if not browser_list: |
365 | - browser_list = USER_AGENTS['default'] |
366 | - random_index = randint(0, len(browser_list) - 1) |
367 | - return browser_list[random_index] |
368 | - |
369 | - |
370 | -def get_web_page(url, header=None, update_openlp=False): |
371 | - """ |
372 | - Attempts to download the webpage at url and returns that page or None. |
373 | - |
374 | - :param url: The URL to be downloaded. |
375 | - :param header: An optional HTTP header to pass in the request to the web server. |
376 | - :param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded. |
377 | - Defaults to False. |
378 | - """ |
379 | - # TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a |
380 | - # proxy_handler, build into an opener and install the opener into urllib2. |
381 | - # http://docs.python.org/library/urllib2.html |
382 | - if not url: |
383 | - return None |
384 | - # This is needed to work around http://bugs.python.org/issue22248 and https://bugs.launchpad.net/openlp/+bug/1251437 |
385 | - opener = urllib.request.build_opener(HTTPRedirectHandlerFixed()) |
386 | - urllib.request.install_opener(opener) |
387 | - req = urllib.request.Request(url) |
388 | - if not header or header[0].lower() != 'user-agent': |
389 | - user_agent = _get_user_agent() |
390 | - req.add_header('User-Agent', user_agent) |
391 | - if header: |
392 | - req.add_header(header[0], header[1]) |
393 | - log.debug('Downloading URL = %s' % url) |
394 | - retries = 0 |
395 | - while retries <= CONNECTION_RETRIES: |
396 | - retries += 1 |
397 | - time.sleep(0.1) |
398 | - try: |
399 | - page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT) |
400 | - log.debug('Downloaded page {text}'.format(text=page.geturl())) |
401 | - break |
402 | - except urllib.error.URLError as err: |
403 | - log.exception('URLError on {text}'.format(text=url)) |
404 | - log.exception('URLError: {text}'.format(text=err.reason)) |
405 | - page = None |
406 | - if retries > CONNECTION_RETRIES: |
407 | - raise |
408 | - except socket.timeout: |
409 | - log.exception('Socket timeout: {text}'.format(text=url)) |
410 | - page = None |
411 | - if retries > CONNECTION_RETRIES: |
412 | - raise |
413 | - except socket.gaierror: |
414 | - log.exception('Socket gaierror: {text}'.format(text=url)) |
415 | - page = None |
416 | - if retries > CONNECTION_RETRIES: |
417 | - raise |
418 | - except ConnectionRefusedError: |
419 | - log.exception('ConnectionRefused: {text}'.format(text=url)) |
420 | - page = None |
421 | - if retries > CONNECTION_RETRIES: |
422 | - raise |
423 | - break |
424 | - except ConnectionError: |
425 | - log.exception('Connection error: {text}'.format(text=url)) |
426 | - page = None |
427 | - if retries > CONNECTION_RETRIES: |
428 | - raise |
429 | - except HTTPException: |
430 | - log.exception('HTTPException error: {text}'.format(text=url)) |
431 | - page = None |
432 | - if retries > CONNECTION_RETRIES: |
433 | - raise |
434 | - except: |
435 | - # Don't know what's happening, so reraise the original |
436 | - raise |
437 | - if update_openlp: |
438 | - Registry().get('application').process_events() |
439 | - if not page: |
440 | - log.exception('{text} could not be downloaded'.format(text=url)) |
441 | - return None |
442 | - log.debug(page) |
443 | - return page |
444 | - |
445 | - |
446 | -__all__ = ['get_web_page'] |
447 | |
448 | === modified file 'openlp/core/ui/firsttimeform.py' |
449 | --- openlp/core/ui/firsttimeform.py 2016-08-05 19:41:22 +0000 |
450 | +++ openlp/core/ui/firsttimeform.py 2016-12-21 12:50:44 +0000 |
451 | @@ -22,7 +22,6 @@ |
452 | """ |
453 | This module contains the first time wizard. |
454 | """ |
455 | -import hashlib |
456 | import logging |
457 | import os |
458 | import socket |
459 | @@ -39,7 +38,7 @@ |
460 | translate, clean_button_text, trace_error_handler |
461 | from openlp.core.lib import PluginStatus, build_icon |
462 | from openlp.core.lib.ui import critical_error_message_box |
463 | -from openlp.core.lib.webpagereader import get_web_page, CONNECTION_RETRIES, CONNECTION_TIMEOUT |
464 | +from openlp.core.common.httputils import get_web_page, get_url_file_size, url_get_file, CONNECTION_TIMEOUT |
465 | from .firsttimewizard import UiFirstTimeWizard, FirstTimePage |
466 | |
467 | log = logging.getLogger(__name__) |
468 | @@ -395,54 +394,6 @@ |
469 | self.was_cancelled = True |
470 | self.close() |
471 | |
472 | - def url_get_file(self, url, f_path, sha256=None): |
473 | - """" |
474 | - Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any |
475 | - point. Returns False on download error. |
476 | - |
477 | - :param url: URL to download |
478 | - :param f_path: Destination file |
479 | - """ |
480 | - block_count = 0 |
481 | - block_size = 4096 |
482 | - retries = 0 |
483 | - while True: |
484 | - try: |
485 | - filename = open(f_path, "wb") |
486 | - url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) |
487 | - if sha256: |
488 | - hasher = hashlib.sha256() |
489 | - # Download until finished or canceled. |
490 | - while not self.was_cancelled: |
491 | - data = url_file.read(block_size) |
492 | - if not data: |
493 | - break |
494 | - filename.write(data) |
495 | - if sha256: |
496 | - hasher.update(data) |
497 | - block_count += 1 |
498 | - self._download_progress(block_count, block_size) |
499 | - filename.close() |
500 | - if sha256 and hasher.hexdigest() != sha256: |
501 | - log.error('sha256 sums did not match for file: {file}'.format(file=f_path)) |
502 | - os.remove(f_path) |
503 | - return False |
504 | - except (urllib.error.URLError, socket.timeout) as err: |
505 | - trace_error_handler(log) |
506 | - filename.close() |
507 | - os.remove(f_path) |
508 | - if retries > CONNECTION_RETRIES: |
509 | - return False |
510 | - else: |
511 | - retries += 1 |
512 | - time.sleep(0.1) |
513 | - continue |
514 | - break |
515 | - # Delete file if cancelled, it may be a partial file. |
516 | - if self.was_cancelled: |
517 | - os.remove(f_path) |
518 | - return True |
519 | - |
520 | def _build_theme_screenshots(self): |
521 | """ |
522 | This method builds the theme screenshots' icons for all items in the ``self.themes_list_widget``. |
523 | @@ -455,26 +406,6 @@ |
524 | if item: |
525 | item.setIcon(build_icon(os.path.join(gettempdir(), 'openlp', screenshot))) |
526 | |
527 | - def _get_file_size(self, url): |
528 | - """ |
529 | - Get the size of a file. |
530 | - |
531 | - :param url: The URL of the file we want to download. |
532 | - """ |
533 | - retries = 0 |
534 | - while True: |
535 | - try: |
536 | - site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) |
537 | - meta = site.info() |
538 | - return int(meta.get("Content-Length")) |
539 | - except urllib.error.URLError: |
540 | - if retries > CONNECTION_RETRIES: |
541 | - raise |
542 | - else: |
543 | - retries += 1 |
544 | - time.sleep(0.1) |
545 | - continue |
546 | - |
547 | def _download_progress(self, count, block_size): |
548 | """ |
549 | Calculate and display the download progress. |
550 | @@ -510,7 +441,7 @@ |
551 | item = self.songs_list_widget.item(i) |
552 | if item.checkState() == QtCore.Qt.Checked: |
553 | filename, sha256 = item.data(QtCore.Qt.UserRole) |
554 | - size = self._get_file_size('{path}{name}'.format(path=self.songs_url, name=filename)) |
555 | + size = get_url_file_size('{path}{name}'.format(path=self.songs_url, name=filename)) |
556 | self.max_progress += size |
557 | # Loop through the Bibles list and increase for each selected item |
558 | iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget) |
559 | @@ -519,7 +450,7 @@ |
560 | item = iterator.value() |
561 | if item.parent() and item.checkState(0) == QtCore.Qt.Checked: |
562 | filename, sha256 = item.data(0, QtCore.Qt.UserRole) |
563 | - size = self._get_file_size('{path}{name}'.format(path=self.bibles_url, name=filename)) |
564 | + size = get_url_file_size('{path}{name}'.format(path=self.bibles_url, name=filename)) |
565 | self.max_progress += size |
566 | iterator += 1 |
567 | # Loop through the themes list and increase for each selected item |
568 | @@ -528,7 +459,7 @@ |
569 | item = self.themes_list_widget.item(i) |
570 | if item.checkState() == QtCore.Qt.Checked: |
571 | filename, sha256 = item.data(QtCore.Qt.UserRole) |
572 | - size = self._get_file_size('{path}{name}'.format(path=self.themes_url, name=filename)) |
573 | + size = get_url_file_size('{path}{name}'.format(path=self.themes_url, name=filename)) |
574 | self.max_progress += size |
575 | except urllib.error.URLError: |
576 | trace_error_handler(log) |
577 | @@ -636,8 +567,8 @@ |
578 | self._increment_progress_bar(self.downloading.format(name=filename), 0) |
579 | self.previous_size = 0 |
580 | destination = os.path.join(songs_destination, str(filename)) |
581 | - if not self.url_get_file('{path}{name}'.format(path=self.songs_url, name=filename), |
582 | - destination, sha256): |
583 | + if not url_get_file(self, '{path}{name}'.format(path=self.songs_url, name=filename), |
584 | + destination, sha256): |
585 | missed_files.append('Song: {name}'.format(name=filename)) |
586 | # Download Bibles |
587 | bibles_iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget) |
588 | @@ -648,9 +579,9 @@ |
589 | # TODO: Tested at home |
590 | self._increment_progress_bar(self.downloading.format(name=bible), 0) |
591 | self.previous_size = 0 |
592 | - if not self.url_get_file('{path}{name}'.format(path=self.bibles_url, name=bible), |
593 | - os.path.join(bibles_destination, bible), |
594 | - sha256): |
595 | + if not url_get_file(self, '{path}{name}'.format(path=self.bibles_url, name=bible), |
596 | + os.path.join(bibles_destination, bible), |
597 | + sha256): |
598 | missed_files.append('Bible: {name}'.format(name=bible)) |
599 | bibles_iterator += 1 |
600 | # Download themes |
601 | @@ -661,9 +592,9 @@ |
602 | # TODO: Tested at home |
603 | self._increment_progress_bar(self.downloading.format(name=theme), 0) |
604 | self.previous_size = 0 |
605 | - if not self.url_get_file('{path}{name}'.format(path=self.themes_url, name=theme), |
606 | - os.path.join(themes_destination, theme), |
607 | - sha256): |
608 | + if not url_get_file(self, '{path}{name}'.format(path=self.themes_url, name=theme), |
609 | + os.path.join(themes_destination, theme), |
610 | + sha256): |
611 | missed_files.append('Theme: {name}'.format(name=theme)) |
612 | if missed_files: |
613 | file_list = '' |
614 | |
615 | === modified file 'openlp/plugins/bibles/lib/importers/http.py' |
616 | --- openlp/plugins/bibles/lib/importers/http.py 2016-09-18 14:54:55 +0000 |
617 | +++ openlp/plugins/bibles/lib/importers/http.py 2016-12-21 12:50:44 +0000 |
618 | @@ -32,7 +32,7 @@ |
619 | |
620 | from openlp.core.common import Registry, RegistryProperties, translate |
621 | from openlp.core.lib.ui import critical_error_message_box |
622 | -from openlp.core.lib.webpagereader import get_web_page |
623 | +from openlp.core.common.httputils import get_web_page |
624 | from openlp.plugins.bibles.lib import SearchResults |
625 | from openlp.plugins.bibles.lib.bibleimport import BibleImport |
626 | from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, Book |
627 | |
628 | === added file 'tests/functional/openlp_core_common/test_httputils.py' |
629 | --- tests/functional/openlp_core_common/test_httputils.py 1970-01-01 00:00:00 +0000 |
630 | +++ tests/functional/openlp_core_common/test_httputils.py 2016-12-21 12:50:44 +0000 |
631 | @@ -0,0 +1,274 @@ |
632 | +# -*- coding: utf-8 -*- |
633 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
634 | + |
635 | +############################################################################### |
636 | +# OpenLP - Open Source Lyrics Projection # |
637 | +# --------------------------------------------------------------------------- # |
638 | +# Copyright (c) 2008-2016 OpenLP Developers # |
639 | +# --------------------------------------------------------------------------- # |
640 | +# This program is free software; you can redistribute it and/or modify it # |
641 | +# under the terms of the GNU General Public License as published by the Free # |
642 | +# Software Foundation; version 2 of the License. # |
643 | +# # |
644 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
645 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
646 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
647 | +# more details. # |
648 | +# # |
649 | +# You should have received a copy of the GNU General Public License along # |
650 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
651 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
652 | +############################################################################### |
653 | +""" |
654 | +Functional tests to test the AppLocation class and related methods. |
655 | +""" |
656 | +import os |
657 | +import tempfile |
658 | +import socket |
659 | +from unittest import TestCase |
660 | + |
661 | +from openlp.core.common.httputils import get_user_agent, get_web_page, get_url_file_size, url_get_file |
662 | + |
663 | +from tests.functional import MagicMock, patch |
664 | +from tests.helpers.testmixin import TestMixin |
665 | + |
666 | + |
667 | +class TestHttpUtils(TestCase, TestMixin): |
668 | + |
669 | + """ |
670 | + A test suite to test out various http helper functions. |
671 | + """ |
672 | + def setUp(self): |
673 | + self.tempfile = os.path.join(tempfile.gettempdir(), 'testfile') |
674 | + |
675 | + def tearDown(self): |
676 | + if os.path.isfile(self.tempfile): |
677 | + os.remove(self.tempfile) |
678 | + |
679 | + def test_get_user_agent_linux(self): |
680 | + """ |
681 | + Test that getting a user agent on Linux returns a user agent suitable for Linux |
682 | + """ |
683 | + with patch('openlp.core.common.httputils.sys') as mocked_sys: |
684 | + |
685 | + # GIVEN: The system is Linux |
686 | + mocked_sys.platform = 'linux2' |
687 | + |
688 | + # WHEN: We call get_user_agent() |
689 | + user_agent = get_user_agent() |
690 | + |
691 | + # THEN: The user agent is a Linux (or ChromeOS) user agent |
692 | + result = 'Linux' in user_agent or 'CrOS' in user_agent |
693 | + self.assertTrue(result, 'The user agent should be a valid Linux user agent') |
694 | + |
695 | + def test_get_user_agent_windows(self): |
696 | + """ |
697 | + Test that getting a user agent on Windows returns a user agent suitable for Windows |
698 | + """ |
699 | + with patch('openlp.core.common.httputils.sys') as mocked_sys: |
700 | + |
701 | + # GIVEN: The system is Linux |
702 | + mocked_sys.platform = 'win32' |
703 | + |
704 | + # WHEN: We call get_user_agent() |
705 | + user_agent = get_user_agent() |
706 | + |
707 | + # THEN: The user agent is a Linux (or ChromeOS) user agent |
708 | + self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent') |
709 | + |
710 | + def test_get_user_agent_macos(self): |
711 | + """ |
712 | + Test that getting a user agent on OS X returns a user agent suitable for OS X |
713 | + """ |
714 | + with patch('openlp.core.common.httputils.sys') as mocked_sys: |
715 | + |
716 | + # GIVEN: The system is Linux |
717 | + mocked_sys.platform = 'darwin' |
718 | + |
719 | + # WHEN: We call get_user_agent() |
720 | + user_agent = get_user_agent() |
721 | + |
722 | + # THEN: The user agent is a Linux (or ChromeOS) user agent |
723 | + self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent') |
724 | + |
725 | + def test_get_user_agent_default(self): |
726 | + """ |
727 | + Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent |
728 | + """ |
729 | + with patch('openlp.core.common.httputils.sys') as mocked_sys: |
730 | + |
731 | + # GIVEN: The system is Linux |
732 | + mocked_sys.platform = 'freebsd' |
733 | + |
734 | + # WHEN: We call get_user_agent() |
735 | + user_agent = get_user_agent() |
736 | + |
737 | + # THEN: The user agent is a Linux (or ChromeOS) user agent |
738 | + self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent') |
739 | + |
740 | + def test_get_web_page_no_url(self): |
741 | + """ |
742 | + Test that sending a URL of None to the get_web_page method returns None |
743 | + """ |
744 | + # GIVEN: A None url |
745 | + test_url = None |
746 | + |
747 | + # WHEN: We try to get the test URL |
748 | + result = get_web_page(test_url) |
749 | + |
750 | + # THEN: None should be returned |
751 | + self.assertIsNone(result, 'The return value of get_web_page should be None') |
752 | + |
753 | + def test_get_web_page(self): |
754 | + """ |
755 | + Test that the get_web_page method works correctly |
756 | + """ |
757 | + with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \ |
758 | + patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \ |
759 | + patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent, \ |
760 | + patch('openlp.core.common.Registry') as MockRegistry: |
761 | + # GIVEN: Mocked out objects and a fake URL |
762 | + mocked_request_object = MagicMock() |
763 | + MockRequest.return_value = mocked_request_object |
764 | + mocked_page_object = MagicMock() |
765 | + mock_urlopen.return_value = mocked_page_object |
766 | + mock_get_user_agent.return_value = 'user_agent' |
767 | + fake_url = 'this://is.a.fake/url' |
768 | + |
769 | + # WHEN: The get_web_page() method is called |
770 | + returned_page = get_web_page(fake_url) |
771 | + |
772 | + # THEN: The correct methods are called with the correct arguments and a web page is returned |
773 | + MockRequest.assert_called_with(fake_url) |
774 | + mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent') |
775 | + self.assertEqual(1, mocked_request_object.add_header.call_count, |
776 | + 'There should only be 1 call to add_header') |
777 | + mock_get_user_agent.assert_called_with() |
778 | + mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
779 | + mocked_page_object.geturl.assert_called_with() |
780 | + self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called') |
781 | + self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
782 | + |
783 | + def test_get_web_page_with_header(self): |
784 | + """ |
785 | + Test that adding a header to the call to get_web_page() adds the header to the request |
786 | + """ |
787 | + with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \ |
788 | + patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \ |
789 | + patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent: |
790 | + # GIVEN: Mocked out objects, a fake URL and a fake header |
791 | + mocked_request_object = MagicMock() |
792 | + MockRequest.return_value = mocked_request_object |
793 | + mocked_page_object = MagicMock() |
794 | + mock_urlopen.return_value = mocked_page_object |
795 | + mock_get_user_agent.return_value = 'user_agent' |
796 | + fake_url = 'this://is.a.fake/url' |
797 | + fake_header = ('Fake-Header', 'fake value') |
798 | + |
799 | + # WHEN: The get_web_page() method is called |
800 | + returned_page = get_web_page(fake_url, header=fake_header) |
801 | + |
802 | + # THEN: The correct methods are called with the correct arguments and a web page is returned |
803 | + MockRequest.assert_called_with(fake_url) |
804 | + mocked_request_object.add_header.assert_called_with(fake_header[0], fake_header[1]) |
805 | + self.assertEqual(2, mocked_request_object.add_header.call_count, |
806 | + 'There should only be 2 calls to add_header') |
807 | + mock_get_user_agent.assert_called_with() |
808 | + mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
809 | + mocked_page_object.geturl.assert_called_with() |
810 | + self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
811 | + |
812 | + def test_get_web_page_with_user_agent_in_headers(self): |
813 | + """ |
814 | + Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request |
815 | + """ |
816 | + with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \ |
817 | + patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \ |
818 | + patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent: |
819 | + # GIVEN: Mocked out objects, a fake URL and a fake header |
820 | + mocked_request_object = MagicMock() |
821 | + MockRequest.return_value = mocked_request_object |
822 | + mocked_page_object = MagicMock() |
823 | + mock_urlopen.return_value = mocked_page_object |
824 | + fake_url = 'this://is.a.fake/url' |
825 | + user_agent_header = ('User-Agent', 'OpenLP/2.2.0') |
826 | + |
827 | + # WHEN: The get_web_page() method is called |
828 | + returned_page = get_web_page(fake_url, header=user_agent_header) |
829 | + |
830 | + # THEN: The correct methods are called with the correct arguments and a web page is returned |
831 | + MockRequest.assert_called_with(fake_url) |
832 | + mocked_request_object.add_header.assert_called_with(user_agent_header[0], user_agent_header[1]) |
833 | + self.assertEqual(1, mocked_request_object.add_header.call_count, |
834 | + 'There should only be 1 call to add_header') |
835 | + self.assertEqual(0, mock_get_user_agent.call_count, 'get_user_agent should not have been called') |
836 | + mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
837 | + mocked_page_object.geturl.assert_called_with() |
838 | + self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
839 | + |
840 | + def test_get_web_page_update_openlp(self): |
841 | + """ |
842 | + Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events() |
843 | + """ |
844 | + with patch('openlp.core.common.httputils.urllib.request.Request') as MockRequest, \ |
845 | + patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \ |
846 | + patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent, \ |
847 | + patch('openlp.core.common.httputils.Registry') as MockRegistry: |
848 | + # GIVEN: Mocked out objects, a fake URL |
849 | + mocked_request_object = MagicMock() |
850 | + MockRequest.return_value = mocked_request_object |
851 | + mocked_page_object = MagicMock() |
852 | + mock_urlopen.return_value = mocked_page_object |
853 | + mock_get_user_agent.return_value = 'user_agent' |
854 | + mocked_registry_object = MagicMock() |
855 | + mocked_application_object = MagicMock() |
856 | + mocked_registry_object.get.return_value = mocked_application_object |
857 | + MockRegistry.return_value = mocked_registry_object |
858 | + fake_url = 'this://is.a.fake/url' |
859 | + |
860 | + # WHEN: The get_web_page() method is called |
861 | + returned_page = get_web_page(fake_url, update_openlp=True) |
862 | + |
863 | + # THEN: The correct methods are called with the correct arguments and a web page is returned |
864 | + MockRequest.assert_called_with(fake_url) |
865 | + mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent') |
866 | + self.assertEqual(1, mocked_request_object.add_header.call_count, |
867 | + 'There should only be 1 call to add_header') |
868 | + mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
869 | + mocked_page_object.geturl.assert_called_with() |
870 | + mocked_registry_object.get.assert_called_with('application') |
871 | + mocked_application_object.process_events.assert_called_with() |
872 | + self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
873 | + |
874 | + def test_get_url_file_size(self): |
875 | + """ |
876 | + Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events() |
877 | + """ |
878 | + with patch('openlp.core.common.httputils.urllib.request.urlopen') as mock_urlopen, \ |
879 | + patch('openlp.core.common.httputils.get_user_agent') as mock_get_user_agent: |
880 | + # GIVEN: Mocked out objects, a fake URL |
881 | + mocked_page_object = MagicMock() |
882 | + mock_urlopen.return_value = mocked_page_object |
883 | + mock_get_user_agent.return_value = 'user_agent' |
884 | + fake_url = 'this://is.a.fake/url' |
885 | + |
886 | + # WHEN: The get_url_file_size() method is called |
887 | + size = get_url_file_size(fake_url) |
888 | + |
889 | + # THEN: The correct methods are called with the correct arguments and a web page is returned |
890 | + mock_urlopen.assert_called_with(fake_url, timeout=30) |
891 | + |
892 | + @patch('openlp.core.ui.firsttimeform.urllib.request.urlopen') |
893 | + def test_socket_timeout(self, mocked_urlopen): |
894 | + """ |
895 | + Test socket timeout gets caught |
896 | + """ |
897 | + # GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download |
898 | + mocked_urlopen.side_effect = socket.timeout() |
899 | + |
900 | + # WHEN: Attempt to retrieve a file |
901 | + url_get_file(MagicMock(), url='http://localhost/test', f_path=self.tempfile) |
902 | + |
903 | + # THEN: socket.timeout should have been caught |
904 | + # NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files |
905 | + self.assertFalse(os.path.exists(self.tempfile), 'FTW url_get_file should have caught socket.timeout') |
906 | |
907 | === removed file 'tests/functional/openlp_core_lib/test_webpagereader.py' |
908 | --- tests/functional/openlp_core_lib/test_webpagereader.py 2016-05-31 21:40:13 +0000 |
909 | +++ tests/functional/openlp_core_lib/test_webpagereader.py 1970-01-01 00:00:00 +0000 |
910 | @@ -1,229 +0,0 @@ |
911 | -# -*- coding: utf-8 -*- |
912 | -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
913 | - |
914 | -############################################################################### |
915 | -# OpenLP - Open Source Lyrics Projection # |
916 | -# --------------------------------------------------------------------------- # |
917 | -# Copyright (c) 2008-2016 OpenLP Developers # |
918 | -# --------------------------------------------------------------------------- # |
919 | -# This program is free software; you can redistribute it and/or modify it # |
920 | -# under the terms of the GNU General Public License as published by the Free # |
921 | -# Software Foundation; version 2 of the License. # |
922 | -# # |
923 | -# This program is distributed in the hope that it will be useful, but WITHOUT # |
924 | -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
925 | -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
926 | -# more details. # |
927 | -# # |
928 | -# You should have received a copy of the GNU General Public License along # |
929 | -# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
930 | -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
931 | -############################################################################### |
932 | -""" |
933 | -Functional tests to test the AppLocation class and related methods. |
934 | -""" |
935 | -from unittest import TestCase |
936 | - |
937 | -from openlp.core.lib.webpagereader import _get_user_agent, get_web_page |
938 | - |
939 | -from tests.functional import MagicMock, patch |
940 | - |
941 | - |
942 | -class TestUtils(TestCase): |
943 | - """ |
944 | - A test suite to test out various methods around the AppLocation class. |
945 | - """ |
946 | - def test_get_user_agent_linux(self): |
947 | - """ |
948 | - Test that getting a user agent on Linux returns a user agent suitable for Linux |
949 | - """ |
950 | - with patch('openlp.core.lib.webpagereader.sys') as mocked_sys: |
951 | - |
952 | - # GIVEN: The system is Linux |
953 | - mocked_sys.platform = 'linux2' |
954 | - |
955 | - # WHEN: We call _get_user_agent() |
956 | - user_agent = _get_user_agent() |
957 | - |
958 | - # THEN: The user agent is a Linux (or ChromeOS) user agent |
959 | - result = 'Linux' in user_agent or 'CrOS' in user_agent |
960 | - self.assertTrue(result, 'The user agent should be a valid Linux user agent') |
961 | - |
962 | - def test_get_user_agent_windows(self): |
963 | - """ |
964 | - Test that getting a user agent on Windows returns a user agent suitable for Windows |
965 | - """ |
966 | - with patch('openlp.core.lib.webpagereader.sys') as mocked_sys: |
967 | - |
968 | - # GIVEN: The system is Linux |
969 | - mocked_sys.platform = 'win32' |
970 | - |
971 | - # WHEN: We call _get_user_agent() |
972 | - user_agent = _get_user_agent() |
973 | - |
974 | - # THEN: The user agent is a Linux (or ChromeOS) user agent |
975 | - self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent') |
976 | - |
977 | - def test_get_user_agent_macos(self): |
978 | - """ |
979 | - Test that getting a user agent on OS X returns a user agent suitable for OS X |
980 | - """ |
981 | - with patch('openlp.core.lib.webpagereader.sys') as mocked_sys: |
982 | - |
983 | - # GIVEN: The system is Linux |
984 | - mocked_sys.platform = 'darwin' |
985 | - |
986 | - # WHEN: We call _get_user_agent() |
987 | - user_agent = _get_user_agent() |
988 | - |
989 | - # THEN: The user agent is a Linux (or ChromeOS) user agent |
990 | - self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent') |
991 | - |
992 | - def test_get_user_agent_default(self): |
993 | - """ |
994 | - Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent |
995 | - """ |
996 | - with patch('openlp.core.lib.webpagereader.sys') as mocked_sys: |
997 | - |
998 | - # GIVEN: The system is Linux |
999 | - mocked_sys.platform = 'freebsd' |
1000 | - |
1001 | - # WHEN: We call _get_user_agent() |
1002 | - user_agent = _get_user_agent() |
1003 | - |
1004 | - # THEN: The user agent is a Linux (or ChromeOS) user agent |
1005 | - self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent') |
1006 | - |
1007 | - def test_get_web_page_no_url(self): |
1008 | - """ |
1009 | - Test that sending a URL of None to the get_web_page method returns None |
1010 | - """ |
1011 | - # GIVEN: A None url |
1012 | - test_url = None |
1013 | - |
1014 | - # WHEN: We try to get the test URL |
1015 | - result = get_web_page(test_url) |
1016 | - |
1017 | - # THEN: None should be returned |
1018 | - self.assertIsNone(result, 'The return value of get_web_page should be None') |
1019 | - |
1020 | - def test_get_web_page(self): |
1021 | - """ |
1022 | - Test that the get_web_page method works correctly |
1023 | - """ |
1024 | - with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \ |
1025 | - patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \ |
1026 | - patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent, \ |
1027 | - patch('openlp.core.common.Registry') as MockRegistry: |
1028 | - # GIVEN: Mocked out objects and a fake URL |
1029 | - mocked_request_object = MagicMock() |
1030 | - MockRequest.return_value = mocked_request_object |
1031 | - mocked_page_object = MagicMock() |
1032 | - mock_urlopen.return_value = mocked_page_object |
1033 | - mock_get_user_agent.return_value = 'user_agent' |
1034 | - fake_url = 'this://is.a.fake/url' |
1035 | - |
1036 | - # WHEN: The get_web_page() method is called |
1037 | - returned_page = get_web_page(fake_url) |
1038 | - |
1039 | - # THEN: The correct methods are called with the correct arguments and a web page is returned |
1040 | - MockRequest.assert_called_with(fake_url) |
1041 | - mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent') |
1042 | - self.assertEqual(1, mocked_request_object.add_header.call_count, |
1043 | - 'There should only be 1 call to add_header') |
1044 | - mock_get_user_agent.assert_called_with() |
1045 | - mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
1046 | - mocked_page_object.geturl.assert_called_with() |
1047 | - self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called') |
1048 | - self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
1049 | - |
1050 | - def test_get_web_page_with_header(self): |
1051 | - """ |
1052 | - Test that adding a header to the call to get_web_page() adds the header to the request |
1053 | - """ |
1054 | - with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \ |
1055 | - patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \ |
1056 | - patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent: |
1057 | - # GIVEN: Mocked out objects, a fake URL and a fake header |
1058 | - mocked_request_object = MagicMock() |
1059 | - MockRequest.return_value = mocked_request_object |
1060 | - mocked_page_object = MagicMock() |
1061 | - mock_urlopen.return_value = mocked_page_object |
1062 | - mock_get_user_agent.return_value = 'user_agent' |
1063 | - fake_url = 'this://is.a.fake/url' |
1064 | - fake_header = ('Fake-Header', 'fake value') |
1065 | - |
1066 | - # WHEN: The get_web_page() method is called |
1067 | - returned_page = get_web_page(fake_url, header=fake_header) |
1068 | - |
1069 | - # THEN: The correct methods are called with the correct arguments and a web page is returned |
1070 | - MockRequest.assert_called_with(fake_url) |
1071 | - mocked_request_object.add_header.assert_called_with(fake_header[0], fake_header[1]) |
1072 | - self.assertEqual(2, mocked_request_object.add_header.call_count, |
1073 | - 'There should only be 2 calls to add_header') |
1074 | - mock_get_user_agent.assert_called_with() |
1075 | - mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
1076 | - mocked_page_object.geturl.assert_called_with() |
1077 | - self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
1078 | - |
1079 | - def test_get_web_page_with_user_agent_in_headers(self): |
1080 | - """ |
1081 | - Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request |
1082 | - """ |
1083 | - with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \ |
1084 | - patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \ |
1085 | - patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent: |
1086 | - # GIVEN: Mocked out objects, a fake URL and a fake header |
1087 | - mocked_request_object = MagicMock() |
1088 | - MockRequest.return_value = mocked_request_object |
1089 | - mocked_page_object = MagicMock() |
1090 | - mock_urlopen.return_value = mocked_page_object |
1091 | - fake_url = 'this://is.a.fake/url' |
1092 | - user_agent_header = ('User-Agent', 'OpenLP/2.2.0') |
1093 | - |
1094 | - # WHEN: The get_web_page() method is called |
1095 | - returned_page = get_web_page(fake_url, header=user_agent_header) |
1096 | - |
1097 | - # THEN: The correct methods are called with the correct arguments and a web page is returned |
1098 | - MockRequest.assert_called_with(fake_url) |
1099 | - mocked_request_object.add_header.assert_called_with(user_agent_header[0], user_agent_header[1]) |
1100 | - self.assertEqual(1, mocked_request_object.add_header.call_count, |
1101 | - 'There should only be 1 call to add_header') |
1102 | - self.assertEqual(0, mock_get_user_agent.call_count, '_get_user_agent should not have been called') |
1103 | - mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
1104 | - mocked_page_object.geturl.assert_called_with() |
1105 | - self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
1106 | - |
1107 | - def test_get_web_page_update_openlp(self): |
1108 | - """ |
1109 | - Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events() |
1110 | - """ |
1111 | - with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \ |
1112 | - patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \ |
1113 | - patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent, \ |
1114 | - patch('openlp.core.lib.webpagereader.Registry') as MockRegistry: |
1115 | - # GIVEN: Mocked out objects, a fake URL |
1116 | - mocked_request_object = MagicMock() |
1117 | - MockRequest.return_value = mocked_request_object |
1118 | - mocked_page_object = MagicMock() |
1119 | - mock_urlopen.return_value = mocked_page_object |
1120 | - mock_get_user_agent.return_value = 'user_agent' |
1121 | - mocked_registry_object = MagicMock() |
1122 | - mocked_application_object = MagicMock() |
1123 | - mocked_registry_object.get.return_value = mocked_application_object |
1124 | - MockRegistry.return_value = mocked_registry_object |
1125 | - fake_url = 'this://is.a.fake/url' |
1126 | - |
1127 | - # WHEN: The get_web_page() method is called |
1128 | - returned_page = get_web_page(fake_url, update_openlp=True) |
1129 | - |
1130 | - # THEN: The correct methods are called with the correct arguments and a web page is returned |
1131 | - MockRequest.assert_called_with(fake_url) |
1132 | - mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent') |
1133 | - self.assertEqual(1, mocked_request_object.add_header.call_count, |
1134 | - 'There should only be 1 call to add_header') |
1135 | - mock_urlopen.assert_called_with(mocked_request_object, timeout=30) |
1136 | - mocked_page_object.geturl.assert_called_with() |
1137 | - mocked_registry_object.get.assert_called_with('application') |
1138 | - mocked_application_object.process_events.assert_called_with() |
1139 | - self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') |
1140 | |
1141 | === modified file 'tests/functional/openlp_core_ui/test_first_time.py' |
1142 | --- tests/functional/openlp_core_ui/test_first_time.py 2016-05-31 21:40:13 +0000 |
1143 | +++ tests/functional/openlp_core_ui/test_first_time.py 2016-12-21 12:50:44 +0000 |
1144 | @@ -31,7 +31,7 @@ |
1145 | from tests.functional import patch |
1146 | from tests.helpers.testmixin import TestMixin |
1147 | |
1148 | -from openlp.core.lib.webpagereader import CONNECTION_RETRIES, get_web_page |
1149 | +from openlp.core.common.httputils import CONNECTION_RETRIES, get_web_page |
1150 | |
1151 | |
1152 | class TestFirstTimeWizard(TestMixin, TestCase): |
1153 | |
1154 | === modified file 'tests/functional/openlp_core_ui/test_firsttimeform.py' |
1155 | --- tests/functional/openlp_core_ui/test_firsttimeform.py 2016-05-31 21:40:13 +0000 |
1156 | +++ tests/functional/openlp_core_ui/test_firsttimeform.py 2016-12-21 12:50:44 +0000 |
1157 | @@ -23,7 +23,6 @@ |
1158 | Package to test the openlp.core.ui.firsttimeform package. |
1159 | """ |
1160 | import os |
1161 | -import socket |
1162 | import tempfile |
1163 | import urllib |
1164 | from unittest import TestCase |
1165 | @@ -236,20 +235,3 @@ |
1166 | # THEN: the critical_error_message_box should have been called |
1167 | self.assertEquals(mocked_message_box.mock_calls[1][1][0], 'Network Error 407', |
1168 | 'first_time_form should have caught Network Error') |
1169 | - |
1170 | - @patch('openlp.core.ui.firsttimeform.urllib.request.urlopen') |
1171 | - def test_socket_timeout(self, mocked_urlopen): |
1172 | - """ |
1173 | - Test socket timeout gets caught |
1174 | - """ |
1175 | - # GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download |
1176 | - first_time_form = FirstTimeForm(None) |
1177 | - first_time_form.initialize(MagicMock()) |
1178 | - mocked_urlopen.side_effect = socket.timeout() |
1179 | - |
1180 | - # WHEN: Attempt to retrieve a file |
1181 | - first_time_form.url_get_file(url='http://localhost/test', f_path=self.tempfile) |
1182 | - |
1183 | - # THEN: socket.timeout should have been caught |
1184 | - # NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files |
1185 | - self.assertFalse(os.path.exists(self.tempfile), 'FTW url_get_file should have caught socket.timeout') |
Looks ok to me