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")