Esempio n. 1
0
 def test_enum_change(self):
     enum_original = make_enum(
         name="Irrelevant",
         values=(
             ("RED", 1),
             ("GREEN", 2),
             ("BLUE", 3),
         ),
     )
     enum_update = make_enum(
         name="Irrelevant",
         values=(
             ("RED", 1),
             ("GREEN", 2),
         ),
     )
     FileSetComparator(
         make_file_set(files=[make_file_pb2(enums=[enum_original])]),
         make_file_set(files=[make_file_pb2(enums=[enum_update])]),
         self.finding_container,
     ).compare()
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(finding.message,
                      "An existing EnumValue `BLUE` is removed.")
     self.assertEqual(finding.category.name, "ENUM_VALUE_REMOVAL")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "my_proto.proto")
Esempio n. 2
0
 def test_java_outer_classname_removal(self):
     option1 = descriptor_pb2.FileOptions()
     option1.java_outer_classname = "Foo"
     file1 = make_file_pb2(
         name="fil1.proto",
         package="example.v1",
         options=option1,
     )
     option2 = descriptor_pb2.FileOptions()
     option2.java_outer_classname = "Bar"
     file2 = make_file_pb2(
         name="fil2.proto",
         package="example.v1",
         options=option2,
     )
     file_set_original = make_file_set(files=[file1, file2])
     option3 = descriptor_pb2.FileOptions()
     option3.java_outer_classname = "Bar"
     file3 = make_file_pb2(name="file3.proto",
                           package="example.v1beta",
                           options=option3)
     file_set_update = make_file_set(files=[file3])
     FileSetComparator(file_set_original, file_set_update,
                       self.finding_container).compare()
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(finding.category.name, "PACKAGING_OPTION_REMOVAL")
     self.assertEqual(
         finding.message,
         "An existing packaging option `Foo` for `java_outer_classname` is removed.",
     )
     self.assertEqual(finding.change_type.name, "MAJOR")
Esempio n. 3
0
    def test_resources_addition(self):
        file_set_original = make_file_set(
            files=[make_file_pb2(name="foo.proto", package=".example.v1")])

        options_update = make_file_options_resource_definition(
            resource_type=".example.v1.Bar",
            resource_patterns=["foo/{foo}/bar/{bar}"])
        file_pb2 = make_file_pb2(name="foo.proto",
                                 package=".example.v1",
                                 options=options_update)
        file_set_update = make_file_set(files=[file_pb2])
        FileSetComparator(file_set_original, file_set_update,
                          self.finding_container).compare()
        finding = self.finding_container.getAllFindings()[0]
        self.assertEqual(
            finding.message,
            "A new resource definition `.example.v1.Bar` has been added.",
        )
        self.assertEqual(finding.change_type.name, "MINOR")
        self.assertEqual(
            finding.category.name,
            "RESOURCE_DEFINITION_ADDITION",
        )
        self.assertEqual(
            finding.location.proto_file_name,
            "foo.proto",
        )
Esempio n. 4
0
    def test_resources_existing_pattern_removal(self):
        options_original = make_file_options_resource_definition(
            resource_type=".example.v1.Bar",
            resource_patterns=["bar/{bar}", "foo/{foo}/bar"],
        )
        file_pb2 = make_file_pb2(name="foo.proto",
                                 package=".example.v1",
                                 options=options_original)
        file_set_original = make_file_set(files=[file_pb2])

        options_update = make_file_options_resource_definition(
            resource_type=".example.v1.Bar", resource_patterns=["bar/{bar}"])
        file_pb2 = make_file_pb2(name="foo.proto",
                                 package=".example.v1",
                                 options=options_update)
        file_set_update = make_file_set(files=[file_pb2])

        FileSetComparator(file_set_original, file_set_update,
                          self.finding_container).compare()
        finding = self.finding_container.getAllFindings()[0]
        self.assertEqual(
            finding.message,
            "An existing pattern value of the resource definition `.example.v1.Bar` is removed.",
        )
        self.assertEqual(finding.change_type.name, "MAJOR")
        self.assertEqual(finding.category.name, "RESOURCE_PATTERN_REMOVEL")
        self.assertEqual(
            finding.location.proto_file_name,
            "foo.proto",
        )
Esempio n. 5
0
 def test_resource_reference_change(self):
     _INVOKER_ORIGNAL = UnittestInvoker(
         ["resource_reference_v1.proto"],
         "resource_reference_v1_descriptor_set.pb",
         True,
     )
     _INVOKER_UPDATE = UnittestInvoker(
         ["resource_reference_v1beta1.proto"],
         "resource_reference_v1beta1_descriptor_set.pb",
         True,
     )
     FileSetComparator(FileSet(_INVOKER_ORIGNAL.run()),
                       FileSet(_INVOKER_UPDATE.run())).compare()
     findings_map = {
         f.message: f
         for f in FindingContainer.getAllFindings()
     }
     self.assertEqual(
         findings_map[
             "The child_type 'example.googleapis.com/t1' and type 'example.googleapis.com/t1' of resource reference option in field 'topic' cannot be resolved to the identical resource."]
         .category.name,
         "RESOURCE_REFERENCE_CHANGE",
     )
     _INVOKER_ORIGNAL.cleanup()
     _INVOKER_UPDATE.cleanup()
Esempio n. 6
0
    def test_packaging_options_version_update(self):
        file_options_original = descriptor_pb2.FileOptions()
        file_options_original.java_outer_classname = "ServiceProto"
        file_options_original.java_package = "com.google.cloud.service.v1"
        file_options_original.csharp_namespace = "Google.Cloud.Service.V1"
        file_options_original.php_namespace = "Google\\Cloud\\Service\\V1"
        file_options_original.ruby_package = "Google::Cloud::Service::V1"
        file_original = make_file_pb2(
            name="original.proto",
            package="google.cloud.service.v1",
            options=file_options_original,
        )

        file_options_update = descriptor_pb2.FileOptions()
        file_options_update.java_outer_classname = "ServiceProto"
        file_options_update.java_package = "com.google.cloud.service.v1alpha"
        file_options_update.csharp_namespace = "Google.Cloud.Service.V1alpha"
        file_options_update.php_namespace = "Google\\Cloud\\Service\\V1alpha"
        file_options_update.ruby_package = "Google::Cloud::Service::V1alpha"
        file_update = make_file_pb2(
            name="update.proto",
            package="google.cloud.service.v1alpha",
            options=file_options_update,
        )

        FileSetComparator(
            make_file_set(files=[file_original]),
            make_file_set(files=[file_update]),
            self.finding_container,
        ).compare()
        self.assertEqual(self.finding_container.get_all_findings(), [])
Esempio n. 7
0
    def test_resources_existing_pattern_change(self):
        options_original = make_file_options_resource_definition(
            resource_type=".example.v1.Bar",
            resource_patterns=["foo/{foo}/bar/{bar}"])
        file_pb2 = make_file_pb2(name="foo.proto",
                                 package=".example.v1",
                                 options=options_original)
        file_set_original = make_file_set(files=[file_pb2])
        options_update = make_file_options_resource_definition(
            resource_type=".example.v1.Bar",
            resource_patterns=["foo/{foo}/bar/"])
        file_pb2 = make_file_pb2(name="foo.proto",
                                 package=".example.v1",
                                 options=options_update)
        file_set_update = make_file_set(files=[file_pb2])

        FileSetComparator(file_set_original, file_set_update,
                          self.finding_container).compare()
        finding = next(f for f in self.finding_container.get_all_findings()
                       if f.change_type.name == "MAJOR")
        self.assertEqual(finding.category.name, "RESOURCE_PATTERN_REMOVAL")
        self.assertEqual(
            finding.location.proto_file_name,
            "foo.proto",
        )
Esempio n. 8
0
    def test_packaging_options_version_update(self):
        file_options_original = descriptor_pb2.FileOptions()
        file_options_original.java_outer_classname = "ServiceProto"
        file_options_original.java_package = "com.google.cloud.service.v1"
        file_options_original.csharp_namespace = "Google.Cloud.Service.V1"
        file_options_original.php_namespace = "Google\\Cloud\\Service\\V1"
        file_options_original.ruby_package = "Google::Cloud::Service::V1"
        file_original = make_file_pb2(
            name="original.proto",
            package="google.cloud.service.v1",
            options=file_options_original,
        )

        file_options_update = descriptor_pb2.FileOptions()
        file_options_update.java_outer_classname = "ServiceProto"
        file_options_update.java_package = "com.google.cloud.service.v1alpha"
        file_options_update.csharp_namespace = "Google.Cloud.Service.V1alpha"
        file_options_update.php_namespace = "Google\\Cloud\\Service\\V1alpha"
        file_options_update.ruby_package = "Google::Cloud::Service::V1alpha"
        file_update = make_file_pb2(
            name="update.proto",
            package="google.cloud.service.v1alpha",
            options=file_options_update,
        )

        FileSetComparator(
            make_file_set(files=[file_original]),
            make_file_set(files=[file_update]),
            self.finding_container,
        ).compare()
        findings_map = self.finding_container.getAllFindings()
        # No breaking changes since there are only minor version updates.
        self.assertFalse(findings_map)
Esempio n. 9
0
 def test_service_change(self):
     input_message = make_message(name="request",
                                  full_name=".example.v1.request")
     output_message = make_message(name="response",
                                   full_name=".example.v1.response")
     service_original = make_service(methods=[
         make_method(
             name="DoThing",
             input_message=input_message,
             output_message=output_message,
         )
     ])
     service_update = make_service()
     FileSetComparator(
         make_file_set(files=[
             make_file_pb2(
                 services=[service_original],
                 messages=[input_message, output_message],
             )
         ]),
         make_file_set(files=[make_file_pb2(services=[service_update])]),
         self.finding_container,
     ).compare()
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(finding.message,
                      "An existing rpc method `DoThing` is removed.")
     self.assertEqual(finding.category.name, "METHOD_REMOVAL")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "my_proto.proto")
Esempio n. 10
0
 def test_resource_reference_change(self):
     _INVOKER_ORIGNAL = Loader(
         proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
         proto_files=[os.path.join(self.PROTO_DIR, "resource_reference_v1.proto")],
         descriptor_set=None,
     )
     _INVOKER_UPDATE = Loader(
         proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
         proto_files=[
             os.path.join(self.PROTO_DIR, "resource_reference_v1beta1.proto")
         ],
         descriptor_set=None,
     )
     FileSetComparator(
         FileSet(_INVOKER_ORIGNAL.get_descriptor_set()),
         FileSet(_INVOKER_UPDATE.get_descriptor_set()),
         self.finding_container,
     ).compare()
     finding = next(
         f
         for f in self.finding_container.get_all_findings()
         if f.category.name == "RESOURCE_REFERENCE_CHANGE_CHILD_TYPE"
     )
     self.assertEqual(
         finding.location.proto_file_name, "resource_reference_v1beta1.proto"
     )
     self.assertEqual(finding.location.source_code_line, 25)
     # Find more details in comments of `resource_reference_v1beta1.proto`
     # 1. Resource_reference annotation is removed for `string name=1`,
     # but it is added in message-level. Non-breaking change.
     # 2. File-level resource definition `t2` is removed, but is added
     # to message-level resource. Non-breaking change.
     breaking_changes = self.finding_container.get_actionable_findings()
     self.assertEqual(len(breaking_changes), 1)
Esempio n. 11
0
 def test_resources_removal(self):
     # Create message with resource options.
     message_options = make_message_options_resource_definition(
         resource_type="example.v1/Bar",
         resource_patterns=["user/{user}", "user/{user}/bar/"],
     )
     message = make_message("Test", options=message_options)
     # Original file set with one resource defined at message level.
     file_set_original = make_file_set(files=[
         make_file_pb2(
             name="bar.proto", package=".example.v1", messages=[message])
     ])
     # Update file set without any resources.
     file_set_update = make_file_set(
         files=[make_file_pb2(name="foo.proto", package=".example.v1")])
     FileSetComparator(file_set_original, file_set_update,
                       self.finding_container).compare()
     findings_map = {
         f.message: f
         for f in self.finding_container.getAllFindings()
     }
     file_resource_removal = findings_map[
         "An existing resource definition `example.v1/Bar` has been removed."]
     self.assertEqual(
         file_resource_removal.category.name,
         "RESOURCE_DEFINITION_REMOVAL",
     )
     self.assertEqual(
         file_resource_removal.location.proto_file_name,
         "bar.proto",
     )
Esempio n. 12
0
    def test_resources_change(self):
        _INVOKER_ORIGNAL = Loader(
            proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
            proto_files=[os.path.join(self.PROTO_DIR, "resource_database_v1.proto")],
            descriptor_set=None,
        )
        _INVOKER_UPDATE = Loader(
            proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
            proto_files=[
                os.path.join(self.PROTO_DIR, "resource_database_v1beta1.proto")
            ],
            descriptor_set=None,
        )
        FileSetComparator(
            FileSet(_INVOKER_ORIGNAL.get_descriptor_set()),
            FileSet(_INVOKER_UPDATE.get_descriptor_set()),
            self.finding_container,
        ).compare()

        addition_finding = next(
            f
            for f in self.finding_container.get_all_findings()
            if f.category.name == "RESOURCE_PATTERN_ADDITION"
        )
        removal_finding = next(
            f
            for f in self.finding_container.get_all_findings()
            if f.category.name == "RESOURCE_PATTERN_REMOVAL"
        )
        resource_definition_removal_finding = next(
            f
            for f in self.finding_container.get_all_findings()
            if f.category.name == "RESOURCE_DEFINITION_REMOVAL"
        )
        self.assertEqual(
            addition_finding.location.proto_file_name,
            "resource_database_v1.proto",
        )
        self.assertEqual(addition_finding.location.source_code_line, 13)

        self.assertEqual(
            removal_finding.location.proto_file_name,
            "resource_database_v1.proto",
        )
        self.assertEqual(
            removal_finding.location.source_code_line,
            13,
        )
        self.assertEqual(
            resource_definition_removal_finding.location.proto_file_name,
            "resource_database_v1.proto",
        )
        self.assertEqual(
            resource_definition_removal_finding.location.source_code_line, 34
        )
        self.assertEqual(resource_definition_removal_finding.change_type.value, 1)
Esempio n. 13
0
 def test_service_removal(self):
     file_set = make_file_set(
         files=[make_file_pb2(services=[make_service()], )])
     FileSetComparator(
         file_set,
         make_file_set(),
         self.finding_container,
     ).compare()
     finding = self.finding_container.get_all_findings()[0]
     self.assertEqual(finding.change_type.name, "MAJOR")
Esempio n. 14
0
 def test_service_addition(self):
     file_set = make_file_set(
         files=[make_file_pb2(services=[make_service()], )])
     FileSetComparator(
         make_file_set(),
         file_set,
         self.finding_container,
     ).compare()
     finding = self.finding_container.get_all_findings()[0]
     self.assertEqual(finding.category.name, "SERVICE_ADDITION")
     self.assertEqual(finding.change_type.name, "MINOR")
Esempio n. 15
0
 def test_service_removal(self):
     file_set = make_file_set(
         files=[make_file_pb2(services=[make_service()], )])
     FileSetComparator(
         file_set,
         make_file_set(),
         self.finding_container,
     ).compare()
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(finding.message,
                      "An existing service `Placeholder` is removed.")
     self.assertEqual(finding.change_type.name, "MAJOR")
Esempio n. 16
0
 def test_service_addition(self):
     file_set = make_file_set(
         files=[make_file_pb2(services=[make_service()], )])
     FileSetComparator(
         make_file_set(),
         file_set,
         self.finding_container,
     ).compare()
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(finding.message,
                      "A new service `Placeholder` is added.")
     self.assertEqual(finding.change_type.name, "MINOR")
Esempio n. 17
0
 def test_message_change_breaking(self):
     message_original = make_message(
         fields=(make_field(name="field_one", number=1), ))
     message_update = make_message(
         fields=(make_field(name="field_two", number=1), ))
     FileSetComparator(
         make_file_set(files=[make_file_pb2(messages=[message_original])]),
         make_file_set(files=[make_file_pb2(messages=[message_update])]),
         self.finding_container,
     ).compare()
     finding = self.finding_container.get_all_findings()[0]
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.category.name, "FIELD_NAME_CHANGE")
     self.assertEqual(finding.location.proto_file_name, "my_proto.proto")
Esempio n. 18
0
 def test_enum_change(self):
     _INVOKER_ORIGNAL = UnittestInvoker(["enum_v1.proto"],
                                        "enum_v1_descriptor_set.pb")
     _INVOKER_UPDATE = UnittestInvoker(["enum_v1beta1.proto"],
                                       "enum_v1beta1_descriptor_set.pb")
     FileSetComparator(FileSet(_INVOKER_ORIGNAL.run()),
                       FileSet(_INVOKER_UPDATE.run())).compare()
     findings_map = {
         f.message: f
         for f in FindingContainer.getAllFindings()
     }
     finding = findings_map["An Enum BookType is removed"]
     self.assertEqual(finding.category.name, "ENUM_REMOVAL")
     self.assertEqual(finding.location.path, "enum_v1.proto Line: 5")
     _INVOKER_ORIGNAL.cleanup()
     _INVOKER_UPDATE.cleanup()
Esempio n. 19
0
 def test_enum_in_dependency_change_breaking(self):
     # Enum "dep_message" is imported from dep.proto and referenced as a field type.
     field_type_original = make_enum(
         name="dep_enum",
         proto_file_name="dep.proto",
     )
     message_original = make_message(
         fields=[make_field(type_name=".test.import.dep_enum")], )
     # Message "test_enum" is defined in update.proto referenced as a field type.
     field_type_update = make_enum(name="test_enum", )
     message_update = make_message(
         fields=[make_field(type_name="test_enum")])
     FileSetComparator(
         make_file_set(files=[
             make_file_pb2(
                 name="orignal.proto",
                 messages=[message_original],
                 dependency="test/import/dep.proto",
                 package="example.v1",
             ),
             make_file_pb2(
                 name="dep.proto",
                 enums=[field_type_original],
                 package="test.import",
             ),
         ]),
         make_file_set(files=[
             make_file_pb2(
                 name="update.proto",
                 messages=[message_update],
                 enums=[field_type_update],
                 package="example.v1beta1",
             )
         ]),
         self.finding_container,
     ).compare()
     # The breaking change should be in field level, instead of message removal,
     # since the message is imported from dependency file.
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(
         finding.message,
         "Type of an existing field `my_field` is changed from `.test.import.dep_enum` to `test_enum`.",
     )
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.category.name, "FIELD_TYPE_CHANGE")
     self.assertEqual(finding.location.proto_file_name, "update.proto")
Esempio n. 20
0
    def detect_breaking_changes(self):
        # Init FileSetComparator and compare the two FileDescriptorSet.
        FileSetComparator(
            FileSet(self.descriptor_set_original),
            FileSet(self.descriptor_set_update),
            self.finding_container,
        ).compare()

        if not self.opts:
            return self.finding_container.getActionableFindings()
        # Output json file of findings and human-readable messages if the
        # command line option is enabled.
        with open(self.opts.output_json_path, "w") as write_json_file:
            json.dump(self.finding_container.toDictArr(), write_json_file)

        if self.opts.human_readable_message:
            sys.stdout.write(self.finding_container.toHumanReadableMessage())
Esempio n. 21
0
    def test_packaging_options_change(self):
        file_options_original = descriptor_pb2.FileOptions()
        file_options_original.php_namespace = "Google\\Cloud\\Service\\V1"
        file_options_original.csharp_namespace = "Google.Cloud.Service.V1"
        file_options_original.java_outer_classname = "ServiceProto"
        file_original = make_file_pb2(
            name="original.proto",
            package="google.cloud.service.v1",
            options=file_options_original,
        )

        file_options_update = descriptor_pb2.FileOptions()
        # Breaking since version should be updated to `v1alpha`
        file_options_update.php_namespace = "Google\\Cloud\\Service\\V1beta"
        # No breaking change
        file_options_update.csharp_namespace = "Google.Cloud.Service.V1alpha"
        file_options_update.java_outer_classname = "ServiceUpdateProto"
        file_update = make_file_pb2(
            name="update.proto",
            package="google.cloud.service.v1alpha",
            options=file_options_update,
        )

        FileSetComparator(
            make_file_set(files=[file_original]),
            make_file_set(files=[file_update]),
            self.finding_container,
        ).compare()
        findings_map = {
            f.message: f
            for f in self.finding_container.getAllFindings()
        }
        java_classname_option_change = findings_map[
            "An existing packaging option `ServiceProto` for `java_outer_classname` is removed."]
        self.assertEqual(java_classname_option_change.category.name,
                         "PACKAGING_OPTION_REMOVAL")
        php_namespace_option_removal = findings_map[
            "An existing packaging option `Google\\Cloud\\Service\\V1` for `php_namespace` is removed."]
        self.assertEqual(php_namespace_option_removal.category.name,
                         "PACKAGING_OPTION_REMOVAL")

        php_namespace_option_addition = findings_map[
            "A new packaging option `Google\\Cloud\\Service\\V1beta` for `php_namespace` is added."]
        self.assertEqual(php_namespace_option_addition.category.name,
                         "PACKAGING_OPTION_ADDITION")
Esempio n. 22
0
 def test_message_change(self):
     _INVOKER_ORIGNAL = UnittestInvoker(["message_v1.proto"],
                                        "message_v1_descriptor_set.pb")
     _INVOKER_UPDATE = UnittestInvoker(["message_v1beta1.proto"],
                                       "message_v1beta1_descriptor_set.pb")
     FileSetComparator(FileSet(_INVOKER_ORIGNAL.run()),
                       FileSet(_INVOKER_UPDATE.run())).compare()
     findings_map = {
         f.message: f
         for f in FindingContainer.getAllFindings()
     }
     self.assertEqual(
         findings_map[
             "Type of the field is changed, the original is TYPE_INT32, but the updated is TYPE_STRING"]
         .category.name,
         "FIELD_TYPE_CHANGE",
     )
     _INVOKER_ORIGNAL.cleanup()
     _INVOKER_UPDATE.cleanup()
Esempio n. 23
0
 def test_resources_change(self):
     _INVOKER_ORIGNAL = UnittestInvoker(
         ["resource_database_v1.proto"],
         "resource_database_v1_descriptor_set.pb",
         True,
     )
     _INVOKER_UPDATE = UnittestInvoker(
         ["resource_database_v1beta1.proto"],
         "resource_database_v1beta1_descriptor_set.pb",
         True,
     )
     FileSetComparator(FileSet(_INVOKER_ORIGNAL.run()),
                       FileSet(_INVOKER_UPDATE.run())).compare()
     findings_map = {
         f.message: f
         for f in FindingContainer.getAllFindings()
     }
     self.assertEqual(
         findings_map[
             "Pattern value of the resource definition 'example.googleapis.com/t2' is updated from 'foo/{foo}/bar/{bar}/t2' to 'foo/{foo}/bar/{bar}/t2_update'."]
         .category.name,
         "RESOURCE_DEFINITION_CHANGE",
     )
     self.assertEqual(
         findings_map[
             "A file-level resource definition 'example.googleapis.com/t3' has been added."]
         .category.name,
         "RESOURCE_DEFINITION_ADDITION",
     )
     self.assertEqual(
         findings_map[
             "The pattern of message-level resource definition has changed from ['foo/{foo}/bar/{bar}'] to ['foo/{foo}/bar']."]
         .category.name,
         "RESOURCE_DEFINITION_CHANGE",
     )
     self.assertEqual(
         findings_map[
             "A message-level resource definition example.googleapis.com/Test has been removed."]
         .category.name,
         "RESOURCE_DEFINITION_REMOVAL",
     )
     _INVOKER_ORIGNAL.cleanup()
     _INVOKER_UPDATE.cleanup()
Esempio n. 24
0
    def test_service_change(self):
        _INVOKER_ORIGNAL = UnittestInvoker(["service_v1.proto"],
                                           "service_v1_descriptor_set.pb")
        _INVOKER_UPDATE = UnittestInvoker(["service_v1beta1.proto"],
                                          "service_v1beta1_descriptor_set.pb")
        FileSetComparator(FileSet(_INVOKER_ORIGNAL.run()),
                          FileSet(_INVOKER_UPDATE.run())).compare()
        findings_map = {
            f.message: f
            for f in FindingContainer.getAllFindings()
        }
        finding = findings_map[
            "The paginated response of method paginatedMethod is changed"]
        self.assertEqual(finding.category.name,
                         "METHOD_PAGINATED_RESPONSE_CHANGE")
        self.assertEqual(finding.location.path,
                         "service_v1beta1.proto Line: 11")

        _INVOKER_ORIGNAL.cleanup()
        _INVOKER_UPDATE.cleanup()
Esempio n. 25
0
    def test_packaging_options_change(self):
        file_options_original = descriptor_pb2.FileOptions()
        file_options_original.php_namespace = "Google\\Cloud\\Service\\V1"
        file_options_original.csharp_namespace = "Google.Cloud.Service.V1"
        file_options_original.java_outer_classname = "ServiceProto"
        file_original = make_file_pb2(
            name="original.proto",
            package="google.cloud.service.v1",
            options=file_options_original,
        )

        file_options_update = descriptor_pb2.FileOptions()
        # Breaking since version should be updated to `v1alpha`
        file_options_update.php_namespace = "Google\\Cloud\\Service\\V1beta"
        # No breaking change
        file_options_update.csharp_namespace = "Google.Cloud.Service.V1alpha"
        file_options_update.java_outer_classname = "ServiceUpdateProto"
        file_update = make_file_pb2(
            name="update.proto",
            package="google.cloud.service.v1alpha",
            options=file_options_update,
        )

        FileSetComparator(
            make_file_set(files=[file_original]),
            make_file_set(files=[file_update]),
            self.finding_container,
        ).compare()
        java_classname_option_removal = next(
            f for f in self.finding_container.get_all_findings()
            if f.category.name == "PACKAGING_OPTION_REMOVAL"
            and f.subject == "java_outer_classname")
        php_namespace_option_removal = next(
            f for f in self.finding_container.get_all_findings()
            if f.category.name == "PACKAGING_OPTION_REMOVAL"
            and f.subject == "php_namespace")
        self.assertTrue(java_classname_option_removal)
        self.assertTrue(php_namespace_option_removal)
Esempio n. 26
0
    def detect_breaking_changes(self):
        # Init FileSetComparator and compare the two FileDescriptorSet.
        FileSetComparator(
            FileSet(self.descriptor_set_original),
            FileSet(self.descriptor_set_update),
            self.finding_container,
        ).compare()

        if self.opts and self.opts.output_json_path:
            # Output json file of findings and human-readable messages if the
            # command line option is enabled.
            with open(self.opts.output_json_path, "w") as write_json_file:
                json.dump(
                    self.finding_container.to_dict_arr(), write_json_file, indent=2
                )

        if self.opts and self.opts.human_readable_message:
            sys.stdout.write(
                self.finding_container.to_human_readable_message(
                    line_numbers=self.opts.line_numbers
                )
            )

        return self.finding_container.get_actionable_findings()
Esempio n. 27
0
    def test_java_multiple_files_addition(self):
        option1 = descriptor_pb2.FileOptions()
        option1.java_multiple_files = False
        file1 = make_file_pb2(
            name="file.proto",
            package="example.v1",
            options=option1,
        )
        file_set_original = make_file_set(files=[file1])

        option2 = descriptor_pb2.FileOptions()
        option2.java_multiple_files = True
        file2 = make_file_pb2(
            name="file.proto",
            package="example.v1",
            options=option2,
        )
        file_set_update = make_file_set(files=[file2])
        FileSetComparator(file_set_original, file_set_update,
                          self.finding_container).compare()
        self.assertTrue(len(self.finding_container.get_all_findings()))
        finding = self.finding_container.get_all_findings()[0]
        self.assertEqual(finding.category.name, "PACKAGING_OPTION_ADDITION")
        self.assertEqual(finding.change_type.name, "MAJOR")
 def test_resource_reference_change(self):
     _INVOKER_ORIGNAL = Loader(
         proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
         proto_files=[os.path.join(self.PROTO_DIR, "resource_reference_v1.proto")],
         descriptor_set=None,
     )
     _INVOKER_UPDATE = Loader(
         proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
         proto_files=[
             os.path.join(self.PROTO_DIR, "resource_reference_v1beta1.proto")
         ],
         descriptor_set=None,
     )
     FileSetComparator(
         FileSet(_INVOKER_ORIGNAL.get_descriptor_set()),
         FileSet(_INVOKER_UPDATE.get_descriptor_set()),
         self.finding_container,
     ).compare()
     findings_map = {f.message: f for f in self.finding_container.getAllFindings()}
     # Type of the resource_reference is changed from type to child_type, but
     # they can not be resoved to the identical resource. Breaking change.
     finding = findings_map[
         "The child_type `example.googleapis.com/t1` and type `example.googleapis.com/t1` of resource reference option in field `topic` cannot be resolved to the identical resource."
     ]
     self.assertEqual(finding.category.name, "RESOURCE_REFERENCE_CHANGE")
     self.assertEqual(
         finding.location.proto_file_name, "resource_reference_v1beta1.proto"
     )
     self.assertEqual(finding.location.source_code_line, 25)
     # Find more details in comments of `resource_reference_v1beta1.proto`
     # 1. Resource_reference annotation is removed for `string name=1`,
     # but it is added in message-level. Non-breaking change.
     # 2. File-level resource definition `t2` is removed, but is added
     # to message-level resource. Non-breaking change.
     breaking_changes = self.finding_container.getActionableFindings()
     self.assertEqual(len(breaking_changes), 1)
 def test_resources_change(self):
     _INVOKER_ORIGNAL = Loader(
         proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
         proto_files=[os.path.join(self.PROTO_DIR, "resource_database_v1.proto")],
         descriptor_set=None,
     )
     _INVOKER_UPDATE = Loader(
         proto_definition_dirs=[self.PROTO_DIR, self.COMMON_PROTOS_DIR],
         proto_files=[
             os.path.join(self.PROTO_DIR, "resource_database_v1beta1.proto")
         ],
         descriptor_set=None,
     )
     FileSetComparator(
         FileSet(_INVOKER_ORIGNAL.get_descriptor_set()),
         FileSet(_INVOKER_UPDATE.get_descriptor_set()),
         self.finding_container,
     ).compare()
     findings_map = {f.message: f for f in self.finding_container.getAllFindings()}
     # An existing pattern of a file-level resource definition is changed.
     file_resource_pattern_change = findings_map[
         "An existing pattern value of the resource definition `example.googleapis.com/t2` is updated from `foo/{foo}/bar/{bar}/t2` to `foo/{foo}/bar/{bar}/t2_update`."
     ]
     self.assertEqual(
         file_resource_pattern_change.category.name, "RESOURCE_PATTERN_CHANGE"
     )
     self.assertEqual(
         file_resource_pattern_change.location.proto_file_name,
         "resource_database_v1beta1.proto",
     )
     self.assertEqual(file_resource_pattern_change.location.source_code_line, 13)
     # An existing pattern of a message-level resource annotation is changed.
     message_resource_pattern_change = findings_map[
         "An existing pattern value of the resource definition `example.googleapis.com/Foo` is updated from `foo/{foo}/bar/{bar}` to `foo/{foo}/bar`."
     ]
     self.assertEqual(
         message_resource_pattern_change.category.name,
         "RESOURCE_PATTERN_CHANGE",
     )
     self.assertEqual(
         message_resource_pattern_change.location.proto_file_name,
         "resource_database_v1beta1.proto",
     )
     self.assertEqual(
         message_resource_pattern_change.location.source_code_line,
         26,
     )
     # An existing message-level resource annotation is removed, and it is not moved to
     # file-level resource definition. So it is a breaking change.
     message_resource_removal = findings_map[
         "An existing resource definition `example.googleapis.com/Test` has been removed."
     ]
     self.assertEqual(
         message_resource_removal.category.name,
         "RESOURCE_DEFINITION_REMOVAL",
     )
     self.assertEqual(
         message_resource_removal.location.proto_file_name,
         "resource_database_v1.proto",
     )
     self.assertEqual(message_resource_removal.location.source_code_line, 34)
     self.assertEqual(message_resource_removal.change_type.value, 1)