def test_resource_reference_change_type_conversion_non_breaking(self): child_resource = make_resource_descriptor( resource_type="example.v1/Foo", resource_patterns=["bar/{bar}/foo/{foo}", "bar/{bar}/foo"], ) parent_resource = make_resource_descriptor( resource_type="example.v1/Bar", resource_patterns=["bar/{bar}"] ) # Register two resources in database. resource_database = make_resource_database( resources=[child_resource, parent_resource] ) # The original field is defined by child type. field_options_child = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=True ) field_with_reference_child = make_field( name="Test", options=field_options_child, resource_database=resource_database, ) # The update field is defined by parent type. field_options_parent = make_field_annotation_resource_reference( resource_type="example.v1/Bar", is_child_type=False ) field_with_reference_parent = make_field( name="Test", options=field_options_parent, resource_database=resource_database, ) # The two resources can be resolved to the identical resource. FieldComparator( field_with_reference_child, field_with_reference_parent, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings() # No breaking change should be detected. self.assertFalse(finding) # Reverse should be same since the two resources can # be resolved to the identical resource. FieldComparator( field_with_reference_parent, field_with_reference_child, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings() # No breaking change should be detected. self.assertFalse(finding)
def test_resource_reference_removal_non_breaking2(self): # Removed resource reference is defined by child type, and it # can be resolved to the same resource with the message options. # Original field has resource reference `example.v1/Foo`. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_with_reference = make_field(name="Test", options=field_options) # Update field has no resource reference. But the message has # resource options `example.v1/Foo`. message_resource = make_resource_descriptor( resource_type="example.v1/Foo", resource_patterns=["bar/{bar}"] ) field_resource = make_resource_descriptor( resource_type="example.v1/Foo", resource_patterns=["bar/{bar}/foo/{foo}"] ) # Register the two resources in the database. resource_database = make_resource_database( resources=[message_resource, field_resource] ) field_without_reference = make_field( name="Test", message_resource=message_resource, resource_database=resource_database, ) # `bar/{bar}` is the parent resource of `bar/{bar}/foo/{foo}`. FieldComparator( field_with_reference, field_without_reference, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_MOVED") self.assertEqual(finding.change_type.name, "MINOR")
def test_resource_reference_removal_non_breaking1(self): # Removed resource reference is defined by type, and it is # added back to the message options. # Original field has resource reference `example.v1/Foo`. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_with_reference = make_field(name="Test", options=field_options) # Update field has no resource reference. But the message has # resource options `example.v1/Foo`. message_resource = make_resource_descriptor( resource_type="example.v1/Foo", resource_patterns=["bar/{bar}"] ) field_without_reference = make_field( name="Test", message_resource=message_resource ) FieldComparator( field_with_reference, field_without_reference, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_MOVED") self.assertEqual(finding.change_type.name, "MINOR")
def test_resource_reference_removal_breaking2(self): # Removed resource reference is defined by type, which is not identical # with the message options. # Original field has resource reference `example.v1/Foo`. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_with_reference = make_field(name="Test", options=field_options) # Update field has no resource reference, and the resource type # is different from the message options type. message_resource = make_resource_descriptor( resource_type="NotInteresting", resource_patterns=["NotInteresting"] ) field_without_reference = make_field( name="Test", message_resource=message_resource ) FieldComparator( field_with_reference, field_without_reference, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_actionable_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_REMOVAL") self.assertEqual(finding.change_type.name, "MAJOR")
def test_resource_reference_change_same_type_breaking(self): # Both fields have resource reference identified by type. # But the type value is different. Breaking change. field_options_foo = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_options_bar = make_field_annotation_resource_reference( resource_type="example.v1/Bar", is_child_type=False ) field_with_reference_foo = make_field(name="Test", options=field_options_foo) field_with_reference_bar = make_field(name="Test", options=field_options_bar) FieldComparator( field_with_reference_foo, field_with_reference_bar, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings()[0] self.assertEqual(finding.change_type.name, "MAJOR")
def test_resource_reference_change_type_conversion_breaking(self): resource_bar = make_resource_descriptor( resource_type="example.v1/Bar", resource_patterns=["bar/{bar}/foo/{foo}", "bar/{bar}/foo"], ) resource_foo = make_resource_descriptor( resource_type="example.v1/Foo", resource_patterns=["foo/{foo}"] ) # Register two resources in database. resource_database = make_resource_database( resources=[resource_bar, resource_foo] ) # The original field is defined by child type. field_options_child = make_field_annotation_resource_reference( resource_type="example.v1/Bar", is_child_type=True ) field_with_reference_child = make_field( name="Test", options=field_options_child, resource_database=resource_database, ) # The update field is defined by parent type. field_options_parent = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_with_reference_parent = make_field( name="Test", options=field_options_parent, resource_database=resource_database, ) # The two resources can nnot be resolved to the identical resource. FieldComparator( field_with_reference_child, field_with_reference_parent, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_CHANGE_CHILD_TYPE") self.assertEqual(finding.change_type.name, "MAJOR")
def test_resource_reference_change_same_child_type_non_breaking(self): # The field has the identical resource reference. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=True ) field_with_reference = make_field(name="Test", options=field_options) FieldComparator( field_with_reference, field_with_reference, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings() # No breaking change should be detected. self.assertFalse(finding)
def test_resource_reference_addition_breaking(self): # The added resource reference is not in the database. Breaking change. # The original field is without resource reference. field_without_reference = make_field(name="Test") # The update field has resource reference, but it does not exist # in the global database. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_with_reference = make_field(name="Test", options=field_options) FieldComparator( field_without_reference, field_with_reference, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_all_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_ADDITION")
def test_resource_reference_removal_breaking1(self): # Removed resource reference is not added in message options. Breaking. # Original field has resource reference `example.v1/Foo`. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=False ) field_with_reference = make_field(name="Test", options=field_options) # The update field has no resource reference, and no resource reference is # defined in the message. field_without_reference = make_field(name="Test") FieldComparator( field_with_reference, field_without_reference, self.finding_container, context="ctx", ).compare() finding = self.finding_container.get_actionable_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_REMOVAL") self.assertEqual(finding.change_type.name, "MAJOR")
def test_resource_reference_removal_breaking3(self): # Removed resource reference is defined by child type, which can not # be resolved to identical resource with the message options. # Original field has resource reference `example.v1/Foo`. field_options = make_field_annotation_resource_reference( resource_type="example.v1/Foo", is_child_type=True ) field_with_reference = make_field(name="Test", options=field_options) # Update field has no resource reference, and the removed resource child type # is not identical with the message resource option. message_resource = make_resource_descriptor( resource_type="example.v1/Bar", resource_patterns=["bar/{bar}"] ) field_resource = make_resource_descriptor( resource_type="example.v1/Foo", resource_patterns=["foo/{foo}"] ) # Register the two resources in the database. resource_database = make_resource_database( resources=[message_resource, field_resource] ) field_without_reference = make_field( name="Test", resource_database=resource_database, message_resource=message_resource, ) FieldComparator( field_with_reference, field_without_reference, self.finding_container, context="ctx", ).compare() # `bar/{bar}` is not parent resource of `foo/{foo}`. finding = self.finding_container.get_actionable_findings()[0] self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_REMOVAL") self.assertEqual(finding.change_type.name, "MAJOR")