Merge lp:~trb143/openlp/httpfixes into lp:openlp

Proposed by Tim Bentley
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
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.

To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) wrote :

Looks ok to me

review: Approve

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')