diff --git a/pythonforandroid/recipe.py b/pythonforandroid/recipe.py index 4de888306a..48efa8de1d 100644 --- a/pythonforandroid/recipe.py +++ b/pythonforandroid/recipe.py @@ -156,10 +156,10 @@ def report_hook(index, blksize, size): while True: try: urlretrieve(url, target, report_hook) - except OSError as e: + except OSError: attempts += 1 if attempts >= 5: - raise e + raise stdout.write('Download failed retrying in a second...') time.sleep(1) continue diff --git a/tests/test_recipe.py b/tests/test_recipe.py index 8946c92247..eefddee8aa 100644 --- a/tests/test_recipe.py +++ b/tests/test_recipe.py @@ -2,10 +2,28 @@ import types import unittest import warnings +import mock +from backports import tempfile from pythonforandroid.build import Context from pythonforandroid.recipe import Recipe, import_recipe +def patch_logger(level): + return mock.patch('pythonforandroid.recipe.{}'.format(level)) + + +def patch_logger_info(): + return patch_logger('info') + + +def patch_logger_debug(): + return patch_logger('debug') + + +class DummyRecipe(Recipe): + pass + + class TestRecipe(unittest.TestCase): def test_recipe_dirs(self): @@ -58,3 +76,49 @@ def test_import_recipe(self): module = import_recipe(name, pathname) assert module is not None assert recorded_warnings == [] + + def test_download_if_necessary(self): + """ + Download should happen via `Recipe.download()` only if the recipe + specific environment variable is not set. + """ + # download should happen as the environment variable is not set + recipe = DummyRecipe() + with mock.patch.object(Recipe, 'download') as m_download: + recipe.download_if_necessary() + assert m_download.call_args_list == [mock.call()] + # after setting it the download should be skipped + env_var = 'P4A_test_recipe_DIR' + env_dict = {env_var: '1'} + with mock.patch.object(Recipe, 'download') as m_download, mock.patch.dict(os.environ, env_dict): + recipe.download_if_necessary() + assert m_download.call_args_list == [] + + def test_download(self): + """ + Verifies the actual download gets triggered when the URL is set. + """ + # test with no URL set + recipe = DummyRecipe() + with patch_logger_info() as m_info: + recipe.download() + assert m_info.call_args_list == [ + mock.call('Skipping test_recipe download as no URL is set')] + # when the URL is set `Recipe.download_file()` should be called + filename = 'Python-3.7.4.tgz' + url = 'https://www.python.org/ftp/python/3.7.4/{}'.format(filename) + recipe._url = url + recipe.ctx = Context() + with ( + patch_logger_debug()) as m_debug, ( + mock.patch.object(Recipe, 'download_file')) as m_download_file, ( + mock.patch('pythonforandroid.recipe.sh.touch')) as m_touch, ( + tempfile.TemporaryDirectory()) as temp_dir: + recipe.ctx.setup_dirs(temp_dir) + recipe.download() + assert m_download_file.call_args_list == [mock.call(url, filename)] + assert m_debug.call_args_list == [ + mock.call( + 'Downloading test_recipe from ' + 'https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz')] + assert m_touch.call_count == 1 diff --git a/tox.ini b/tox.ini index 63393eab3f..bd1ae28df4 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,7 @@ deps = pytest virtualenv py3: coveralls + backports.tempfile # makes it possible to override pytest args, e.g. # tox -- tests/test_graph.py commands = pytest {posargs:tests/}