11import os
2+ import pytest
23import types
34import unittest
45import warnings
@@ -20,6 +21,10 @@ def patch_logger_debug():
2021 return patch_logger ('debug' )
2122
2223
24+ def patch_urlretrieve ():
25+ return mock .patch ('pythonforandroid.recipe.urlretrieve' )
26+
27+
2328class DummyRecipe (Recipe ):
2429 pass
2530
@@ -94,21 +99,34 @@ def test_download_if_necessary(self):
9499 recipe .download_if_necessary ()
95100 assert m_download .call_args_list == []
96101
97- def test_download (self ):
102+ def test_download_url_not_set (self ):
98103 """
99- Verifies the actual download gets triggered when the URL is set.
104+ Verifies that no download happens when URL is not set.
100105 """
101- # test with no URL set
102106 recipe = DummyRecipe ()
103107 with patch_logger_info () as m_info :
104108 recipe .download ()
105109 assert m_info .call_args_list == [
106110 mock .call ('Skipping test_recipe download as no URL is set' )]
107- # when the URL is set `Recipe.download_file()` should be called
111+
112+ @staticmethod
113+ def get_dummy_python_recipe_for_download_tests ():
114+ """
115+ Helper method for creating a test recipe used in download tests.
116+ """
117+ recipe = DummyRecipe ()
108118 filename = 'Python-3.7.4.tgz'
109119 url = 'https://www.python.org/ftp/python/3.7.4/{}' .format (filename )
110120 recipe ._url = url
111121 recipe .ctx = Context ()
122+ return recipe , filename
123+
124+ def test_download_url_is_set (self ):
125+ """
126+ Verifies the actual download gets triggered when the URL is set.
127+ """
128+ recipe , filename = self .get_dummy_python_recipe_for_download_tests ()
129+ url = recipe .url
112130 with (
113131 patch_logger_debug ()) as m_debug , (
114132 mock .patch .object (Recipe , 'download_file' )) as m_download_file , (
@@ -122,3 +140,39 @@ def test_download(self):
122140 'Downloading test_recipe from '
123141 'https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz' )]
124142 assert m_touch .call_count == 1
143+
144+ def test_download_file_scheme_https (self ):
145+ """
146+ Verifies `urlretrieve()` is being called on https downloads.
147+ """
148+ recipe , filename = self .get_dummy_python_recipe_for_download_tests ()
149+ url = recipe .url
150+ with (
151+ patch_urlretrieve ()) as m_urlretrieve , (
152+ tempfile .TemporaryDirectory ()) as temp_dir :
153+ recipe .ctx .setup_dirs (temp_dir )
154+ assert recipe .download_file (url , filename ) == filename
155+ assert m_urlretrieve .call_args_list == [
156+ mock .call (url , filename , mock .ANY )
157+ ]
158+
159+ def test_download_file_scheme_https_oserror (self ):
160+ """
161+ Checks `urlretrieve()` is being retried on `OSError`.
162+ After a number of retries the exception is re-reaised.
163+ """
164+ recipe , filename = self .get_dummy_python_recipe_for_download_tests ()
165+ url = recipe .url
166+ with (
167+ patch_urlretrieve ()) as m_urlretrieve , (
168+ mock .patch ('pythonforandroid.recipe.time.sleep' )) as m_sleep , (
169+ pytest .raises (OSError )), (
170+ tempfile .TemporaryDirectory ()) as temp_dir :
171+ recipe .ctx .setup_dirs (temp_dir )
172+ m_urlretrieve .side_effect = OSError
173+ assert recipe .download_file (url , filename ) == filename
174+ retry = 5
175+ expected_call_args_list = [mock .call (url , filename , mock .ANY )] * retry
176+ assert m_urlretrieve .call_args_list == expected_call_args_list
177+ expected_call_args_list = [mock .call (1 )] * (retry - 1 )
178+ assert m_sleep .call_args_list == expected_call_args_list
0 commit comments