Skip to content

Commit

Permalink
Refs #9 -- Ensure non-strict mode checks presence of all PK attrs.
Browse files Browse the repository at this point in the history
  • Loading branch information
mxsasha committed May 15, 2018
1 parent 99aee84 commit 74e30f7
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 17 deletions.
38 changes: 23 additions & 15 deletions irrd/rpsl/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ def _validate_object(self) -> None:
(see the docstring for __init__).
"""
self.cleaned_data: Dict[str, str] = {}
if self.strict_validation:
self._validate_attribute_counts()
self._validate_attribute_counts()
self._clean_attribute_data()

if self.strict_validation:
Expand All @@ -182,21 +181,30 @@ def _validate_attribute_counts(self) -> None:
Validate the number of times each attribute occurs.
The expected counts (0, 1, or >=1) are derived indirectly
from the field data.
from the field data. In non-strict mode, only validate
presence of all PK attributes.
"""
attrs_present = Counter([attr[0] for attr in self._object_data])
for attr_name, count in attrs_present.items():
if attr_name not in self.attrs_allowed:
self.messages.error(f"Unrecognised attribute {attr_name} on object {self.rpsl_object_class}")
if count > 1 and attr_name not in self.attrs_multiple:
self.messages.error(
f"Attribute {attr_name} on object {self.rpsl_object_class} occurs multiple times, but is "
f"only allowed once")
for attr_required in self.attrs_required:
if attr_required not in attrs_present:
self.messages.error(
f"Mandatory attribute {attr_required} on object {self.rpsl_object_class} is missing"
)

if self.strict_validation:
for attr_name, count in attrs_present.items():
if attr_name not in self.attrs_allowed:
self.messages.error(f"Unrecognised attribute {attr_name} on object {self.rpsl_object_class}")
if count > 1 and attr_name not in self.attrs_multiple:
self.messages.error(
f"Attribute '{attr_name}' on object {self.rpsl_object_class} occurs multiple times, but is "
f"only allowed once")
for attr_required in self.attrs_required:
if attr_required not in attrs_present:
self.messages.error(
f"Mandatory attribute '{attr_required}' on object {self.rpsl_object_class} is missing"
)
else:
for attr_pk in self.pk_fields:
if attr_pk not in attrs_present:
self.messages.error(
f"Primary key attribute '{attr_pk}' on object {self.rpsl_object_class} is missing"
)

def _clean_attribute_data(self) -> None:
"""
Expand Down
14 changes: 12 additions & 2 deletions irrd/rpsl/tests/test_rpsl_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def test_malformed_attribute_name(self):
def test_missing_mandatory_attribute(self):
obj = rpsl_object_from_text(SAMPLE_MISSING_MANDATORY_ATTRIBUTE, strict_validation=True)
assert len(obj.messages.errors()) == 1, f"Unexpected extra errors: {obj.messages.errors()}"
assert "Mandatory attribute tech-c on object as-block is missing" in obj.messages.errors()[0]
assert "Mandatory attribute 'tech-c' on object as-block is missing" in obj.messages.errors()[0]

obj = rpsl_object_from_text(SAMPLE_MISSING_MANDATORY_ATTRIBUTE, strict_validation=False)
assert len(obj.messages.errors()) == 0, f"Unexpected extra errors: {obj.messages.errors()}"
Expand Down Expand Up @@ -249,7 +249,7 @@ def test_clean_missing_key(self, tmp_gpg_dir):

errors = obj.messages.errors()
assert len(errors) == 2, f"Unexpected multiple errors: {errors}"
assert "Mandatory attribute certif on object key-cert is missing" in errors[0]
assert "Mandatory attribute 'certif' on object key-cert is missing" in errors[0]
assert "No valid data found" in errors[1]

def test_verify(self, tmp_gpg_dir):
Expand Down Expand Up @@ -359,6 +359,16 @@ def test_parse(self):
# Field cleaning will cause our object to look slightly different than the original, hence the replace()
assert obj.render_rpsl_text() == rpsl_text.replace("193.254.030.00/24", "193.254.30.0/24")

def test_missing_pk_nonstrict(self):
# In non-strict mode, the parser should not fail validation for missing
# attributes, except for those part of the PK. Route is one of the few
# objects that has two PK attributes.
missing_pk_route = "route: 192.0.2.0/24"
obj = rpsl_object_from_text(missing_pk_route, strict_validation=False)
assert obj.__class__ == RPSLRoute
assert len(obj.messages.errors()) == 1, f"Unexpected extra errors: {obj.messages.errors()}"
assert "Primary key attribute 'origin' on object route is missing" in obj.messages.errors()[0]

def test_generate_template(self):
template = RPSLRoute().generate_template()
assert template == TEMPLATE_ROUTE_OBJECT
Expand Down

0 comments on commit 74e30f7

Please sign in to comment.