예제 #1
0
def test_lro():
    # Set up a prior proto that mimics google/protobuf/empty.proto
    lro_proto = api.Proto.build(make_file_pb2(
        name='operations.proto',
        package='google.longrunning',
        messages=(make_message_pb2(name='Operation'), ),
    ),
                                file_to_generate=False,
                                naming=make_naming())

    # Set up a method with LRO annotations.
    method_pb2 = descriptor_pb2.MethodDescriptorProto(
        name='AsyncDoThing',
        input_type='google.example.v3.AsyncDoThingRequest',
        output_type='google.longrunning.Operation',
    )
    method_pb2.options.Extensions[operations_pb2.operation_info].MergeFrom(
        operations_pb2.OperationInfo(
            response_type='google.example.v3.AsyncDoThingResponse',
            metadata_type='google.example.v3.AsyncDoThingMetadata',
        ), )

    # Set up the service with an RPC.
    service_pb = descriptor_pb2.ServiceDescriptorProto(
        name='LongRunningService',
        method=(method_pb2, ),
    )

    # Set up the messages, including the annotated ones.
    messages = (
        make_message_pb2(name='AsyncDoThingRequest', fields=()),
        make_message_pb2(name='AsyncDoThingResponse', fields=()),
        make_message_pb2(name='AsyncDoThingMetadata', fields=()),
    )

    # Finally, set up the file that encompasses these.
    fdp = make_file_pb2(
        package='google.example.v3',
        messages=messages,
        services=(service_pb, ),
    )

    # Make the proto object.
    proto = api.Proto.build(fdp,
                            file_to_generate=True,
                            prior_protos={
                                'google/longrunning/operations.proto':
                                lro_proto,
                            },
                            naming=make_naming())

    # Establish that our data looks correct.
    assert len(proto.services) == 1
    assert len(proto.messages) == 3
    assert len(lro_proto.messages) == 1
예제 #2
0
def test_cross_file_lro():
    # Protobuf annotations for longrunning operations use strings to name types.
    # As far as the protobuf compiler is concerned they don't reference the
    # _types_ at all, so the corresponding proto file that owns the types
    # does not need to be imported.
    # This creates a potential issue when building rich structures around
    # LRO returning methods. This test is intended to verify that the issue
    # is handled correctly.

    # Set up a prior proto that mimics google/protobuf/empty.proto
    lro_proto = api.Proto.build(make_file_pb2(
        name='operations.proto',
        package='google.longrunning',
        messages=(make_message_pb2(name='Operation'), ),
    ),
                                file_to_generate=False,
                                naming=make_naming())

    # Set up a method with LRO annotations.
    method_pb2 = descriptor_pb2.MethodDescriptorProto(
        name='AsyncDoThing',
        input_type='google.example.v3.AsyncDoThingRequest',
        output_type='google.longrunning.Operation',
    )
    method_pb2.options.Extensions[operations_pb2.operation_info].MergeFrom(
        operations_pb2.OperationInfo(
            response_type='google.example.v3.AsyncDoThingResponse',
            metadata_type='google.example.v3.AsyncDoThingMetadata',
        ), )

    # Set up the service with an RPC.
    service_file = make_file_pb2(
        name='service_file.proto',
        package='google.example.v3',
        messages=(make_message_pb2(name='AsyncDoThingRequest', fields=()), ),
        services=(descriptor_pb2.ServiceDescriptorProto(
            name='LongRunningService',
            method=(method_pb2, ),
        ), ))

    # Set up the messages, including the annotated ones.
    # This file is distinct and is not explicitly imported
    # into the file that defines the service.
    messages_file = make_file_pb2(
        name='messages_file.proto',
        package='google.example.v3',
        messages=(
            make_message_pb2(name='AsyncDoThingResponse', fields=()),
            make_message_pb2(name='AsyncDoThingMetadata', fields=()),
        ),
    )

    api_schema = api.API.build(
        file_descriptors=(
            service_file,
            messages_file,
        ),
        package='google.example.v3',
        prior_protos={
            'google/longrunning/operations.proto': lro_proto,
        },
    )

    method = (api_schema.all_protos['service_file.proto'].services[
        'google.example.v3.LongRunningService'].methods['AsyncDoThing'])

    assert method.lro
    assert method.lro.response_type.name == 'AsyncDoThingResponse'
    assert method.lro.metadata_type.name == 'AsyncDoThingMetadata'
예제 #3
0
def test_proto_names_import_collision_flattening():
    lro_proto = api.Proto.build(make_file_pb2(
        name='operations.proto',
        package='google.longrunning',
        messages=(make_message_pb2(name='Operation'), ),
    ),
                                file_to_generate=False,
                                naming=make_naming())

    fd = (
        make_file_pb2(
            name='mollusc.proto',
            package='google.animalia.mollusca',
            messages=(
                make_message_pb2(name='Mollusc', ),
                make_message_pb2(name='MolluscResponse', ),
                make_message_pb2(name='MolluscMetadata', ),
            ),
        ),
        make_file_pb2(
            name='squid.proto',
            package='google.animalia.mollusca',
            messages=(
                make_message_pb2(
                    name='IdentifySquidRequest',
                    fields=(make_field_pb2(
                        name='mollusc',
                        number=1,
                        type_name='.google.animalia.mollusca.Mollusc'), ),
                ),
                make_message_pb2(
                    name='IdentifySquidResponse',
                    fields=(),
                ),
            ),
            services=(descriptor_pb2.ServiceDescriptorProto(
                name='SquidIdentificationService',
                method=(descriptor_pb2.MethodDescriptorProto(
                    name='IdentifyMollusc',
                    input_type='google.animalia.mollusca.IdentifySquidRequest',
                    output_type='google.longrunning.Operation',
                ), ),
            ), ),
        ),
    )

    method_options = fd[1].service[0].method[0].options
    # Notice that a signature field collides with the name of an imported module
    method_options.Extensions[client_pb2.method_signature].append('mollusc')
    method_options.Extensions[operations_pb2.operation_info].MergeFrom(
        operations_pb2.OperationInfo(
            response_type='google.animalia.mollusca.MolluscResponse',
            metadata_type='google.animalia.mollusca.MolluscMetadata',
        ))
    api_schema = api.API.build(fd,
                               package='google.animalia.mollusca',
                               prior_protos={
                                   'google/longrunning/operations.proto':
                                   lro_proto,
                               })

    actual_imports = {
        ref_type.ident.python_import
        for service in api_schema.services.values()
        for method in service.methods.values() for ref_type in method.ref_types
    }

    expected_imports = {
        imp.Import(
            package=('google', 'animalia', 'mollusca', 'types'),
            module='mollusc',
            alias='gam_mollusc',
        ),
        imp.Import(
            package=('google', 'animalia', 'mollusca', 'types'),
            module='squid',
        ),
        imp.Import(
            package=('google', 'api_core'),
            module='operation',
        ),
        imp.Import(
            package=('google', 'api_core'),
            module='operation_async',
        ),
    }

    assert expected_imports == actual_imports

    method = (api_schema.
              services['google.animalia.mollusca.SquidIdentificationService'].
              methods['IdentifyMollusc'])

    actual_response_import = method.lro.response_type.ident.python_import
    expected_response_import = imp.Import(
        package=('google', 'animalia', 'mollusca', 'types'),
        module='mollusc',
        alias='gam_mollusc',
    )
    assert actual_response_import == expected_response_import
def make_method(
        name: str,
        input_message: wrappers.Message = None,
        output_message: wrappers.Message = None,
        client_streaming: bool = False,
        server_streaming: bool = False,
        signatures: Sequence[str] = (),
        lro_response_type: str = None,
        lro_metadata_type: str = None,
        http_method: str = "get",
        http_uri: str = None,
        http_body: str = None,
        messages_map: Dict[str, wrappers.Message] = {},
        proto_file_name: str = "foo",
        locations: Sequence[desc.SourceCodeInfo.Location] = [],
        path: Tuple[int] = (),
        **kwargs,
) -> wrappers.Method:
    # Use default input and output messages if they are not provided.
    input_message = input_message or make_message("MethodInput")
    output_message = output_message or make_message("MethodOutput")

    method_pb = make_method_pb2(
        name=name,
        input_type=input_message.full_name,
        output_type=output_message.full_name,
        client_streaming=client_streaming,
        server_streaming=server_streaming,
        **kwargs,
    )

    # If there are signatures, include them.
    for sig in signatures:
        ext_key = client_pb2.method_signature
        method_pb.options.Extensions[ext_key].append(sig)

    # If there are LRO annotations, include them.
    if lro_response_type and lro_metadata_type:
        method_pb.options.Extensions[operations_pb2.operation_info].MergeFrom(
            operations_pb2.OperationInfo(
                response_type=lro_response_type,
                metadata_type=lro_metadata_type,
            ))
    # If there are HTTP annotations, include them.
    if http_method and http_uri and http_body:
        http_annotation = method_pb.options.Extensions[annotations_pb2.http]
        http_annotation.get = http_uri
        http_annotation.body = http_body

    source_code_locations = {
        tuple(location.path): location
        for location in locations
    }
    # Instantiate the wrapper class.
    return wrappers.Method(
        method_pb=method_pb,
        messages_map=messages_map,
        proto_file_name=proto_file_name,
        source_code_locations=source_code_locations,
        path=path,
    )