-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unit tests Recipe download feature #1946
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a fan of this line break styling, but I'm willing to believe there's no great option for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not fan either, I usually use backslash There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also dislike backslashes (as is well documented :p), but I think they would be nicer here. I don't mind though, when there's no good solution we have to choose something. I've just googled and found https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack which is new to me. With this method you would do:
It's obviously less nice in that you have to know what ExitStack is to understand it, but at least the code is nicely formatted. I think I wouldn't be averse to using this, but I'm not saying we should either. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for sharing! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, my three cents to this: as per formatting, I would go for the following, basically because I usually trigger an script when I have a doubt (that runs python's black module targeting the file I want)...and this is what I got for the discussed lines:
Do you noticed that the aligned parenthesis helps with the reading? also there is some more space available...but...still may be confusing...anyway...I really prefer decorators when possible...it's cleaner I think, so I would split the test in two using
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for your input. |
||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ deps = | |
pytest | ||
virtualenv | ||
py3: coveralls | ||
backports.tempfile | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically backports Python TemporaryDirectory context manager to Python2. |
||
# makes it possible to override pytest args, e.g. | ||
# tox -- tests/test_graph.py | ||
commands = pytest {posargs:tests/} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor changes that I came across, doesn't harm, but sightly simplify things.
More serious refactoring will come after this module is properly covered by unit tests