|
13 | 13 | # limitations under the License. |
14 | 14 |
|
15 | 15 | import json |
| 16 | +import os |
16 | 17 | from textwrap import dedent |
17 | 18 | from typing import Mapping |
18 | 19 | from unittest import mock |
19 | 20 |
|
20 | 21 | import jinja2 |
21 | 22 | import pytest |
22 | 23 |
|
23 | | -from google.api import service_pb2 |
| 24 | +from google.api import annotations_pb2 |
24 | 25 | from google.api import client_pb2 |
| 26 | +from google.api import http_pb2 |
| 27 | +from google.api import routing_pb2 |
| 28 | +from google.api import service_pb2 |
25 | 29 | from google.protobuf import descriptor_pb2 |
26 | 30 | from google.protobuf.compiler.plugin_pb2 import CodeGeneratorResponse |
27 | 31 |
|
@@ -912,6 +916,112 @@ def test_generator_duplicate_samples(fs): |
912 | 916 | generator.get_response(api_schema=api_schema, opts=Options.build("")) |
913 | 917 |
|
914 | 918 |
|
| 919 | +@pytest.mark.parametrize("use_ads_templates", (False, True)) |
| 920 | +@pytest.mark.parametrize("explicit_routing", (False, True)) |
| 921 | +@pytest.mark.parametrize("client_streaming", (False, True)) |
| 922 | +@pytest.mark.parametrize("server_streaming", (False, True)) |
| 923 | +def test_routing_headers_client_streaming( |
| 924 | + use_ads_templates: bool, |
| 925 | + explicit_routing: bool, |
| 926 | + client_streaming: bool, |
| 927 | + server_streaming: bool, |
| 928 | +): |
| 929 | + """Verify routing metadata is omitted for client-streaming RPCs and included otherwise.""" |
| 930 | + ads_templates_dir = os.path.abspath( |
| 931 | + os.path.join( |
| 932 | + os.path.dirname(__file__), "..", "..", "..", "gapic", "ads-templates" |
| 933 | + ) |
| 934 | + ) |
| 935 | + opts_str = ( |
| 936 | + f"autogen-snippets=false,python-gapic-templates={ads_templates_dir},old-naming" |
| 937 | + if use_ads_templates |
| 938 | + else "autogen-snippets=false" |
| 939 | + ) |
| 940 | + opts = Options.build(opts_str) |
| 941 | + generator_obj = generator.Generator(opts) |
| 942 | + |
| 943 | + method_options = descriptor_pb2.MethodOptions() |
| 944 | + method_options.Extensions[annotations_pb2.http].CopyFrom( |
| 945 | + http_pb2.HttpRule( |
| 946 | + post="/v1/{table_name=projects/*/tables/*}:someMethod", |
| 947 | + body="*", |
| 948 | + ) |
| 949 | + ) |
| 950 | + if explicit_routing: |
| 951 | + method_options.Extensions[routing_pb2.routing].CopyFrom( |
| 952 | + routing_pb2.RoutingRule( |
| 953 | + routing_parameters=[ |
| 954 | + routing_pb2.RoutingParameter( |
| 955 | + field="table_name", |
| 956 | + path_template="{table_name=projects/*/tables/*}", |
| 957 | + ) |
| 958 | + ] |
| 959 | + ) |
| 960 | + ) |
| 961 | + |
| 962 | + file_pb = descriptor_pb2.FileDescriptorProto( |
| 963 | + name="some_service.proto", |
| 964 | + package="google.cloud.hatstand.v1", |
| 965 | + message_type=[ |
| 966 | + descriptor_pb2.DescriptorProto( |
| 967 | + name="SomeRequest", |
| 968 | + field=[ |
| 969 | + descriptor_pb2.FieldDescriptorProto( |
| 970 | + name="table_name", |
| 971 | + number=1, |
| 972 | + type=descriptor_pb2.FieldDescriptorProto.Type.Value( |
| 973 | + "TYPE_STRING" |
| 974 | + ), |
| 975 | + ) |
| 976 | + ], |
| 977 | + ), |
| 978 | + descriptor_pb2.DescriptorProto(name="SomeResponse"), |
| 979 | + ], |
| 980 | + service=[ |
| 981 | + descriptor_pb2.ServiceDescriptorProto( |
| 982 | + name="SomeService", |
| 983 | + method=[ |
| 984 | + descriptor_pb2.MethodDescriptorProto( |
| 985 | + name="SomeMethod", |
| 986 | + input_type=".google.cloud.hatstand.v1.SomeRequest", |
| 987 | + output_type=".google.cloud.hatstand.v1.SomeResponse", |
| 988 | + client_streaming=client_streaming, |
| 989 | + server_streaming=server_streaming, |
| 990 | + options=method_options, |
| 991 | + ) |
| 992 | + ], |
| 993 | + ) |
| 994 | + ], |
| 995 | + ) |
| 996 | + api_schema = api.API.build([file_pb], package="google.cloud.hatstand.v1", opts=opts) |
| 997 | + |
| 998 | + cgr = generator_obj.get_response(api_schema=api_schema, opts=opts) |
| 999 | + files_by_name = {f.name: f.content for f in cgr.file} |
| 1000 | + |
| 1001 | + client_files = [ |
| 1002 | + content |
| 1003 | + for name, content in files_by_name.items() |
| 1004 | + if name.endswith("/services/some_service/client.py") |
| 1005 | + or name.endswith("/services/some_service/async_client.py") |
| 1006 | + ] |
| 1007 | + assert len(client_files) == (1 if use_ads_templates else 2) |
| 1008 | + |
| 1009 | + for content in client_files: |
| 1010 | + if client_streaming: |
| 1011 | + assert "gapic_v1.routing_header.to_grpc_metadata" not in content |
| 1012 | + assert "header_params" not in content |
| 1013 | + else: |
| 1014 | + assert "gapic_v1.routing_header.to_grpc_metadata" in content |
| 1015 | + if explicit_routing and not use_ads_templates: |
| 1016 | + assert "header_params: dict[str, str] = {}" in content |
| 1017 | + assert ( |
| 1018 | + "gapic_v1.routing_header.to_grpc_metadata(header_params)" in content |
| 1019 | + ) |
| 1020 | + else: |
| 1021 | + assert "header_params" not in content |
| 1022 | + assert '("table_name", request.table_name)' in content |
| 1023 | + |
| 1024 | + |
915 | 1025 | def make_generator(opts_str: str = "") -> generator.Generator: |
916 | 1026 | return generator.Generator(Options.build(opts_str)) |
917 | 1027 |
|
|
0 commit comments