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")
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")
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", )
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", )
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()
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(), [])
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", )
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)
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")
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)
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", )
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)
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")
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")
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")
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")
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")
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()
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")
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())
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")
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()
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()
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()
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)
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()
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)