Skip to content

Commit

Permalink
Merge a4c5577 into a9271e0
Browse files Browse the repository at this point in the history
  • Loading branch information
eduzen committed May 11, 2019
2 parents a9271e0 + a4c5577 commit b10a665
Show file tree
Hide file tree
Showing 17 changed files with 880 additions and 924 deletions.
4 changes: 2 additions & 2 deletions .appveyor.yml
Expand Up @@ -25,10 +25,10 @@ install:

# Check that we have the expected version and architecture for Python
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""

build: off

test_script:
# Run the project tests
- "%CMD_IN_ENV% python bin/fades -v -r requirements.txt -x nosetests -v -s tests"
- "%CMD_IN_ENV% python bin/fades -v -r requirements.txt -x pytest"
4 changes: 1 addition & 3 deletions .travis.yml
@@ -1,16 +1,14 @@
language: python

python:
- "3.3"
- "3.4"
- "3.5"
- "3.6"
- "3.7-dev"
install:
- "pip install -r requirements.txt"
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install python-coveralls ; fi
script:
- "nosetests --with-xcoverage --cover-package=fades -v fades tests"
- "pytest --cov=fades"
after_script:
- "flake8 fades --max-line-length=99 --select=E,W,F,C,N"

Expand Down
8 changes: 6 additions & 2 deletions requirements.txt
@@ -1,8 +1,6 @@
flake8==3.5.0
logassert==2
mccabe==0.6.1
nose==1.3.7
nosexcover==1.0.10
pep257==0.7.0
pep8==1.7.0
pycodestyle==2.3.1
Expand All @@ -12,3 +10,9 @@ pyxdg==0.25
rst2html5==1.9.3
setuptools>=5.5
wheel==0.26.0
coverage==4.0.3
pytest==4.4.2
pytest-xdist==1.28.0
pytest-sugar==0.9.2
pytest-cov==2.5.1
pytest-mock==1.10.4
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -121,7 +121,7 @@ def finalize_options(self):
'install': CustomInstall,
},
install_requires=['setuptools'],
tests_require=['logassert', 'pyxdg', 'pyuca', 'nose', 'flake8',
tests_require=['logassert', 'pyxdg', 'pyuca', 'pytest', 'flake8',
'pep257', 'rst2html5'], # what unittests require
python_requires='>=3.3', # Minimum Python version supported.
extras_require={
Expand Down
2 changes: 1 addition & 1 deletion test
Expand Up @@ -12,7 +12,7 @@ fi

FADES='./bin/fades -r requirements.txt'

$FADES -x nosetests --with-xcoverage --cover-package=fades -v -s $TARGET_TESTS
$FADES -x pytest --cov=fades

# check if we are using exit() in the code.
if grep -r -n ' exit(' --include="*.py" .; then echo 'Please use sys.exit() instead of exit(). https://github.com/PyAr/fades/issues/280'; fi
2 changes: 1 addition & 1 deletion testdev
Expand Up @@ -10,4 +10,4 @@ else
TARGET_TESTS="fades tests"
fi

./bin/fades -r requirements.txt -x nosetests -v -s $TARGET_TESTS
./bin/fades -r requirements.txt -x pytest
2 changes: 1 addition & 1 deletion testdev.bat
Expand Up @@ -8,4 +8,4 @@ if not [%*] == [] (
set TARGET_TESTS=fades tests
)

bin\fades -r requirements.txt -x nosetests -v -s %TARGET_TESTS%
bin\fades -r requirements.txt -x pytest -v -s %TARGET_TESTS%
41 changes: 41 additions & 0 deletions tests/cache/test_cache.py
@@ -0,0 +1,41 @@
"""Tests for the helpers."""
from fades import cache


def test_missing_file_pytest(tmp_file, mocker):
venvscache = cache.VEnvsCache(str(tmp_file))
mock = mocker.patch.object(venvscache, '_select')
mock.return_value = None
resp = venvscache.get_venv('requirements', 'interpreter', uuid='', options='options')
mock.assert_called_with([], 'requirements', 'interpreter', uuid='', options='options')
assert not resp


def test_empty_file_pytest(tmp_file, mocker):
open(tmp_file, 'wt', encoding='utf8').close()
venvscache = cache.VEnvsCache(tmp_file)
mock = mocker.patch.object(venvscache, '_select', return_value=None)
resp = venvscache.get_venv('requirements', 'interpreter')
mock.assert_called_with([], 'requirements', 'interpreter', uuid='', options=None)
assert not resp


def test_some_file_content_pytest(tmp_file, mocker):
with open(tmp_file, 'wt', encoding='utf8') as fh:
fh.write('foo\nbar\n')
venvscache = cache.VEnvsCache(tmp_file)
mock = mocker.patch.object(venvscache, '_select', return_value="resp")
resp = venvscache.get_venv('requirements', 'interpreter', uuid='', options='options')
mock.assert_called_with(['foo', 'bar'], 'requirements', 'interpreter', uuid='',
options='options')
assert resp == 'resp'


def test_get_by_uuid_pytest(tmp_file, mocker):
with open(tmp_file, 'wt', encoding='utf8') as fh:
fh.write('foo\nbar\n')
venvscache = cache.VEnvsCache(tmp_file)
mock = mocker.patch.object(venvscache, '_select', return_value='resp')
resp = venvscache.get_venv(uuid='uuid')
mock.assert_called_with(['foo', 'bar'], None, '', uuid='uuid', options=None)
assert resp == 'resp'
98 changes: 98 additions & 0 deletions tests/cache/test_comparisons.py
@@ -0,0 +1,98 @@
import json
import pytest

from fades import parsing

from tests.conftest import get_req, get_distrib


@pytest.mark.parametrize("req,installed,expected", [
("==5", "5", "ok"),
("==5", "2", None),
(">5", "4", None),
(">5", "5", None),
(">5", "6", "ok"),
(">=5", "4", None),
(">=5", "5", "ok"),
(">=5", "6", "ok"),
("<5", "4", "ok"),
("<5", "5", None),
("<5", "6", None),
("<=5", "4", "ok"),
("<=5", "5", "ok"),
("<=5", "6", None),
("== 2.5", "2.5.0", "ok"),
("> 2.7", "2.12", "ok"),
("> 2.7a0", "2.7", "ok"),
("> 2.7", "2.7a0", None),
(">1.6,<1.9,!=1.9.6", "1.5.0", None),
(">1.6,<1.9,!=1.9.6", "1.6.7", "ok"),
(">1.6,<1.9,!=1.8.6", "1.8.7", "ok"),
(">1.6,<1.9,!=1.9.6", "1.9.6", None),
])
def test_check_versions(venvscache, req, installed, expected):
"""The comparison in the selection."""
reqs = {"pypi": get_req("dep" + req)}
interpreter = "pythonX.Y"
options = {"foo": "bar"}
venv = json.dumps({
"metadata": "ok",
"installed": {"pypi": {"dep": installed}},
"interpreter": "pythonX.Y",
"options": {"foo": "bar"}
})
resp = venvscache._select([venv], reqs, interpreter, uuid="", options=options)
assert resp == expected


@pytest.mark.parametrize("possible_venvs", [
[
(get_distrib(('dep', '3')), 'venv_best_fit'),
],
[
(get_distrib(('dep1', '3'), ('dep2', '3')), 'venv_best_fit'),
],
[
(get_distrib(('dep', '5')), 'venv_best_fit'),
(get_distrib(('dep', '3')), 'venv_1'),
],
[
(get_distrib(('dep1', '5'), ('dep2', '7')), 'venv_best_fit'),
(get_distrib(('dep1', '3'), ('dep2', '6')), 'venv_1'),
],
[
(get_distrib(('dep1', '3'), ('dep2', '9')), 'venv_1'),
(get_distrib(('dep1', '5'), ('dep2', '7')), 'venv_best_fit'),
],
[
(get_distrib(('dep1', '5'), ('dep2', '7')), 'venv_1'),
(get_distrib(('dep1', '3'), ('dep2', '9')), 'venv_best_fit'),
],
[
(get_distrib(('dep1', '3'), ('dep2', '9'), ('dep3', '4')), 'venv_best_fit'),
(get_distrib(('dep1', '5'), ('dep2', '7'), ('dep3', '2')), 'venv_1'),
],
[
(get_distrib(('dep2', '3'), ('dep1', '2'), ('dep3', '8')), 'venv_best_fit'),
(get_distrib(('dep1', '7'), ('dep3', '5'), ('dep2', '2')), 'venv_1'),
],
[
(get_distrib(('dep1', '3'), ('dep2', '2')), 'venv_1'),
(get_distrib(('dep1', '4'), ('dep2', '2')), 'venv_2'),
(get_distrib(('dep1', '5'), ('dep2', '7')), 'venv_best_fit'),
(get_distrib(('dep1', '5'), ('dep2', '6')), 'venv_3'),
],
[
([parsing.VCSDependency('someurl')], 'venv_best_fit'),
],
[
([parsing.VCSDependency('someurl')] + get_distrib(('dep', '3')), 'venv_best_fit'),
],
[
([parsing.VCSDependency('someurl')] + get_distrib(('dep', '3')), 'venv_best_fit'),
([parsing.VCSDependency('someurl')] + get_distrib(('dep', '1')), 'venv_1'),
],
])
def test_best_fit(venvscache, possible_venvs):
"""Check the venv best fitting decissor."""
assert venvscache._select_better_fit(possible_venvs) == 'venv_best_fit'
86 changes: 86 additions & 0 deletions tests/cache/test_remove.py
@@ -0,0 +1,86 @@
import json
import os
import time
import pytest

from threading import Thread

from fades import cache


def test_missing_file(tmp_file):
venvscache = cache.VEnvsCache(tmp_file)
venvscache.remove('missing/path')

lines = venvscache._read_cache()
assert lines == []


def test_missing_env_in_cache(tmp_file):
venvscache = cache.VEnvsCache(tmp_file)
options = {'foo': 'bar'}
venvscache.store('installed', {'env_path': 'some/path'}, 'interpreter', options=options)
lines = venvscache._read_cache()
assert len(lines) == 1

venvscache.remove('some/path')

lines = venvscache._read_cache()
assert lines == []


def test_preserve_cache_data_ordering(tmp_file):
venvscache = cache.VEnvsCache(tmp_file)
# store 3 venvs
options = {'foo': 'bar'}
venvscache.store('installed1', {'env_path': 'path/env1'}, 'interpreter', options=options)
venvscache.store('installed2', {'env_path': 'path/env2'}, 'interpreter', options=options)
venvscache.store('installed3', {'env_path': 'path/env3'}, 'interpreter', options=options)

venvscache.remove('path/env2')

lines = venvscache._read_cache()
assert len(lines) == 2
assert json.loads(lines[0]).get('metadata').get('env_path') == 'path/env1'
assert json.loads(lines[1]).get('metadata').get('env_path') == 'path/env3'


@pytest.mark.skip(reason="I dont know why is not working with pytest")
def test_lock_cache_for_remove(tmp_file, mocker):
venvscache = cache.VEnvsCache(tmp_file)
# store 3 venvs
options = {'foo': 'bar'}
venvscache.store('installed1', {'env_path': 'path/env1'}, 'interpreter', options=options)
venvscache.store('installed2', {'env_path': 'path/env2'}, 'interpreter', options=options)
venvscache.store('installed3', {'env_path': 'path/env3'}, 'interpreter', options=options)

# patch _write_cache so it emulates a slow write during which
# another process managed to modify the cache file before the
# first process finished writing the modified cache data
original_write_cache = venvscache._write_cache
p = mocker.patch('fades.cache.VEnvsCache._write_cache')
mock_write_cache = p.start()

t1 = Thread(target=venvscache.remove, args=('path/env1',))

def slow_write_cache(*args, **kwargs):
p.stop()
t1.start()
# wait to ensure t1 thread must wait for lock to be released
time.sleep(0.01)
original_write_cache(*args, **kwargs)

mock_write_cache.side_effect = slow_write_cache

# just a sanity check
assert not os.path.exists(venvscache.filepath + '.lock')
# remove a virtualenv from the cache
venvscache.remove('path/env2')
t1.join()

# when cache file is properly locked both virtualenvs
# will have been removed from the cache
lines = venvscache._read_cache()
assert len(lines) == 1
assert json.loads(lines[0]).get('metadata').get('env_path') == 'path/env3'
assert not os.path.exists(venvscache.filepath + '.lock')

0 comments on commit b10a665

Please sign in to comment.