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 setUp(self): # We take the enumDescriptorProto `phoneType` and `phoneType` from the original # and updated `_descriptor_set.pb` files for comparison. self.enum_original = (FileSet( self._PB_ORIGNAL).messages_map["Person"].nested_enums["PhoneType"]) self.enum_update = (FileSet( self._PB_UPDATE).messages_map["Person"].nested_enums["PhoneType"])
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_get_root_package(self): common = descriptor_pb2.FileDescriptorProto( name="google/cloud/common_resources.proto", package="google.cloud", ) speech_resource = descriptor_pb2.FileDescriptorProto( name="google/cloud/speech/v1/resource.proto", package="google.cloud.speech.v1", ) speech_with_dep = descriptor_pb2.FileDescriptorProto( name="google/cloud/speech/v1/cloud_speech.proto", package="google.cloud.speech.v1", dependency=["google/cloud/speech/v1/resource.proto"], ) speech_no_dep = descriptor_pb2.FileDescriptorProto( name="google/cloud/speech/v1/cloud_speech.proto", package="google.cloud.speech.v1", ) self.assertEqual( FileSet.get_root_package( descriptor_pb2.FileDescriptorSet( file=[common, speech_with_dep, speech_resource])), "google.cloud.speech.v1", ) self.assertEqual( FileSet.get_root_package( descriptor_pb2.FileDescriptorSet( file=[common, speech_no_dep])), "google.cloud.speech.v1", ) self.assertEqual( FileSet.get_root_package( descriptor_pb2.FileDescriptorSet(file=[common])), "", )
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 setUp(self): # Get `Example` service from the original and updated `service_*.proto` files. self.service_original = FileSet( self._INVOKER_SERVICE_ORIGNAL.run() ).services_map["Example"] self.service_update = FileSet(self._INVOKER_SERVICE_UPDATE.run()).services_map[ "Example" ] # Get `Example` service from the original and updated `service_annotation_*.proto` files. self.service_annotation_original = FileSet( self._INVOKER_ANNOTATION_ORIGNAL.run() ).services_map["Example"] self.service_annotation_update = FileSet( self._INVOKER_ANNOTATION_UPDATE.run() ).services_map["Example"]
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 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_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_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 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()
class WrappersTest(unittest.TestCase): # This is for tesing the behavior of classes in src.comparator.wrapper. # UnittestInvoker helps us to execute the protoc command to compile the proto file, # get a *_descriptor_set.pb file (by -o option) which contains the serialized data in protos, and # create a FileDescriptorSet out of it. _CURRENT_DIR = os.getcwd() COMMON_PROTOS_DIR = os.path.join(_CURRENT_DIR, "api-common-protos") _INVOKER = Loader( proto_definition_dirs=[ os.path.join(_CURRENT_DIR, "test/testdata/protos/example/"), COMMON_PROTOS_DIR, ], proto_files=[ os.path.join(_CURRENT_DIR, "test/testdata/protos/example/wrappers.proto") ], descriptor_set=None, ) _FILE_SET = FileSet(_INVOKER.get_descriptor_set()) def test_file_set_wrapper(self): self.assertTrue(self._FILE_SET.messages_map) self.assertTrue(self._FILE_SET.enums_map) self.assertTrue(self._FILE_SET.services_map) resources_database = self._FILE_SET.resources_database self.assertEqual( resources_database.types["example.googleapis.com/t1"].value. pattern, ["foo/{foo}", "foo/{foo}/bar/{bar}/t1"], ) # The service from imported dependency `google/longrunning/operations` # is included in the file set. self.assertEqual(list(self._FILE_SET.services_map.keys()), ["Example"]) self.assertEqual(self._FILE_SET.root_package, "example.v1alpha") self.assertEqual(len(self._FILE_SET.definition_files), 1) self.assertEqual(self._FILE_SET.definition_files[0].name, "wrappers.proto") self.assertEqual(self._FILE_SET.api_version, "v1alpha") # Check the global messages/enums map self.assertEqual( [ message_name for message_name in self._FILE_SET.global_messages_map.keys() if message_name.startswith(".example.v1alpha") ], [ ".example.v1alpha.MapMessage", ".example.v1alpha.FooMetadata", ".example.v1alpha.FooResponse", ".example.v1alpha.FooRequest", ".example.v1alpha.FooRequest.NestedMessage", ], ) self.assertEqual( [ message_name for message_name in self._FILE_SET.global_messages_map.keys() if message_name.startswith(".google.api") ], [ ".google.api.ResourceReference", ".google.api.ResourceDescriptor", ".google.api.CustomHttpPattern", ".google.api.HttpRule", ".google.api.Http", ], ) self.assertEqual( [ enum_name for enum_name in self._FILE_SET.global_enums_map.keys() if enum_name.startswith(".example.v1alpha") ], [ ".example.v1alpha.Enum1", ".example.v1alpha.FooRequest.NestedEnum", ], ) # Check the used messages map. used_messages_name = [ ".example.v1alpha.FooRequest", ".example.v1alpha.FooResponse", ".google.longrunning.Operation", ".example.v1alpha.FooMetadata", ".example.v1alpha.MapMessage", ".google.rpc.Status", ] self.assertTrue( set(self._FILE_SET.messages_map.keys()) <= set( self._FILE_SET.global_messages_map.keys())) self.assertEqual(list(self._FILE_SET.messages_map.keys()), used_messages_name) self.assertEqual(list(self._FILE_SET.enums_map.keys()), [".example.v1alpha.Enum1"]) def test_service_wrapper(self): service = self._FILE_SET.services_map["Example"] # Service `Example` is defined at Line20 in .proto file. self.assertEqual(service.source_code_line, 20) self.assertEqual(service.api_version, "v1alpha") self.assertEqual(service.proto_file_name, "wrappers.proto") self.assertEqual(len(service.oauth_scopes), 1) self.assertEqual( service.oauth_scopes[0].value, "https://www.googleapis.com/auth/cloud-platform", ) self.assertEqual(service.oauth_scopes[0].source_code_line, 21) foo_method = service.methods["Foo"] bar_method = service.methods["Bar"] self.assertEqual(foo_method.input.value, ".example.v1alpha.FooRequest") self.assertEqual(foo_method.output.value, ".example.v1alpha.FooResponse") self.assertEqual(foo_method.paged_result_field, None) self.assertEqual(foo_method.method_signatures.value, ["content", "error"]) self.assertEqual(foo_method.http_annotation.value["http_uri"], "/v1/example:foo") # Method `Foo` is defined at Line23 in .proto file. self.assertEqual(foo_method.source_code_line, 23) self.assertEqual(foo_method.proto_file_name, "wrappers.proto") self.assertEqual(bar_method.input.value, ".example.v1alpha.FooRequest") self.assertEqual(bar_method.output.value, ".google.longrunning.Operation") self.assertEqual(bar_method.paged_result_field, None) self.assertTrue(bar_method.longrunning) self.assertEqual(bar_method.lro_annotation.value["response_type"], "FooResponse") self.assertEqual(bar_method.lro_annotation.value["metadata_type"], "FooMetadata") self.assertEqual(bar_method.http_annotation.value["http_uri"], "/v1/example:bar") # Method `Bar` is defined at Line31 in .proto file. self.assertEqual(bar_method.source_code_line, 31) def test_message_wrapper(self): messages_map = self._FILE_SET.messages_map foo_request_message = messages_map[".example.v1alpha.FooRequest"] # Message `FooRequest` is defined at Line43 in .proto file. self.assertEqual(foo_request_message.source_code_line, 43) self.assertEqual(foo_request_message.api_version, "v1alpha") self.assertTrue(foo_request_message.nested_messages["NestedMessage"]) self.assertEqual(foo_request_message.proto_file_name, "wrappers.proto") self.assertEqual(list(foo_request_message.oneofs.keys()), ["response"]) # Nested message `NestedMessage` is defined at Line52 in .proto file. self.assertEqual( foo_request_message.nested_messages["NestedMessage"]. source_code_line, 52) self.assertTrue(foo_request_message.nested_enums["NestedEnum"]) # Nested enum `NestedEnum` is defined at Line53 in .proto file. self.assertEqual( foo_request_message.nested_enums["NestedEnum"].source_code_line, 53) resource = foo_request_message.resource self.assertEqual(resource.value.pattern, ["foo/{foo}/bar/{bar}"]) self.assertEqual(resource.value.type, "example.googleapis.com/Foo") # The message has auto-generated map entries (nested type) for fields that is map type. map_message = messages_map[".example.v1alpha.MapMessage"] self.assertEqual(len(map_message.fields.keys()), 1) self.assertEqual(map_message.fields[1].name, "first_field") self.assertEqual(list(map_message.map_entries.keys()), ["FirstFieldEntry"]) self.assertTrue( isinstance(map_message.map_entries["FirstFieldEntry"]["key"], Field)) self.assertTrue( isinstance(map_message.map_entries["FirstFieldEntry"]["value"], Field)) # It should not put into the nested message, so the nested message map is empty. self.assertFalse(map_message.nested_messages) def test_field_wrapper(self): foo_request_message = self._FILE_SET.messages_map[ ".example.v1alpha.FooRequest"] # Oneof field `content` and `error` are defined at Line49,50 in .proto file. content_field_oneof = foo_request_message.fields[1] error_field_oneof = foo_request_message.fields[2] self.assertEqual(content_field_oneof.oneof_name, "response") self.assertEqual(error_field_oneof.oneof_name, "response") self.assertFalse(content_field_oneof.map_entry_type) self.assertEqual(content_field_oneof.source_code_line, 49) self.assertEqual(error_field_oneof.source_code_line, 50) foo_response_message = self._FILE_SET.messages_map[ ".example.v1alpha.FooResponse"] enum_field = foo_response_message.fields[1] self.assertEqual(enum_field.api_version, "v1alpha") self.assertFalse(enum_field.repeated.value) self.assertFalse(enum_field.required.value) self.assertEqual(enum_field.proto_type.value, "enum") self.assertEqual(enum_field.type_name.value, ".example.v1alpha.Enum1") self.assertEqual(enum_field.is_primitive_type, False) self.assertEqual(enum_field.oneof, False) self.assertEqual(enum_field.child_type, True) self.assertEqual(enum_field.resource_reference.value.child_type, "example.googleapis.com/t1") # Enum `enum_field` is defined at Line58 in .proto file. self.assertEqual(enum_field.source_code_line, 59) self.assertEqual(enum_field.proto_file_name, "wrappers.proto") foo_metadata_message = self._FILE_SET.messages_map[ ".example.v1alpha.FooMetadata"] # Field `name` has `google.api.field_behavior` option as `required`. name_field = foo_metadata_message.fields[1] self.assertEqual(name_field.name, "name") self.assertFalse(name_field.repeated.value) self.assertTrue(name_field.required.value) map_field = self._FILE_SET.messages_map[ ".example.v1alpha.MapMessage"].fields[1] self.assertTrue(map_field.map_entry) self.assertTrue(map_field.is_map_type) self.assertEqual(map_field.map_entry_type["key"], "string") self.assertEqual(map_field.map_entry_type["value"], ".example.v1alpha.FooMetadata") def test_enum_wrapper(self): enum = self._FILE_SET.enums_map[".example.v1alpha.Enum1"] self.assertEqual(enum.values[0].name, "a") self.assertEqual(enum.values[1].name, "b") # EnumValue `a` and `b` are defined at Line71 in .proto file. self.assertEqual(enum.values[0].source_code_line, 71) self.assertEqual(enum.values[1].source_code_line, 72) self.assertEqual(enum.values[0].proto_file_name, "wrappers.proto")
def setUp(self): # Get `MOBILE` and `HOME` enumValueDescriptorProto from `message_v1_descriptor_set.pb`. enum_type_values = (FileSet(self._PB_ORIGNAL).messages_map["Person"]. nested_enums["PhoneType"].values) self.enumValue_mobile = enum_type_values[0] self.enumValue_home = enum_type_values[1]
def setUp(self): self.person_fields_v1 = FileSet( self._PB_ORIGNAL).messages_map["Person"].fields self.person_fields_v1beta1 = (FileSet( self._PB_UPDATE).messages_map["Person"].fields)
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)
class WrappersTest(unittest.TestCase): # This is for tesing the behavior of classes in src.comparator.wrapper. # UnittestInvoker helps us to execute the protoc command to compile the proto file, # get a *_descriptor_set.pb file (by -o option) which contains the serialized data in protos, and # create a FileDescriptorSet out of it. _INVOKER = UnittestInvoker(["wrappers.proto"], "wrappers_descriptor_set.pb", True) _FILE_SET = FileSet(_INVOKER.run()) def test_file_set_wrapper(self): self.assertTrue(self._FILE_SET.messages_map) self.assertTrue(self._FILE_SET.enums_map) self.assertTrue(self._FILE_SET.services_map) resources_database = self._FILE_SET.resources_database self.assertEqual( resources_database.types["example.googleapis.com/t1"].pattern, ["foo/{foo}", "foo/{foo}/bar/{bar}/t1"], ) def test_service_wrapper(self): service = self._FILE_SET.services_map["Example"] # Service `Example` is defined at Line19 in .proto file. self.assertEqual(service.source_code_line, 19) self.assertEqual(service.proto_file_name, "wrappers.proto") foo_method = service.methods["Foo"] bar_method = service.methods["Bar"] self.assertEqual(foo_method.input.value, "FooRequest") self.assertEqual(foo_method.output.value, "FooResponse") self.assertEqual(foo_method.paged_result_field, None) self.assertEqual(foo_method.method_signatures.value, ["content", "error"]) self.assertEqual(foo_method.http_annotation.value["http_uri"], "/v1/example:foo") # Method `Foo` is defined at Line21 in .proto file. self.assertEqual(foo_method.source_code_line, 21) self.assertEqual(foo_method.proto_file_name, "wrappers.proto") self.assertEqual(bar_method.input.value, "FooRequest") self.assertEqual(bar_method.output.value, ".google.longrunning.Operation") self.assertEqual(bar_method.paged_result_field, None) self.assertTrue(bar_method.longrunning) self.assertEqual(bar_method.lro_annotation.value["response_type"], "FooResponse") self.assertEqual(bar_method.lro_annotation.value["metadata_type"], "FooMetadata") self.assertEqual(bar_method.http_annotation.value["http_uri"], "/v1/example:bar") # Method `Bar` is defined at Line29 in .proto file. self.assertEqual(bar_method.source_code_line, 29) def test_message_wrapper(self): messages_map = self._FILE_SET.messages_map foo_request_message = messages_map["FooRequest"] # Message `FooRequest` is defined at Line41 in .proto file. self.assertEqual(foo_request_message.source_code_line, 41) self.assertTrue(foo_request_message.nested_messages["NestedMessage"]) self.assertEqual(foo_request_message.proto_file_name, "wrappers.proto") # Nested message `NestedMessage` is defined at Line50 in .proto file. self.assertEqual( foo_request_message.nested_messages["NestedMessage"]. source_code_line, 50) self.assertTrue(foo_request_message.nested_enums["NestedEnum"]) # Nested enum `NestedEnum` is defined at Line51 in .proto file. self.assertEqual( foo_request_message.nested_enums["NestedEnum"].source_code_line, 51) self.assertEqual(foo_request_message.oneof_fields[0].name, "content") self.assertEqual(foo_request_message.oneof_fields[1].name, "error") # Oneof field `content` and `error` are defined at Line47,48 in .proto file. self.assertEqual(foo_request_message.oneof_fields[0].source_code_line, 47) self.assertEqual(foo_request_message.oneof_fields[1].source_code_line, 48) resource = foo_request_message.resource self.assertEqual(resource.pattern, ["foo/{foo}/bar/{bar}"]) self.assertEqual(resource.type, "example.googleapis.com/Foo") def test_field_wrapper(self): foo_response_message = self._FILE_SET.messages_map["FooResponse"] enum_field = foo_response_message.fields[1] self.assertEqual(enum_field.label, "LABEL_OPTIONAL") self.assertEqual(enum_field.required, False) self.assertEqual(enum_field.proto_type, "TYPE_ENUM") self.assertEqual(enum_field.oneof, False) self.assertEqual(enum_field.child_type, True) self.assertEqual(enum_field.resource_reference.child_type, "example.googleapis.com/t1") # Enum `enum_field` is defined at Line57 in .proto file. self.assertEqual(enum_field.source_code_line, 57) self.assertEqual(enum_field.proto_file_name, "wrappers.proto") def test_enum_wrapper(self): enum = self._FILE_SET.enums_map["Enum1"] self.assertEqual(enum.values[0].name, "a") self.assertEqual(enum.values[1].name, "b") # EnumValue `a` and `b` are defined at Line57 in .proto file. self.assertEqual(enum.values[0].source_code_line, 65) self.assertEqual(enum.values[1].source_code_line, 66) self.assertEqual(enum.values[0].proto_file_name, "wrappers.proto") @classmethod def tearDownClass(cls): cls._INVOKER.cleanup()