From 46c7d66aaf47eb856d66a8144dd7a64d6cf93567 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 28 Apr 2010 16:55:10 -0400 Subject: [PATCH] Various fixes to implementation and uses of assert_installed. Factored out assert_installed() to handle common post-installation checks --- tests/path.py | 2 + tests/test_basic.py | 87 ++++++++++++++--------------------------- tests/test_cleanup.py | 8 ++-- tests/test_pip.py | 81 +++++++++++++++++++++++++++++++++++--- tests/test_uninstall.py | 8 ++-- 5 files changed, 115 insertions(+), 71 deletions(-) diff --git a/tests/path.py b/tests/path.py index 75448cc8e..bbba53759 100644 --- a/tests/path.py +++ b/tests/path.py @@ -8,6 +8,8 @@ class Path(_base): """ Models a path in an object oriented way. """ sep = os.sep # File system path separator: '/' or '\'. pathsep = os.pathsep # Separator in the PATH environment variable. + + string = _base def __new__(cls, *paths): return _base.__new__(cls, os.path.join(*paths) if len(paths) else '') diff --git a/tests/test_basic.py b/tests/test_basic.py index fbe9dbd8c..a93953bee 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1,5 +1,6 @@ from os.path import abspath, exists, join, dirname, curdir, pardir from test_pip import here, reset_env, run_pip, pyversion, mkdir +from path import Path def test_correct_pip_version(): """ @@ -70,12 +71,7 @@ def test_install_editable_from_svn(): """ e = reset_env() result = run_pip('install', '-e', 'svn+http://svn.colorstudy.com/INITools/trunk#egg=initools-dev', expect_error=True) - egg_link = result.files_created[e.site_packages / 'INITools.egg-link'] - # FIXME: I don't understand why there's a trailing . here: - assert egg_link.bytes.endswith('/test-scratch/src/initools\n.'), egg_link.bytes - assert (e.site_packages / 'easy-install.pth') in result.files_updated - assert 'src/initools' in result.files_created - assert 'src/initools/.svn' in result.files_created + result.assert_installed('INITools', with_files=['.svn']) def test_download_editable_to_custom_path(): """ @@ -87,9 +83,12 @@ def test_download_editable_to_custom_path(): result = run_pip('install', '-e', 'svn+http://svn.colorstudy.com/INITools/trunk#egg=initools-dev', '--src', 'customsrc', '--download', 'customdl', expect_error=True) - assert 'customsrc/initools' in result.files_created - assert 'customsrc/initools/setup.py' in result.files_created - assert [filename for filename in result.files_created.keys() if filename.startswith('customdl/initools')] + customsrc = Path('scratch')/'customsrc'/'initools' + assert customsrc in result.files_created, sorted(result.files_created.keys()) + assert customsrc/'setup.py' in result.files_created, sorted(result.files_created.keys()) + + customdl = Path('scratch')/'customdl'/'initools' + assert [filename for filename in result.files_created.keys() if filename.startswith(customdl)] def test_editable_no_install_followed_by_no_download(): """ @@ -100,37 +99,31 @@ def test_editable_no_install_followed_by_no_download(): result = run_pip('install', '-e', 'svn+http://svn.colorstudy.com/INITools/trunk#egg=initools-dev', '--no-install', expect_error=True) - assert lib_py + 'site-packages/INITools.egg-link' not in result.files_created - assert 'src/initools' in result.files_created - assert 'src/initools/.svn' in result.files_created + result.assert_installed('INITools', without_egg_link=True, with_files=['.svn']) result = run_pip('install', '-e', 'svn+http://svn.colorstudy.com/INITools/trunk#egg=initools-dev', '--no-download', expect_error=True) - egg_link = result.files_created[lib_py + 'site-packages/INITools.egg-link'] - # FIXME: I don't understand why there's a trailing . here: - assert egg_link.bytes.endswith('/test-scratch/src/initools\n.'), egg_link.bytes - assert (lib_py + 'site-packages/easy-install.pth') in result.files_updated - assert 'src/initools' not in result.files_created - assert 'src/initools/.svn' not in result.files_created + result.assert_installed('INITools', without_files=[curdir, '.svn']) def test_no_install_followed_by_no_download(): """ Test installing in two steps (first with --no-install, then with --no-download). """ - reset_env() + env = reset_env() result = run_pip('install', 'INITools==0.2', '--no-install', expect_error=True) assert (lib_py + 'site-packages/INITools-0.2-py%s.egg-info' % pyversion) not in result.files_created, str(result) - assert (lib_py + 'site-packages/initools') not in result.files_created, sorted(result.files_created.keys()) - assert 'build/INITools' in result.files_created - assert 'build/INITools/INITools.egg-info' in result.files_created + assert (env.site-packages/'initools') not in result.files_created, sorted(result.files_created.keys()) + build_dir = Path('scratch')/'build'/'INITools' + assert build_dir in result.files_created + assert build_dir/'INITools.egg-info' in result.files_created result = run_pip('install', 'INITools==0.2', '--no-download', expect_error=True) - assert (lib_py + 'site-packages/INITools-0.2-py%s.egg-info' % pyversion) in result.files_created, str(result) - assert (lib_py + 'site-packages/initools') in result.files_created, sorted(result.files_created.keys()) - assert 'build/INITools' not in result.files_created - assert 'build/INITools/INITools.egg-info' not in result.files_created + assert (env.site-packages/'INITools-0.2-py%s.egg-info' % pyversion) in result.files_created, str(result) + assert (env.site-packages/'initools') in result.files_created, sorted(result.files_created.keys()) + assert build_dir not in result.files_created + assert build_dir/'INITools.egg-info' not in result.files_created def test_bad_install_with_no_download(): """ @@ -158,14 +151,7 @@ def test_install_editable_from_git(): """ e = reset_env() result = run_pip('install', '-e', 'git://github.com/jezdez/django-feedutil.git#egg=django-feedutil', expect_error=True) - egg_link = result.files_created[e.site_packages / 'django-feedutil.egg-link'] - # FIXME: I don't understand why there's a trailing . here: - assert egg_link.bytes.endswith('.'), egg_link.bytes - #remove trailing "\n." and check that django-feedutil was installed - assert egg_link.bytes[:-1].strip().endswith(e.env_path/ 'src' / 'django-feedutil'), egg_link.bytes - assert e.site_packages / 'easy-install.pth' in result.files_updated - assert e.relative_env_path / 'src' / 'django-feedutil' in result.files_created - assert e.relative_env_path / 'src' / 'django-feedutil' / '.git' in result.files_created + result.assert_installed('django-feedutil', with_files=['.git']) def test_install_editable_from_hg(): """ @@ -174,15 +160,7 @@ def test_install_editable_from_hg(): """ e = reset_env() result = run_pip('install', '-e', 'hg+http://bitbucket.org/ubernostrum/django-registration/#egg=django-registration', expect_error=True) - egg_link = result.files_created[e.site_packages / 'django-registration.egg-link'] - # FIXME: I don't understand why there's a trailing . here: - assert egg_link.bytes.endswith('.'), egg_link.bytes - #remove trailing "\n." and check that django-registration was installed - assert egg_link.bytes[:-1].strip().endswith(e.env_path/ 'src' / 'django-registration'), egg_link.bytes - assert e.site_packages / 'easy-install.pth' in result.files_updated - assert e.relative_env_path / 'src' / 'django-registration' in result.files_created - assert e.relative_env_path / 'src' / 'django-registration'/'.hg' in result.files_created - + result.assert_installed('django-registration', with_files=['.hg']) def test_vcs_url_final_slash_normalization(): """ @@ -200,14 +178,7 @@ def test_install_editable_from_bazaar(): """ e = reset_env() result = run_pip('install', '-e', 'bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1/@174#egg=django-wikiapp', expect_error=True) - egg_link = result.files_created[e.site_packages / 'django-wikiapp.egg-link'] - # FIXME: I don't understand why there's a trailing . here: - assert egg_link.bytes.endswith('.'), egg_link.bytes - #remove trailing "\n." and check that django-wikiapp was installed - assert egg_link.bytes[:-1].strip().endswith(e.env_path/ 'src' / 'django-wikiapp'), egg_link.bytes - assert e.site_packages / 'easy-install.pth' in result.files_updated - assert e.relative_env_path / 'src' / 'django-wikiapp' in result.files_created - assert e.relative_env_path / 'src' /'django-wikiapp' / '.bzr' in result.files_created + result.assert_installed('django-wikiapp', with_files=['.bzr']) def test_vcs_url_urlquote_normalization(): @@ -224,11 +195,11 @@ def test_install_from_local_directory(): Test installing from a local directory. """ - reset_env() + env = reset_env() to_install = abspath(join(here, 'packages', 'FSPkg')) result = run_pip('install', to_install, expect_error=False) - assert (lib_py + 'site-packages/fspkg') in result.files_created, str(result.stdout) - assert (lib_py + 'site-packages/FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) + assert (env.site-packages/'fspkg') in result.files_created, str(result.stdout) + assert (env.site-packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) def test_install_from_local_directory_with_no_setup_py(): """ @@ -249,8 +220,8 @@ def test_install_curdir(): reset_env() run_from = abspath(join(here, 'packages', 'FSPkg')) result = run_pip('install', curdir, cwd=run_from, expect_error=False) - assert (lib_py + 'site-packages/fspkg') in result.files_created, str(result.stdout) - assert (lib_py + 'site-packages/FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) + assert (env.site-packages/'fspkg') in result.files_created, str(result.stdout) + assert (env.site-packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) def test_install_pardir(): """ @@ -260,5 +231,5 @@ def test_install_pardir(): reset_env() run_from = abspath(join(here, 'packages', 'FSPkg', 'fspkg')) result = run_pip('install', pardir, cwd=run_from, expect_error=False) - assert (lib_py + 'site-packages/fspkg') in result.files_created, str(result.stdout) - assert (lib_py + 'site-packages/FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) + assert (env.site-packages/'fspkg') in result.files_created, str(result.stdout) + assert (env.site-packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) diff --git a/tests/test_cleanup.py b/tests/test_cleanup.py index 0689d0a07..b4b53166f 100644 --- a/tests/test_cleanup.py +++ b/tests/test_cleanup.py @@ -2,7 +2,7 @@ import zipfile import textwrap from os.path import abspath, exists, join -from test_pip import base_path, here, reset_env, run_pip, write_file +from test_pip import here, reset_env, run_pip, write_file def test_cleanup_after_install_from_pypi(): @@ -10,10 +10,10 @@ def test_cleanup_after_install_from_pypi(): Test clean up after installing a package from PyPI. """ - reset_env() + env = reset_env() result = run_pip('install', 'INITools==0.2', expect_error=True) - build = join(base_path, "build") - src = join(base_path, "src") + build = env.scratch_path/"build" + src = env.scratch_path/"src" assert not exists(build), "build/ dir still exists: %s" % build assert not exists(src), "unexpected src/ dir exists: %s" % src diff --git a/tests/test_pip.py b/tests/test_pip.py index cdbafa7bb..0ea32a5e3 100755 --- a/tests/test_pip.py +++ b/tests/test_pip.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -import os, sys, tempfile, shutil, glob, atexit +import os, sys, tempfile, shutil, glob, atexit, textwrap from path import * pyversion = sys.version[:3] @@ -73,6 +73,15 @@ def reset_env(environ = None): env = None +class TestFailure(AssertionError): + """ + + An "assertion" failed during testing. + + """ + pass + + # # This cleanup routine prevents the __del__ method that cleans up the # tree of the last TestPipEnvironment from firing after shutil has @@ -85,6 +94,63 @@ def _cleanup(): atexit.register(_cleanup) +class TestPipResult(object): + + def __init__(self, impl): + self._impl = impl + + def __getattr__(self, attr): + return getattr(self._impl,attr) + + def assert_installed(self, pkg_name, with_files=[], without_files=[], without_egg_link=False): + e = self.test_env + + pkg_dir = e.relative_env_path/ 'src'/ pkg_name.lower() + + egg_link_path = e.site_packages / pkg_name + '.egg-link' + if without_egg_link: + if egg_link_path in self.files_created: + raise TestFailure, 'unexpected egg link file created: %r' % egg_link_path + else: + egg_link_file = self.files_created[egg_link_path] + + if not (# FIXME: I don't understand why there's a trailing . here + egg_link_file.bytes.endswith('.') + and egg_link_file.bytes[:-1].strip().endswith(pkg_dir)): + raise TestFailure, textwrap.dedent(u'''\ + Incorrect egg_link file %r + Expected ending: %r + ------- Actual contents ------- + %s + -------------------------------''' % ( + egg_link_file, + pkg_dir + u'\n.', + egg_link_file.bytes)) + + pth_file = Path.string(e.site_packages / 'easy-install.pth') + + if (pth_file in self.files_updated) == without_egg_link: + raise TestFailure, '%r unexpectedly %supdated by install' % ( + pth_file, ('' if without_egg_link else 'not ')) + + if (pkg_dir in self.files_created) == (curdir in without_files): + raise TestFailure, textwrap.dedent('''\ + expected package directory %r %sto be created + actually created: + %s + ''') % ( + Path.string(pkg_dir), + ('not ' if curdir in without_files else ''), + sorted(self.files_created.keys())) + + for f in with_files: + if not (pkg_dir/f).normpath in self.files_created: + raise TestFailure, 'Package directory %r missing expected content %f' % (pkg_dir,f) + + for f in without_files: + if (pkg_dir/f).normpath in self.files_created: + raise TestFailure, 'Package directory %r has unexpected content %f' % (pkg_dir,f) + class TestPipEnvironment(TestFileEnvironment): def __init__(self, environ=None): @@ -146,14 +212,19 @@ class TestPipEnvironment(TestFileEnvironment): # Install this version instead self.run('python', 'setup.py', 'install', cwd=src) + def run(self, *args, **kw): + cwd = kw.pop('cwd', None) + run_from = kw.pop('run_from',None) + assert not cwd or not run_from, "Don't use run_from; it's going away" + cwd = Path.string(cwd or run_from or self.cwd) + assert not isinstance(cwd,Path) + return TestPipResult( super(TestPipEnvironment,self).run(cwd=cwd,*args,**kw) ) + def __del__(self): shutil.rmtree(self.root_path, ignore_errors=True) def run_pip(*args, **kw): - # assert not 'run_from' in kw, '**** Use "cwd" instead of "run_from"!' - cwd = kw.get('run_from', get_env().cwd) - kw.pop('run_from', None) - return env.run('pip', cwd=cwd, *args, **kw) + return env.run('pip', *args, **kw) def write_file(filename, text, dest=None): """Write a file in the dest (default=env.scratch_path) diff --git a/tests/test_uninstall.py b/tests/test_uninstall.py index 438b632b7..b640156a9 100644 --- a/tests/test_uninstall.py +++ b/tests/test_uninstall.py @@ -62,7 +62,7 @@ def test_uninstall_easy_installed_console_scripts(): env = reset_env() result = env.run('easy_install', 'virtualenv') assert (env.bin_dir/'virtualenv') in result.files_created, sorted(result.files_created.keys()) - result2 = run_pip('uninstall', 'virtualenv', '-y', expect_error=True) + result2 = run_pip('uninstall', 'virtualenv', '-y') assert diff_states(result.files_before, result2.files_after, ignore=[env.relative_env_path/'build', 'cache']).values() == [{}, {}, {}] def test_uninstall_editable_from_svn(): @@ -71,9 +71,9 @@ def test_uninstall_editable_from_svn(): """ env = reset_env() - result = run_pip('install', '-e', 'svn+http://svn.colorstudy.com/INITools/trunk#egg=initools-dev', expect_error=True) - egg_link = result.files_created[env.site_packages/ 'INITools.egg-link'] - result2 = run_pip('uninstall', '-y', 'initools', expect_error=True) + result = run_pip('install', '-e', 'svn+http://svn.colorstudy.com/INITools/trunk#egg=initools-dev') + result.assert_installed('INITools') + result2 = run_pip('uninstall', '-y', 'initools') assert (env.relative_env_path/'src'/'initools' in result2.files_after), 'oh noes, pip deleted my sources!' assert diff_states(result.files_before, result2.files_after, ignore=[env.relative_env_path/'src'/'initools', env.relative_env_path/'build']).values() == [{}, {}, {}]