def test_method_include_flattened_message_fields(): a = make_field('a', type=5) b = make_field('b', type=11, type_name='Eggs', message=make_message('Eggs')) input_msg = make_message('Z', fields=(a, b)) method = make_method('F', input_message=input_msg, signatures=('a,b',)) assert len(method.flattened_fields) == 2
def test_method_http_options_generate_sample_implicit_template(): http_rule = http_pb2.HttpRule( get='/v1/{resource.id}/stuff', ) method = make_method( 'DoSomething', make_message( name="Input", fields=[ make_field( name="resource", number=1, message=make_message( "Resource", fields=[ make_field(name="id", type=9), ], ), ), ], ), http_rule=http_rule, ) sample = method.http_options[0].sample_request(method) assert sample == {'resource': { 'id': 'sample1'}}
def test_method_paged_result_ref_types(): input_msg = make_message( name='ListSquidsRequest', fields=( make_field(name='parent', type=9), # str make_field(name='page_size', type=5), # int make_field(name='page_token', type=9), # str ), module='squid', ) mollusc_msg = make_message('Mollusc', module='mollusc') output_msg = make_message(name='ListMolluscsResponse', fields=(make_field(name='molluscs', message=mollusc_msg, repeated=True), make_field(name='next_page_token', type=9)), module='mollusc') method = make_method('ListSquids', input_message=input_msg, output_message=output_msg, module='squid') ref_type_names = {t.name for t in method.ref_types} assert ref_type_names == { 'ListSquidsRequest', 'ListSquidsPager', 'ListSquidsAsyncPager', 'Mollusc', }
def test_mock_value_original_type_enum(): mollusc_field = make_field( name="class", enum=make_enum( name="Class", values=[ ("UNKNOWN", 0), ("GASTROPOD", 1), ("BIVALVE", 2), ("CEPHALOPOD", 3), ], ), ) assert mollusc_field.mock_value_original_type == 1 empty_field = make_field( name="empty", enum=make_enum( name="Empty", values=[("UNKNOWN", 0)], ), ) assert empty_field.mock_value_original_type == 0
def test_method_http_options_generate_sample(): http_rule = http_pb2.HttpRule( get='/v1/{resource.id=projects/*/regions/*/id/**}/stuff', ) method = make_method( 'DoSomething', make_message( name="Input", fields=[ make_field( name="resource", number=1, type=11, message=make_message( "Resource", fields=[ make_field(name="id", type=9), ], ), ), ], ), http_rule=http_rule, ) sample = method.http_options[0].sample_request(method) assert sample == { 'resource': { 'id': 'projects/sample1/regions/sample2/id/sample3' } }
def test_required_fields(): REQUIRED = field_behavior_pb2.FieldBehavior.Value('REQUIRED') mass_kg = make_field(name="mass_kg", type=5) mass_kg.options.Extensions[field_behavior_pb2.field_behavior].append( REQUIRED) length_m = make_field(name="length_m", type=5) length_m.options.Extensions[field_behavior_pb2.field_behavior].append( REQUIRED) color = make_field(name="color", type=5) color.options.Extensions[field_behavior_pb2.field_behavior].append( REQUIRED) request = make_message( name="CreateMolluscReuqest", fields=( mass_kg, length_m, color, ), ) assert set(request.required_fields) == {mass_kg, length_m, color}
def test_method_flattened_fields_different_package_non_primitive(): # This test verifies that method flattening handles a special case where: # * the method's request message type lives in a different package and # * a field in the method_signature is a non-primitive. # # If the message is defined in a different package it is not guaranteed to # be a proto-plus wrapped type, which puts restrictions on assigning # directly to its fields, which complicates request construction. # The easiest solution in this case is to just prohibit these fields # in the method flattening. message = make_message('Mantle', package="mollusc.cephalopod.v1", module="squid") mantle = make_field('mantle', type=11, type_name='Mantle', message=message, meta=message.meta) arms_count = make_field('arms_count', type=5, meta=message.meta) input_message = make_message('Squid', fields=(mantle, arms_count), package=".".join( message.meta.address.package), module=message.meta.address.module) method = make_method('PutSquid', input_message=input_message, package="remote.package.v1", module="module", signatures=("mantle,arms_count", )) assert set(method.flattened_fields) == {'arms_count'}
def test_operation_polling_method(): T = descriptor_pb2.FieldDescriptorProto.Type operation = make_message( name="Operation", fields=(make_field( name=name, type=T.Value("TYPE_STRING"), number=i) for i, name in enumerate( ("name", "status", "error_code", "error_message"), start=1)), ) for f in operation.field: options = descriptor_pb2.FieldOptions() # Note: The field numbers were carefully chosen to be the corresponding enum values. options.Extensions[ex_ops_pb2.operation_field] = f.number f.options.MergeFrom(options) request = make_message( name="GetOperation", fields=[ make_field(name="name", type=T.Value("TYPE_STRING"), number=1) ], ) options = descriptor_pb2.MethodOptions() options.Extensions[ex_ops_pb2.operation_polling_method] = True polling_method = make_method( name="Get", input_message=request, output_message=operation, options=options, ) # Even though polling_method returns an Operation, it isn't an LRO ops_service = make_service( name="CustomOperations", methods=[ polling_method, make_method( name="Delete", input_message=make_message(name="Input"), output_message=make_message("Output"), ), ], ) assert ops_service.custom_polling_method == polling_method # Methods are LROs, so they are not polling methods user_service = make_service( name="ComputationStarter", methods=[ make_method( name="Start", input_message=make_message(name="StartRequest"), output_message=operation, ), ], ) assert not user_service.custom_polling_method
def test_has_pagers(): paged = make_field(name='foos', message=make_message('Foo'), repeated=True) input_msg = make_message( name='ListFoosRequest', fields=( make_field(name='parent', type=9), # str make_field(name='page_size', type=5), # int make_field(name='page_token', type=9), # str ), ) output_msg = make_message( name='ListFoosResponse', fields=( paged, make_field(name='next_page_token', type=9), # str ), ) method = make_method( 'ListFoos', input_message=input_msg, output_message=output_msg, ) service = make_service( name="Fooer", methods=(method, ), ) assert service.has_pagers other_service = make_service( name="Unfooer", methods=(get_method("Unfoo", "foo.bar.UnfooReq", "foo.bar.UnFooResp"), ), ) assert not other_service.has_pagers
def test_field_types_recursive(): enumeration = make_enum('Enumeration') innest_msg = make_message( 'InnestMessage', fields=( make_field('enumeration', enum=enumeration), ) ) inner_msg = make_message( 'InnerMessage', fields=( make_field('innest_message', message=innest_msg), ) ) topmost_msg = make_message( 'TopmostMessage', fields=( make_field('inner_message', message=inner_msg), make_field('uninteresting') ) ) actual = {t.name for t in topmost_msg.recursive_field_types} expected = {t.name for t in (enumeration, innest_msg, inner_msg)} assert actual == expected
def test_field_types(): # Create the inner message. inner_msg = make_message( 'InnerMessage', fields=( make_field( 'hidden_message', message=make_message('HiddenMessage'), ), ) ) inner_enum = make_enum('InnerEnum') # Create the outer message, which contains an Inner as a field. fields = ( make_field('inner_message', message=inner_msg), make_field('inner_enum', enum=inner_enum), make_field('not_interesting'), ) outer = make_message('Outer', fields=fields) # Assert that composite field types are recognized but primitives are not. assert len(outer.field_types) == 2 assert inner_msg in outer.field_types assert inner_enum in outer.field_types
def test_is_msg_field_pb(): msg_field = make_field('msg_field', message=make_message('test_msg')) str_field = make_field('str_field', type=9) int_field = make_field('int_field', type=5) assert checks.is_msg_field_pb(msg_field.field_pb) assert not checks.is_msg_field_pb(str_field.field_pb) assert not checks.is_msg_field_pb(int_field.field_pb)
def test_method_flattened_fields(): a = make_field('a', type=5) # int b = make_field('b', type=5) input_msg = make_message('Z', fields=(a, b)) method = make_method('F', input_message=input_msg, signatures=('a,b', )) assert len(method.flattened_fields) == 2 assert 'a' in method.flattened_fields assert 'b' in method.flattened_fields
def test_is_operation_polling_method(): T = descriptor_pb2.FieldDescriptorProto.Type operation = make_message( name="Operation", fields=[ make_field(name=name, type=T.Value("TYPE_STRING"), number=i) for i, name in enumerate( ("name", "status", "error_code", "error_message"), start=1) ], ) for f in operation.fields.values(): options = descriptor_pb2.FieldOptions() # Note: The field numbers were carefully chosen to be the corresponding enum values. options.Extensions[ex_ops_pb2.operation_field] = f.number f.options.MergeFrom(options) request = make_message( name="GetOperation", fields=[ make_field(name="name", type=T.Value("TYPE_STRING"), number=1) ], ) # Correct positive options = descriptor_pb2.MethodOptions() options.Extensions[ex_ops_pb2.operation_polling_method] = True polling_method = make_method( name="Get", input_message=request, output_message=operation, options=options, ) assert polling_method.is_operation_polling_method # Normal method that returns operation normal_method = make_method( name="Get", input_message=request, output_message=operation, ) assert not normal_method.is_operation_polling_method # Method with invalid options combination response = make_message(name="Response", fields=[make_field(name="name")]) invalid_method = make_method( name="Get", input_message=request, output_message=response, options=options, # Reuse options from the actual polling method ) assert not invalid_method.is_operation_polling_method
def test_method_query_params(): # tests only the basic case of grpc transcoding http_rule = http_pb2.HttpRule(post='/v1/{project}/topics', body='address') input_message = make_message('MethodInput', fields=(make_field('region'), make_field('project'), make_field('address'))) method = make_method('DoSomething', http_rule=http_rule, input_message=input_message) assert method.query_params == {'region'}
def test_get_field_recursive(): # Create the inner message. inner_fields = (make_field('zero'), make_field('one')) inner = make_message('Inner', fields=inner_fields, package='foo.v1') # Create the outer message, which contains an Inner as a field. outer_field = make_field('inner', message=inner) outer = make_message('Outer', fields=(outer_field, )) # Assert that a recusive retrieval works. assert outer.get_field('inner', 'zero') == inner_fields[0] assert outer.get_field('inner', 'one') == inner_fields[1]
def test_field_name_kword_disambiguation(): from_field = make_field(name="from", ) assert from_field.name == "from_" frum_field = make_field(name="frum", ) assert frum_field.name == "frum" mapping_field = make_field(name="mapping") assert mapping_field.name == "mapping_" ignore_field = make_field(name="ignore_unknown_fields") assert ignore_field.name == "ignore_unknown_fields_"
def test_get_field_nested_not_found_error(): # Create the inner message. inner_field = make_field('zero') inner = make_message('Inner', fields=(inner_field, ), package='foo.v1') # Create the outer message, which contains an Inner as a field. outer_field = make_field('inner', message=inner) outer = make_message('Outer', fields=(outer_field, )) # Assert that a recusive retrieval fails. with pytest.raises(KeyError): assert outer.get_field('inner', 'zero', 'beyond')
def test_field_map(): # Create an Entry message. entry_msg = make_message( name='FooEntry', fields=( make_field(name='key', type=9), make_field(name='value', type=9), ), options=descriptor_pb2.MessageOptions(map_entry=True), ) entry_field = make_field('foos', message=entry_msg, repeated=True) assert entry_msg.map assert entry_field.map
def test_get_field_nonterminal_repeated_error(): # Create the inner message. inner_fields = (make_field('zero'), make_field('one')) inner = make_message('Inner', fields=inner_fields, package='foo.v1') # Create the outer message, which contains an Inner as a field. outer_field = make_field('inner', message=inner, repeated=True) outer = make_message('Outer', fields=(outer_field, )) # Assert that a recusive retrieval fails. with pytest.raises(KeyError): assert outer.get_field('inner', 'zero') == inner_fields[0] with pytest.raises(KeyError): assert outer.get_field('inner', 'one') == inner_fields[1]
def test_body_fields(): http_rule = http_pb2.HttpRule(post='/v1/{arms_shape=arms/*}/squids', body='mantle') mantle_stuff = make_field(name='mantle_stuff', type=9) message = make_message('Mantle', fields=(mantle_stuff, )) mantle = make_field('mantle', type=11, type_name='Mantle', message=message) arms_shape = make_field('arms_shape', type=9) input_message = make_message('Squid', fields=(mantle, arms_shape)) method = make_method('PutSquid', input_message=input_message, http_rule=http_rule) assert set(method.body_fields) == {'mantle'} mock_value = method.body_fields['mantle'].mock_value assert mock_value == "baz.Mantle(mantle_stuff='mantle_stuff_value')"
def test_resource_reference(): field = make_field(type='TYPE_STRING') field.options.Extensions[ resource_pb2. resource_reference].type = "translate.googleapis.com/Glossary" assert field.resource_reference == "translate.googleapis.com/Glossary"
def test_differently_named_extended_operation_fields( all_field_names, canonical_name_to_field_name, ): T = descriptor_pb2.FieldDescriptorProto.Type operation = make_message( name="Operation", fields=[ make_field( name=name.lower(), type=T.Value("TYPE_STRING"), number=i, ) for i, name in enumerate(all_field_names, start=1) ]) for f in operation.fields.values(): options = descriptor_pb2.FieldOptions() options.Extensions[ex_ops_pb2.operation_field] = f.number f.options.MergeFrom(options) expected = { k: operation.fields[v] for k, v in canonical_name_to_field_name.items() } if canonical_name_to_field_name is not None else None actual = operation.differently_named_extended_operation_fields assert expected == actual
def test_method_paged_result_field_not_first(): paged = make_field(name='foos', message=make_message('Foo'), repeated=True) input_msg = make_message(name='ListFoosRequest', fields=( make_field(name='parent', type=9), # str make_field(name='page_size', type=5), # int make_field(name='page_token', type=9), # str )) output_msg = make_message(name='ListFoosResponse', fields=( make_field(name='next_page_token', type=9), # str paged, )) method = make_method('ListFoos', input_message=input_msg, output_message=output_msg, ) assert method.paged_result_field == paged
def test_resource_response(): # Top level response resource squid_resource = make_message("Squid", options=make_resource_opts("squid")) squid_request = make_message("CreateSquidRequest") # Nested response resource clam_resource = make_message("Clam", options=make_resource_opts("clam")) clam_response = make_message( "CreateClamResponse", fields=(make_field('clam', message=clam_resource), ), ) clam_request = make_message("CreateClamRequest") mollusc_service = make_service( "MolluscService", methods=(make_method(f"{request.name}", request, response) for request, response in ( (squid_request, squid_resource), (clam_request, clam_response), )), ) expected = {squid_resource, clam_resource} actual = mollusc_service.resource_messages assert expected == actual
def test_mock_value_map(): entry_msg = make_message( name='SquidEntry', fields=( make_field(name='key', type='TYPE_STRING'), make_field(name='value', type='TYPE_STRING'), ), options=descriptor_pb2.MessageOptions(map_entry=True), ) field = make_field( name='squids', type_name='mollusc.SquidEntry', message=entry_msg, label=3, type='TYPE_MESSAGE', ) assert field.mock_value == "{'key_value': 'value_value'}"
def test_ident_sphinx_map(): entry_msg = make_message( name='SquidEntry', fields=( make_field(name='key', type='TYPE_STRING'), make_field(name='value', type='TYPE_STRING'), ), options=descriptor_pb2.MessageOptions(map_entry=True), ) field = make_field( name='squids', type_name='mollusc.SquidEntry', message=entry_msg, label=3, type='TYPE_MESSAGE', ) assert field.ident.sphinx == 'Mapping[str, str]'
def test_extended_operation_properties(): options = descriptor_pb2.FieldOptions() options.Extensions[ex_ops_pb2.operation_request_field] = "squid" options.Extensions[ex_ops_pb2.operation_response_field] = "clam" f = make_field(options=options) assert f.operation_request_field == "squid" assert f.operation_response_field == "clam"
def test_method_paged_result_field_no_page_field(): input_msg = make_message( name='ListFoosRequest', fields=( make_field(name='parent', type=9), # str make_field(name='page_size', type=5), # int make_field(name='page_token', type=9), # str )) output_msg = make_message( name='ListFoosResponse', fields=( make_field(name='foos', message=make_message('Foo'), repeated=False), make_field(name='next_page_token', type=9), # str )) method = make_method( 'ListFoos', input_message=input_msg, output_message=output_msg, ) assert method.paged_result_field is None method = make_method( name='Foo', input_message=make_message( name='FooRequest', fields=(make_field(name='page_token', type=9), ) # str ), output_message=make_message( name='FooResponse', fields=(make_field(name='next_page_token', type=9), ) # str )) assert method.paged_result_field is None
def test_flattened_ref_types(): method = make_method( 'IdentifyMollusc', input_message=make_message( 'IdentifyMolluscRequest', fields=( make_field( 'cephalopod', message=make_message( 'Cephalopod', fields=( make_field('mass_kg', type='TYPE_INT32'), make_field( 'squid', number=2, message=make_message('Squid'), ), make_field( 'clam', number=3, message=make_message('Clam'), ), ), ), ), make_field( 'stratum', enum=make_enum( 'Stratum', ) ), ), ), signatures=('cephalopod.squid,stratum',), output_message=make_message('Mollusc'), ) expected_flat_ref_type_names = { 'IdentifyMolluscRequest', 'Squid', 'Stratum', 'Mollusc', } actual_flat_ref_type_names = {t.name for t in method.flat_ref_types} assert expected_flat_ref_type_names == actual_flat_ref_type_names