more tests for the validation logic

Refactor the validation logic so we can test one rule at a time, then
write those tests.

Change-Id: I2250f451d92414d0003679d85b38aebbdf8bd3c9
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-03-27 14:20:15 -04:00
parent 3a378a6c57
commit ae899937df
2 changed files with 307 additions and 39 deletions

View File

@ -101,6 +101,48 @@ def get_global_reqs(content):
return global_reqs
def _validate_one(name, reqs, branch_reqs, blacklist, global_reqs):
"Returns True if there is a failure."
print(name, reqs, branch_reqs, blacklist, global_reqs)
if (name in branch_reqs.reqs and
reqs == branch_reqs.reqs[name]):
# Unchanged [or a change that preserves a current value]
return False
if name in blacklist:
# Blacklisted items are not synced and are managed
# by project teams as they see fit, so no further
# testing is needed.
return False
if name not in global_reqs:
print("Requirement %s not in openstack/requirements" %
str(reqs))
return True
if reqs == global_reqs[name]:
return False
counts = {}
for req in reqs:
if req.extras:
for extra in req.extras:
counts[extra] = counts.get(extra, 0) + 1
else:
counts[''] = counts.get('', 0) + 1
if not _is_requirement_in_global_reqs(
req, global_reqs[name]):
print("Requirement for package %s : %s does "
"not match openstack/requirements value : %s" % (
name, str(req), str(global_reqs[name])))
return True
for extra, count in counts.items():
if count != len(global_reqs[name]):
print("Package %s%s requirement does not match "
"number of lines (%d) in "
"openstack/requirements" % (
name,
('[%s]' % extra) if extra else '',
len(global_reqs[name])))
return True
def validate(head_reqs, branch_reqs, blacklist, global_reqs):
failed = False
# iterate through the changing entries and see if they match the global
@ -108,42 +150,15 @@ def validate(head_reqs, branch_reqs, blacklist, global_reqs):
for fname, freqs in head_reqs.reqs_by_file.items():
print("Validating %(fname)s" % {'fname': fname})
for name, reqs in freqs.items():
counts = {}
if (name in branch_reqs.reqs and
reqs == branch_reqs.reqs[name]):
# Unchanged [or a change that preserves a current value]
continue
if name in blacklist:
# Blacklisted items are not synced and are managed
# by project teams as they see fit, so no further
# testing is needed.
continue
if name not in global_reqs:
failed = True
print("Requirement %s not in openstack/requirements" %
str(reqs))
continue
if reqs == global_reqs[name]:
continue
for req in reqs:
if req.extras:
for extra in req.extras:
counts[extra] = counts.get(extra, 0) + 1
else:
counts[''] = counts.get('', 0) + 1
if not _is_requirement_in_global_reqs(
req, global_reqs[name]):
failed = True
print("Requirement for package %s : %s does "
"not match openstack/requirements value : %s" % (
name, str(req), str(global_reqs[name])))
for extra, count in counts.items():
if count != len(global_reqs[name]):
failed = True
print("Package %s%s requirement does not match "
"number of lines (%d) in "
"openstack/requirements" % (
name,
('[%s]' % extra) if extra else '',
len(global_reqs[name])))
failed = (
_validate_one(
name,
reqs,
branch_reqs,
blacklist,
global_reqs,
)
or failed
)
return failed

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import textwrap
from openstack_requirements import check
from openstack_requirements import requirement
@ -26,7 +28,11 @@ class TestIsReqInGlobalReqs(testtools.TestCase):
self.stdout = self.useFixture(self._stdout_fixture).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.stdout))
self.global_reqs = check.get_global_reqs('name>=1.2,!=1.4')
self.global_reqs = check.get_global_reqs(textwrap.dedent("""
name>=1.2,!=1.4
withmarker>=1.5;python_version=='3.5'
withmarker>=1.2,!=1.4;python_version=='2.7'
"""))
print('global_reqs', self.global_reqs)
def test_match(self):
@ -38,6 +44,17 @@ class TestIsReqInGlobalReqs(testtools.TestCase):
)
)
def test_match_with_markers(self):
req = requirement.parse(textwrap.dedent("""
withmarker>=1.5;python_version=='3.5'
"""))['withmarker'][0][0]
self.assertTrue(
check._is_requirement_in_global_reqs(
req,
self.global_reqs['withmarker'],
)
)
def test_name_mismatch(self):
req = requirement.parse('wrongname>=1.2,!=1.4')['wrongname'][0][0]
self.assertFalse(
@ -73,3 +90,239 @@ class TestIsReqInGlobalReqs(testtools.TestCase):
self.global_reqs['name'],
)
)
class TestValidateOne(testtools.TestCase):
def setUp(self):
super(TestValidateOne, self).setUp()
self._stdout_fixture = fixtures.StringStream('stdout')
self.stdout = self.useFixture(self._stdout_fixture).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.stdout))
def test_unchanged(self):
# If the line matches the value in the branch list everything
# is OK.
reqs = [
r
for r, line in requirement.parse('name>=1.2,!=1.4')['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': 'name>=1.2,!=1.4'}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs('name>=1.2,!=1.4')
self.assertFalse(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)
def test_blacklisted(self):
# If the package is blacklisted, everything is OK.
reqs = [
r
for r, line in requirement.parse('name>=1.2,!=1.4')['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': 'name>=1.2,!=1.4'}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs('name>=1.2,!=1.4')
self.assertFalse(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse('name'),
global_reqs=global_reqs,
)
)
def test_blacklisted_mismatch(self):
# If the package is blacklisted, it doesn't matter if the
# version matches.
reqs = [
r
for r, line in requirement.parse('name>=1.5')['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': 'name>=1.2,!=1.4'}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs('name>=1.2,!=1.4')
self.assertFalse(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse('name'),
global_reqs=global_reqs,
)
)
def test_not_in_global_list(self):
# If the package is not in the global list, that is an error.
reqs = [
r
for r, line in requirement.parse('name>=1.2,!=1.4')['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': 'name>=1.2,!=1.4'}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs('')
self.assertTrue(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)
def test_new_item_matches_global_list(self):
# If the new item matches the global list exactly that is OK.
reqs = [
r
for r, line in requirement.parse('name>=1.2,!=1.4')['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': ''}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs('name>=1.2,!=1.4')
self.assertFalse(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)
def test_new_item_mismatches_global_list(self):
# If the new item does not match the global value, that is an
# error.
reqs = [
r
for r, line in requirement.parse('name>=1.2,!=1.4,!=1.5')['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': ''}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs('name>=1.2,!=1.4')
self.assertTrue(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)
def test_new_item_matches_global_list_with_extra(self):
# If the global list has multiple entries for an item with
# different "extra" specifiers, the values must all be in the
# requirements file.
r_content = textwrap.dedent("""
name>=1.5;python_version=='3.5'
name>=1.2,!=1.4;python_version=='2.6'
""")
reqs = [
r
for r, line in requirement.parse(r_content)['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': ''}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs(textwrap.dedent("""
name>=1.5;python_version=='3.5'
name>=1.2,!=1.4;python_version=='2.6'
"""))
self.assertFalse(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)
def test_new_item_missing_extra_line(self):
# If the global list has multiple entries for an item with
# different "extra" specifiers, the values must all be in the
# requirements file.
r_content = textwrap.dedent("""
name>=1.2,!=1.4;python_version=='2.6'
""")
reqs = [
r
for r, line in requirement.parse(r_content)['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': ''}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs(textwrap.dedent("""
name>=1.5;python_version=='3.5'
name>=1.2,!=1.4;python_version=='2.6'
"""))
self.assertTrue(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)
def test_new_item_mismatches_global_list_with_extra(self):
# If the global list has multiple entries for an item with
# different "extra" specifiers, the values must all be in the
# requirements file.
r_content = textwrap.dedent("""
name>=1.5;python_version=='3.6'
name>=1.2,!=1.4;python_version=='2.6'
""")
reqs = [
r
for r, line in requirement.parse(r_content)['name']
]
branch_reqs = check.RequirementsList(
'testproj',
{'requirements': {'requirements.txt': ''}},
)
branch_reqs.process(False)
global_reqs = check.get_global_reqs(textwrap.dedent("""
name>=1.5;python_version=='3.5'
name>=1.2,!=1.4;python_version=='2.6'
"""))
self.assertTrue(
check._validate_one(
'name',
reqs=reqs,
branch_reqs=branch_reqs,
blacklist=requirement.parse(''),
global_reqs=global_reqs,
)
)