requirements/tests/test_update.py
Sean Dague 38b7490667 provide more meaningful output on update.py
In an attempt to make the proposal bot changes for requirements be
more meaningful make the update.py script return something that's more
user friendly.

Now by default the script will return the following to stdout on success:

Version change for: mox, mox3, testrepository, testtools
Updated project/test-requirements.txt:
    mox==0.5.3                     ->   mox>=0.5.3
    mox3==0.7.3                    ->   mox3>=0.7.0
    testrepository>=0.0.13         ->   testrepository>=0.0.17
    testtools>=0.9.27              ->   testtools>=0.9.32

Add a verbose flag that will provide much of the previous debug info.

Eliminate the giant dict dump of all the requirements files, as that
was largely impossible to make sense of, and rarely provided any
insight. During a devstack run you'll have git hashes for all the
trees, so can track down exact file contents if needed.

By making this the default stdout we can then capture and use this for
the git commit messages.

In order to make the test output matching human readable ignore the 80
column limit for the expected blocks via #noqa.

Change-Id: I85604db7bffafcd20bf3cc546fe3e5d7bda72193
2015-01-08 16:18:26 -05:00

225 lines
9.9 KiB
Python

# Copyright 2013 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
import os
import os.path
import shutil
import subprocess
import sys
import fixtures
import testtools
def _file_to_list(fname):
with open(fname) as f:
content = list(map(lambda x: x.rstrip(), f.readlines()))
print(content)
return content
class UpdateTest(testtools.TestCase):
def _init_env(self):
self.project_dir = os.path.join(self.dir, "project")
self.bad_project_dir = os.path.join(self.dir, "bad_project")
self.oslo_dir = os.path.join(self.dir, "project_with_oslo")
self.req_file = os.path.join(self.dir, "global-requirements.txt")
self.dev_req_file = os.path.join(self.dir, "dev-requirements.txt")
self.proj_file = os.path.join(self.project_dir, "requirements.txt")
self.oslo_file = os.path.join(self.oslo_dir, "requirements.txt")
self.bad_proj_file = os.path.join(self.bad_project_dir,
"requirements.txt")
self.proj_test_file = os.path.join(self.project_dir,
"test-requirements.txt")
self.setup_file = os.path.join(self.project_dir, "setup.py")
self.old_setup_file = os.path.join(self.oslo_dir, "setup.py")
self.bad_setup_file = os.path.join(self.bad_project_dir, "setup.py")
self.setup_cfg_file = os.path.join(self.project_dir, "setup.cfg")
self.bad_setup_cfg_file = os.path.join(self.bad_project_dir,
"setup.cfg")
self.oslo_setup_cfg_file = os.path.join(self.oslo_dir, "setup.cfg")
os.mkdir(self.project_dir)
os.mkdir(self.oslo_dir)
os.mkdir(self.bad_project_dir)
shutil.copy("tests/files/gr-base.txt", self.req_file)
shutil.copy("tests/files/dev-req.txt", self.dev_req_file)
shutil.copy("tests/files/project-with-oslo-tar.txt", self.oslo_file)
shutil.copy("tests/files/project.txt", self.proj_file)
shutil.copy("tests/files/project-with-bad-requirement.txt",
self.bad_proj_file)
shutil.copy("tests/files/test-project.txt", self.proj_test_file)
shutil.copy("tests/files/setup.py", self.setup_file)
shutil.copy("tests/files/setup.py", self.bad_setup_file)
shutil.copy("tests/files/old-setup.py", self.old_setup_file)
shutil.copy("tests/files/setup.cfg", self.setup_cfg_file)
shutil.copy("tests/files/setup.cfg", self.bad_setup_cfg_file)
shutil.copy("tests/files/setup.cfg", self.oslo_setup_cfg_file)
shutil.copy("update.py", os.path.join(self.dir, "update.py"))
def _run_update(self):
# now go call update and see what happens
subprocess.check_output(
[sys.executable, "update.py", "project"])
subprocess.check_output([sys.executable, "update.py",
"project_with_oslo"])
def setUp(self):
super(UpdateTest, self).setUp()
self.dir = self.useFixture(fixtures.TempDir()).path
self._init_env()
# for convenience put us in the directory with the update.py
self.addCleanup(os.chdir, os.path.abspath(os.curdir))
os.chdir(self.dir)
def test_requirements(self):
self._run_update()
reqs = _file_to_list(self.req_file)
self.assertIn("jsonschema>=1.0.0,!=1.4.0,<2", reqs)
def test_project(self):
self._run_update()
reqs = _file_to_list(self.proj_file)
# ensure various updates take
self.assertIn("jsonschema>=1.0.0,!=1.4.0,<2", reqs)
self.assertIn("python-keystoneclient>=0.4.1", reqs)
self.assertIn("SQLAlchemy>=0.7,<=0.7.99", reqs)
def test_requirements_header(self):
self._run_update()
_REQS_HEADER = [
'# The order of packages is significant, because pip processes '
'them in the order',
'# of appearance. Changing the order has an impact on the overall '
'integration',
'# process, which may cause wedges in the gate later.',
]
reqs = _file_to_list(self.proj_file)
self.assertEqual(_REQS_HEADER, reqs[:3])
def test_project_with_oslo(self):
self._run_update()
reqs = _file_to_list(self.oslo_file)
oslo_tar = ("-f http://tarballs.openstack.org/oslo.config/"
"oslo.config-1.2.0a3.tar.gz#egg=oslo.config-1.2.0a3")
self.assertIn(oslo_tar, reqs)
self.assertIn("oslo.config>=1.2.0a3", reqs)
self.assertNotIn("oslo.config>=1.1.0", reqs)
def test_test_project(self):
self._run_update()
reqs = _file_to_list(self.proj_test_file)
self.assertIn("testtools>=0.9.32", reqs)
self.assertIn("testrepository>=0.0.17", reqs)
# make sure we didn't add something we shouldn't
self.assertNotIn("sphinxcontrib-pecanwsme>=0.2", reqs)
def test_install_setup(self):
self._run_update()
setup_contents = _file_to_list(self.setup_file)
self.assertIn("# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO"
" - DO NOT EDIT", setup_contents)
def test_no_install_setup(self):
self._run_update()
setup_contents = _file_to_list(self.old_setup_file)
self.assertNotIn(
"# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO"
" - DO NOT EDIT", setup_contents)
# These are tests which don't need to run the project update in advance
def test_requirment_not_in_global(self):
returncode = subprocess.call([sys.executable, "update.py",
"bad_project"])
self.assertEqual(returncode, 1)
def test_requirment_not_in_global_non_fatal(self):
env = os.environ.copy()
env['NON_STANDARD_REQS'] = '1'
returncode = subprocess.call(
[sys.executable, "update.py", "bad_project"],
env=env)
self.assertEqual(returncode, 0)
def test_requirement_soft_update(self):
returncode = subprocess.call(
[sys.executable, "update.py", "-s", "bad_project"])
self.assertEqual(returncode, 0)
reqs = _file_to_list(self.bad_proj_file)
self.assertIn("thisisnotarealdepedency", reqs)
# testing output
def test_non_verbose_output(self):
output = subprocess.check_output(
[sys.executable, "update.py", "project"])
expected = 'Version change for: greenlet, sqlalchemy, eventlet, pastedeploy, routes, webob, wsgiref, boto, kombu, pycrypto, python-swiftclient, lxml, jsonschema, python-keystoneclient\n' # noqa
expected += """Updated project/requirements.txt:
greenlet>=0.3.1 -> greenlet>=0.3.2
SQLAlchemy>=0.7.8,<=0.7.99 -> SQLAlchemy>=0.7,<=0.7.99
eventlet>=0.9.12 -> eventlet>=0.12.0
PasteDeploy -> PasteDeploy>=1.5.0
routes -> Routes>=1.12.3
WebOb>=1.2 -> WebOb>=1.2.3,<1.3
wsgiref -> wsgiref>=0.1.2
boto -> boto>=2.4.0
kombu>2.4.7 -> kombu>=2.4.8
pycrypto>=2.1.0alpha1 -> pycrypto>=2.6
python-swiftclient>=1.2,<2 -> python-swiftclient>=1.2
lxml -> lxml>=2.3
jsonschema -> jsonschema>=1.0.0,!=1.4.0,<2
python-keystoneclient>=0.2.0 -> python-keystoneclient>=0.4.1
Version change for: mox, mox3, testrepository, testtools
Updated project/test-requirements.txt:
mox==0.5.3 -> mox>=0.5.3
mox3==0.7.3 -> mox3>=0.7.0
testrepository>=0.0.13 -> testrepository>=0.0.17
testtools>=0.9.27 -> testtools>=0.9.32
"""
self.assertEqual(expected, output)
def test_verbose_output(self):
output = subprocess.check_output(
[sys.executable, "update.py", "-v", "project"])
expected = """Syncing project/requirements.txt
Version change for: greenlet, sqlalchemy, eventlet, pastedeploy, routes, webob, wsgiref, boto, kombu, pycrypto, python-swiftclient, lxml, jsonschema, python-keystoneclient\n""" # noqa
expected += """Updated project/requirements.txt:
greenlet>=0.3.1 -> greenlet>=0.3.2
SQLAlchemy>=0.7.8,<=0.7.99 -> SQLAlchemy>=0.7,<=0.7.99
eventlet>=0.9.12 -> eventlet>=0.12.0
PasteDeploy -> PasteDeploy>=1.5.0
routes -> Routes>=1.12.3
WebOb>=1.2 -> WebOb>=1.2.3,<1.3
wsgiref -> wsgiref>=0.1.2
boto -> boto>=2.4.0
kombu>2.4.7 -> kombu>=2.4.8
pycrypto>=2.1.0alpha1 -> pycrypto>=2.6
python-swiftclient>=1.2,<2 -> python-swiftclient>=1.2
lxml -> lxml>=2.3
jsonschema -> jsonschema>=1.0.0,!=1.4.0,<2
python-keystoneclient>=0.2.0 -> python-keystoneclient>=0.4.1
Syncing project/test-requirements.txt
Version change for: mox, mox3, testrepository, testtools
Updated project/test-requirements.txt:
mox==0.5.3 -> mox>=0.5.3
mox3==0.7.3 -> mox3>=0.7.0
testrepository>=0.0.13 -> testrepository>=0.0.17
testtools>=0.9.27 -> testtools>=0.9.32
Syncing setup.py
"""
self.assertEqual(expected, output)