From 7fd029dbdf170451147b79111e831fc14903c1fd Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 12 Nov 2026 16:51:35 -0700 Subject: [PATCH 1/5] fix: include headers in lro operations --- .../%sub/services/%service/_mixins.py.j2 | 10 + .../%sub/services/%service/client.py.j2 | 11 + .../%name_%version/%sub/_test_mixins.py.j2 | 91 ++++++++ .../%name_%version/%sub/test_%service.py.j2 | 14 ++ .../services/%service/_async_mixins.py.j2 | 10 + .../%sub/services/%service/_client_macros.j2 | 8 + .../%sub/services/%service/_mixins.py.j2 | 10 + .../%sub/services/%service/async_client.py.j2 | 11 + .../%sub/services/%service/client.py.j2 | 3 + .../%name_%version/%sub/_test_mixins.py.j2 | 119 +++++++++++ .../%name_%version/%sub/test_%service.py.j2 | 18 ++ .../tests/fragments/test_api_version.proto | 15 ++ .../services/echo/async_client.py | 40 ++++ .../showcase_v1beta1/services/echo/client.py | 40 ++++ .../unit/gapic/showcase_v1beta1/test_echo.py | 100 ++++++++- .../tests/unit/generator/test_generator.py | 196 ++++++++++++++++++ 16 files changed, 695 insertions(+), 1 deletion(-) diff --git a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 index eb19c3c8bd07..f0dfb8328c72 100644 --- a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 @@ -44,6 +44,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -98,6 +99,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -155,6 +157,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. rpc(request_pb, retry=retry, timeout=timeout, metadata=metadata,) @@ -207,6 +210,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. rpc(request_pb, retry=retry, timeout=timeout, metadata=metadata,) @@ -257,6 +261,7 @@ rpc = self._transport._wrapped_methods[self._transport.wait_operation] metadata = tuple(metadata) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -381,6 +386,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -501,6 +507,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -559,6 +566,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -616,6 +624,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -669,6 +678,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( diff --git a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 index 33253567b5db..a7f982b1e03f 100644 --- a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 @@ -507,6 +507,11 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): metadata=metadata, ) {% if method.lro %} + {% if service.version %} + lro_metadata = None + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + lro_metadata = [version_header.to_api_version_header("{{ service.version }}")] + {% endif %} # Wrap the response in an operation future. response = {{ method.client_output.ident.module_alias or method.client_output.ident.module }}.from_gapic( @@ -514,6 +519,9 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): self._transport.operations_client, {{ method.lro.response_type.ident }}, metadata_type={{ method.lro.metadata_type.ident }}, + {% if service.version %} + grpc_metadata=lro_metadata, + {% endif %} ) {% elif method.paged_result_field %} @@ -653,6 +661,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -774,6 +783,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -834,6 +844,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( diff --git a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 index e19793749d66..6b259f12a714 100644 --- a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 @@ -113,6 +113,13 @@ def test_delete_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_delete_operation_from_dict(): client = {{ service.client_name }}( @@ -198,6 +205,13 @@ def test_cancel_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_cancel_operation_from_dict(): client = {{ service.client_name }}( @@ -283,6 +297,13 @@ def test_wait_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_wait_operation_from_dict(): client = {{ service.client_name }}( @@ -369,6 +390,13 @@ def test_get_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_get_operation_from_dict(): client = {{ service.client_name }}( @@ -454,6 +482,13 @@ def test_list_operations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_list_operations_from_dict(): @@ -544,6 +579,13 @@ def test_list_locations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_list_locations_from_dict(): client = {{ service.client_name }}( @@ -628,6 +670,13 @@ def test_get_location_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations/abc",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_get_location_from_dict(): client = {{ service.client_name }}( @@ -721,6 +770,13 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_set_iam_policy_from_dict(): client = {{ service.client_name }}( @@ -811,6 +867,13 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_get_iam_policy_from_dict(): @@ -907,6 +970,13 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_test_iam_permissions_from_dict(): @@ -1002,6 +1072,13 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_set_iam_policy_from_dict(): client = {{ service.client_name }}( @@ -1093,6 +1170,13 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_get_iam_policy_from_dict(): @@ -1190,6 +1274,13 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_test_iam_permissions_from_dict(): diff --git a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index 2b3c289a0595..795d47fa0267 100644 --- a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -665,7 +665,11 @@ def test_{{ method_name }}_api_version_header(transport_name): '__call__' ) as call: call.return_value = {{ method.output.ident }}() + {% if method.lro %} + response = client.{{ method_name }}() + {% else %} client.{{ method_name }}() + {% endif %} # Establish that the api version header was sent. _, _, kw = call.mock_calls[0] @@ -673,6 +677,16 @@ def test_{{ method_name }}_api_version_header(transport_name): version_header.API_VERSION_METADATA_KEY, "{{ service.version }}", ) in kw['metadata'] + {% if method.lro %} + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._refresh.keywords["metadata"] + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._cancel.keywords["metadata"] + {% endif %} else: pytest.skip("google-api-core>=2.19.0 is required for `google.api_core.version_header`") {% endif %}{# service.version #} diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_async_mixins.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_async_mixins.py.j2 index 9f5ba3369b6f..e268ed117414 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_async_mixins.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_async_mixins.py.j2 @@ -45,6 +45,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -101,6 +102,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -160,6 +162,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -214,6 +217,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -271,6 +275,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -397,6 +402,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -519,6 +525,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -579,6 +586,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -638,6 +646,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -693,6 +702,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_client_macros.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_client_macros.j2 index 08da6aaa052b..7821112d5a61 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_client_macros.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_client_macros.j2 @@ -174,6 +174,11 @@ {% endif %} ) {% if method.lro %} + {% if service.version %} + lro_metadata = None + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + lro_metadata = [version_header.to_api_version_header("{{ service.version }}")] + {% endif %} # Wrap the response in an operation future. response = {{ method.client_output.ident.module_alias or method.client_output.ident.module }}.from_gapic( @@ -181,6 +186,9 @@ self._transport.operations_client, {{ method.lro.response_type.ident }}, metadata_type={{ method.lro.metadata_type.ident }}, + {% if service.version %} + grpc_metadata=lro_metadata, + {% endif %} ) {% elif method.paged_result_field %} diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_mixins.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_mixins.py.j2 index 4d02f0d91e4c..66450f5bf245 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_mixins.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/_mixins.py.j2 @@ -43,6 +43,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -103,6 +104,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -166,6 +168,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -220,6 +223,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -277,6 +281,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -407,6 +412,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -533,6 +539,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -597,6 +604,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -660,6 +668,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -719,6 +728,7 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/async_client.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/async_client.py.j2 index 8d96ab289388..d94ad0f893f9 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/async_client.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/async_client.py.j2 @@ -430,6 +430,11 @@ class {{ service.async_client_name }}: {% endif %} ) {% if method.lro %} + {% if service.version %} + lro_metadata = None + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + lro_metadata = [version_header.to_api_version_header("{{ service.version }}")] + {% endif %} # Wrap the response in an operation future. response = {{ method.client_output_async.ident.module_alias or method.client_output_async.ident.module }}.from_gapic( @@ -437,6 +442,9 @@ class {{ service.async_client_name }}: self._client._transport.operations_client, {{ method.lro.response_type.ident }}, metadata_type={{ method.lro.metadata_type.ident }}, + {% if service.version %} + grpc_metadata=lro_metadata, + {% endif %} ) {% elif method.paged_result_field %} @@ -569,6 +577,7 @@ class {{ service.async_client_name }}: metadata = tuple(metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -687,6 +696,7 @@ class {{ service.async_client_name }}: metadata = tuple(metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() @@ -743,6 +753,7 @@ class {{ service.async_client_name }}: metadata = tuple(metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._client._validate_universe_domain() diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 index 85c6855ebce1..4c0a016dbe75 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 @@ -721,6 +721,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -849,6 +850,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() @@ -915,6 +917,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) +{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Validate the universe domain. self._validate_universe_domain() diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 index c838c421be8c..39ad45e1644f 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 @@ -86,6 +86,13 @@ def test_delete_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -254,6 +261,13 @@ def test_cancel_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -421,6 +435,13 @@ def test_wait_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -589,6 +610,13 @@ def test_get_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -757,6 +785,13 @@ def test_list_operations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -931,6 +966,13 @@ def test_list_locations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -1100,6 +1142,13 @@ def test_get_location_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations/abc",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -1277,6 +1326,13 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -1445,6 +1501,13 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} @pytest.mark.asyncio @@ -1474,6 +1537,13 @@ async def test_get_iam_policy_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_get_iam_policy_from_dict(): @@ -1642,6 +1712,13 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} @pytest.mark.asyncio @@ -1673,6 +1750,13 @@ async def test_test_iam_permissions_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_test_iam_permissions_from_dict(): @@ -1849,6 +1933,13 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} {% endfor %} @@ -2018,6 +2109,13 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} @pytest.mark.asyncio @@ -2047,6 +2145,13 @@ async def test_get_iam_policy_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_get_iam_policy_from_dict(): @@ -2216,6 +2321,13 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} @pytest.mark.asyncio @@ -2247,6 +2359,13 @@ async def test_test_iam_permissions_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + {% if service.version %} + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw["metadata"] + {% endif %} def test_test_iam_permissions_from_dict(): diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index 136319c7ced0..ec3a664b56e5 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -217,9 +217,17 @@ def test_{{ method_name }}_api_version_header(transport_name): ) as call: call.return_value = {{ method.output.ident }}() {% if mode == "async" %} + {% if method.lro %} + response = await client.{{ method_name }}() + {% else %} await client.{{ method_name }}() + {% endif %} {% else %} + {% if method.lro %} + response = client.{{ method_name }}() + {% else %} client.{{ method_name }}() + {% endif %} {% endif %} # Establish that the api version header was sent. @@ -228,6 +236,16 @@ def test_{{ method_name }}_api_version_header(transport_name): version_header.API_VERSION_METADATA_KEY, "{{ service.version }}", ) in kw['metadata'] + {% if method.lro %} + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._refresh.keywords["metadata"] + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._cancel.keywords["metadata"] + {% endif %} else: pytest.skip("google-api-core>=2.19.0 is required for `google.api_core.version_header`") {% endfor %}{# mode #} diff --git a/packages/gapic-generator/tests/fragments/test_api_version.proto b/packages/gapic-generator/tests/fragments/test_api_version.proto index d75134d8457b..851a246c6016 100644 --- a/packages/gapic-generator/tests/fragments/test_api_version.proto +++ b/packages/gapic-generator/tests/fragments/test_api_version.proto @@ -17,7 +17,9 @@ syntax = "proto3"; package google.fragment; import "google/protobuf/struct.proto"; +import "google/api/annotations.proto"; import "google/api/client.proto"; +import "google/longrunning/operations.proto"; service MyServiceWithVersion { option (google.api.api_version) = "v1_20230601"; @@ -26,6 +28,17 @@ service MyServiceWithVersion { rpc MyMethod(MethodRequest) returns (MethodResponse) { option (google.api.method_signature) = "parameter"; } + + rpc MyLroMethod(MethodRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1/my_lro_method" + body: "*" + }; + option (google.longrunning.operation_info) = { + response_type: "MethodResponse" + metadata_type: "MethodMetadata" + }; + } } message MethodRequest { @@ -35,3 +48,5 @@ message MethodRequest { message MethodResponse { google.protobuf.Value result = 1; } + +message MethodMetadata {} diff --git a/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/async_client.py b/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/async_client.py index 08e073fc4054..a0443c1535f8 100755 --- a/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/async_client.py +++ b/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/async_client.py @@ -1274,6 +1274,9 @@ async def sample_wait(): timeout=timeout, metadata=metadata, ) + lro_metadata = None + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + lro_metadata = [version_header.to_api_version_header("v1_20240408")] # Wrap the response in an operation future. response = operation_async.from_gapic( @@ -1281,6 +1284,7 @@ async def sample_wait(): self._client._transport.operations_client, gs_echo.WaitResponse, metadata_type=gs_echo.WaitMetadata, + grpc_metadata=lro_metadata, ) # Done; return the response. @@ -1412,6 +1416,10 @@ async def list_operations( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1468,6 +1476,10 @@ async def get_operation( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1528,6 +1540,10 @@ async def delete_operation( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1583,6 +1599,10 @@ async def cancel_operation( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1701,6 +1721,10 @@ async def set_iam_policy( gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1824,6 +1848,10 @@ async def get_iam_policy( gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1885,6 +1913,10 @@ async def test_iam_permissions( gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1941,6 +1973,10 @@ async def get_location( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() @@ -1997,6 +2033,10 @@ async def list_locations( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._client._validate_universe_domain() diff --git a/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/client.py b/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/client.py index 50586844102c..b364917567ac 100755 --- a/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/client.py +++ b/packages/gapic-generator/tests/integration/goldens/showcase/google/showcase_v1beta1/services/echo/client.py @@ -1522,6 +1522,9 @@ def sample_wait(): timeout=timeout, metadata=metadata, ) + lro_metadata = None + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + lro_metadata = [version_header.to_api_version_header("v1_20240408")] # Wrap the response in an operation future. response = operation.from_gapic( @@ -1529,6 +1532,7 @@ def sample_wait(): self._transport.operations_client, gs_echo.WaitResponse, metadata_type=gs_echo.WaitMetadata, + grpc_metadata=lro_metadata, ) # Done; return the response. @@ -1673,6 +1677,10 @@ def list_operations( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -1733,6 +1741,10 @@ def get_operation( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -1797,6 +1809,10 @@ def delete_operation( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -1852,6 +1868,10 @@ def cancel_operation( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -1970,6 +1990,10 @@ def set_iam_policy( gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -2097,6 +2121,10 @@ def get_iam_policy( gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -2162,6 +2190,10 @@ def test_iam_permissions( gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -2222,6 +2254,10 @@ def get_location( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() @@ -2282,6 +2318,10 @@ def list_locations( gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + metadata = tuple(metadata) + ( + version_header.to_api_version_header("v1_20240408"), + ) # Validate the universe domain. self._validate_universe_domain() diff --git a/packages/gapic-generator/tests/integration/goldens/showcase/tests/unit/gapic/showcase_v1beta1/test_echo.py b/packages/gapic-generator/tests/integration/goldens/showcase/tests/unit/gapic/showcase_v1beta1/test_echo.py index 526eb660d4ff..cf17c6502895 100755 --- a/packages/gapic-generator/tests/integration/goldens/showcase/tests/unit/gapic/showcase_v1beta1/test_echo.py +++ b/packages/gapic-generator/tests/integration/goldens/showcase/tests/unit/gapic/showcase_v1beta1/test_echo.py @@ -407,7 +407,7 @@ def test_wait_api_version_header(transport_name): '__call__' ) as call: call.return_value = operations_pb2.Operation() - client.wait() + response = client.wait() # Establish that the api version header was sent. _, _, kw = call.mock_calls[0] @@ -415,6 +415,14 @@ def test_wait_api_version_header(transport_name): version_header.API_VERSION_METADATA_KEY, "v1_20240408", ) in kw['metadata'] + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in response._refresh.keywords["metadata"] + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in response._cancel.keywords["metadata"] else: pytest.skip("google-api-core>=2.19.0 is required for `google.api_core.version_header`") @pytest.mark.parametrize("transport_name", [ @@ -8188,6 +8196,11 @@ def test_delete_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_delete_operation_field_headers_async(): @@ -8214,6 +8227,11 @@ async def test_delete_operation_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_delete_operation_from_dict(): @@ -8355,6 +8373,11 @@ def test_cancel_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_cancel_operation_field_headers_async(): @@ -8381,6 +8404,11 @@ async def test_cancel_operation_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_cancel_operation_from_dict(): @@ -8522,6 +8550,11 @@ def test_get_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_get_operation_field_headers_async(): @@ -8548,6 +8581,11 @@ async def test_get_operation_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_get_operation_from_dict(): @@ -8689,6 +8727,11 @@ def test_list_operations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_list_operations_field_headers_async(): @@ -8715,6 +8758,11 @@ async def test_list_operations_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_list_operations_from_dict(): @@ -8856,6 +8904,11 @@ def test_list_locations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_list_locations_field_headers_async(): @@ -8882,6 +8935,11 @@ async def test_list_locations_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_list_locations_from_dict(): @@ -9022,6 +9080,11 @@ def test_get_location_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations/abc",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_get_location_field_headers_async(): @@ -9048,6 +9111,11 @@ async def test_get_location_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations/abc",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_get_location_from_dict(): @@ -9201,6 +9269,11 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio async def test_set_iam_policy_field_headers_async(): @@ -9227,6 +9300,11 @@ async def test_set_iam_policy_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_set_iam_policy_from_dict(): @@ -9393,6 +9471,11 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio @@ -9422,6 +9505,11 @@ async def test_get_iam_policy_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_get_iam_policy_from_dict(): @@ -9589,6 +9677,11 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] @pytest.mark.asyncio @@ -9620,6 +9713,11 @@ async def test_test_iam_permissions_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "v1_20240408", + ) in kw["metadata"] def test_test_iam_permissions_from_dict(): diff --git a/packages/gapic-generator/tests/unit/generator/test_generator.py b/packages/gapic-generator/tests/unit/generator/test_generator.py index ef1692bf2f6c..4c5969f69cb0 100644 --- a/packages/gapic-generator/tests/unit/generator/test_generator.py +++ b/packages/gapic-generator/tests/unit/generator/test_generator.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import dataclasses import json import os from textwrap import dedent @@ -26,6 +27,7 @@ from google.api import http_pb2 from google.api import routing_pb2 from google.api import service_pb2 +from google.longrunning import operations_pb2 from google.protobuf import descriptor_pb2 from google.protobuf.compiler.plugin_pb2 import CodeGeneratorResponse @@ -1022,6 +1024,200 @@ def test_routing_headers_client_streaming( assert '("table_name", request.table_name)' in content +@pytest.mark.parametrize("use_ads_templates", (False, True)) +@pytest.mark.parametrize("add_iam_methods", (False, True)) +def test_api_version_header_lro_and_mixins( + use_ads_templates: bool, + add_iam_methods: bool, +): + """Verify x-goog-api-version metadata is passed to LRO from_gapic and mixin methods.""" + ads_templates_dir = os.path.abspath( + os.path.join( + os.path.dirname(__file__), "..", "..", "..", "gapic", "ads-templates" + ) + ) + opts_parts = ["autogen-snippets=false"] + if use_ads_templates: + opts_parts.extend([f"python-gapic-templates={ads_templates_dir}", "old-naming"]) + if add_iam_methods: + opts_parts.append("add-iam-methods") + opts = Options.build(",".join(opts_parts)) + + http_opt_uri = "/v1/{name=examples/*}/*" + service_yaml_config = { + "apis": [ + {"name": "google.cloud.location.Locations"}, + {"name": "google.longrunning.Operations"}, + {"name": "google.iam.v1.IAMPolicy"}, + ], + "http": { + "rules": [ + { + "selector": "google.cloud.location.Locations.ListLocations", + "get": http_opt_uri, + "body": "*", + }, + { + "selector": "google.cloud.location.Locations.GetLocation", + "get": http_opt_uri, + "body": "*", + }, + { + "selector": "google.longrunning.Operations.CancelOperation", + "post": http_opt_uri, + "body": "*", + }, + { + "selector": "google.longrunning.Operations.DeleteOperation", + "get": http_opt_uri, + "body": "*", + }, + { + "selector": "google.longrunning.Operations.WaitOperation", + "post": http_opt_uri, + "body": "*", + }, + { + "selector": "google.longrunning.Operations.GetOperation", + "post": http_opt_uri, + "body": "*", + }, + { + "selector": "google.longrunning.Operations.ListOperations", + "post": http_opt_uri, + "body": "*", + }, + { + "selector": "google.iam.v1.IAMPolicy.SetIamPolicy", + "post": "/v1/{resource=examples/*}/*", + "body": "*", + }, + { + "selector": "google.iam.v1.IAMPolicy.GetIamPolicy", + "get": "/v1/{resource=examples/*}/*", + "body": "*", + }, + { + "selector": "google.iam.v1.IAMPolicy.TestIamPermissions", + "post": "/v1/{resource=examples/*}/*", + "body": "*", + }, + ] + }, + } + opts = dataclasses.replace(opts, service_yaml_config=service_yaml_config) + generator_obj = generator.Generator(opts) + + service_options = descriptor_pb2.ServiceOptions() + service_options.Extensions[client_pb2.api_version] = "v1_20260331" + + method_options = descriptor_pb2.MethodOptions() + method_options.Extensions[annotations_pb2.http].CopyFrom( + http_pb2.HttpRule( + post="/v1/someLroMethod", + body="*", + ) + ) + method_options.Extensions[operations_pb2.operation_info].MergeFrom( + operations_pb2.OperationInfo( + response_type="google.cloud.hatstand.v1.SomeResponse", + metadata_type="google.cloud.hatstand.v1.SomeMetadata", + ) + ) + + lro_file_pb = descriptor_pb2.FileDescriptorProto( + name="google/longrunning/operations.proto", + package="google.longrunning", + message_type=[descriptor_pb2.DescriptorProto(name="Operation")], + ) + file_pb = descriptor_pb2.FileDescriptorProto( + name="some_service.proto", + package="google.cloud.hatstand.v1", + message_type=[ + descriptor_pb2.DescriptorProto(name="SomeRequest"), + descriptor_pb2.DescriptorProto(name="SomeResponse"), + descriptor_pb2.DescriptorProto(name="SomeMetadata"), + ], + service=[ + descriptor_pb2.ServiceDescriptorProto( + name="SomeService", + options=service_options, + method=[ + descriptor_pb2.MethodDescriptorProto( + name="SomeLroMethod", + input_type=".google.cloud.hatstand.v1.SomeRequest", + output_type=".google.longrunning.Operation", + options=method_options, + ) + ], + ) + ], + ) + lro_proto = api.Proto.build( + lro_file_pb, + file_to_generate=False, + naming=naming.NewNaming(name="Hatstand", version="v1"), + ) + api_schema = api.API.build( + [file_pb], + package="google.cloud.hatstand.v1", + opts=opts, + prior_protos={"google/longrunning/operations.proto": lro_proto}, + ) + + cgr = generator_obj.get_response(api_schema=api_schema, opts=opts) + files_by_name = {f.name: f.content for f in cgr.file} + + client_files = [ + content + for name, content in files_by_name.items() + if name.endswith("/services/some_service/client.py") + or name.endswith("/services/some_service/async_client.py") + ] + assert len(client_files) == (1 if use_ads_templates else 2) + + expected_Mixin_methods = ( + "def list_operations(", + "def get_operation(", + "def delete_operation(", + "def cancel_operation(", + "def wait_operation(", + "def set_iam_policy(", + "def get_iam_policy(", + "def test_iam_permissions(", + "def get_location(", + "def list_locations(", + ) + for content in client_files: + assert ( + 'lro_metadata = [version_header.to_api_version_header("v1_20260331")]' + in content + ) + assert "grpc_metadata=lro_metadata," in content + for method_sig in expected_Mixin_methods: + method_idx = content.index(method_sig) + next_def_idx = content.find("\n def ", method_idx + 1) + if next_def_idx == -1: + next_def_idx = content.find("\n async def ", method_idx + 1) + method_body = ( + content[method_idx:next_def_idx] + if next_def_idx != -1 + else content[method_idx:] + ) + assert ( + 'version_header.to_api_version_header("v1_20260331")' in method_body + ), f"Missing version header in {method_sig}" + + test_files = [ + content + for name, content in files_by_name.items() + if name.endswith("/test_some_service.py") + ] + assert len(test_files) == 1 + assert 'response._refresh.keywords["metadata"]' in test_files[0] + assert 'response._cancel.keywords["metadata"]' in test_files[0] + + def make_generator(opts_str: str = "") -> generator.Generator: return generator.Generator(Options.build(opts_str)) From 47ef50c4fe2aa6fe7366b3b2e23818a18eeeb1d9 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 12 Nov 2026 16:59:30 -0700 Subject: [PATCH 2/5] revert changes in ads templates --- .../%sub/services/%service/_mixins.py.j2 | 10 -- .../%sub/services/%service/client.py.j2 | 11 --- .../%name_%version/%sub/_test_mixins.py.j2 | 91 ------------------- .../%name_%version/%sub/test_%service.py.j2 | 14 --- .../tests/unit/generator/test_generator.py | 11 +-- 5 files changed, 1 insertion(+), 136 deletions(-) diff --git a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 index f0dfb8328c72..eb19c3c8bd07 100644 --- a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/_mixins.py.j2 @@ -44,7 +44,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -99,7 +98,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -157,7 +155,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. rpc(request_pb, retry=retry, timeout=timeout, metadata=metadata,) @@ -210,7 +207,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. rpc(request_pb, retry=retry, timeout=timeout, metadata=metadata,) @@ -261,7 +257,6 @@ rpc = self._transport._wrapped_methods[self._transport.wait_operation] metadata = tuple(metadata) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -386,7 +381,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -507,7 +501,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -566,7 +559,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -624,7 +616,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -678,7 +669,6 @@ gapic_v1.routing_header.to_grpc_metadata( (("name", request_pb.name),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( diff --git a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 index a7f982b1e03f..33253567b5db 100644 --- a/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/%namespace/%name/%version/%sub/services/%service/client.py.j2 @@ -507,11 +507,6 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): metadata=metadata, ) {% if method.lro %} - {% if service.version %} - lro_metadata = None - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - lro_metadata = [version_header.to_api_version_header("{{ service.version }}")] - {% endif %} # Wrap the response in an operation future. response = {{ method.client_output.ident.module_alias or method.client_output.ident.module }}.from_gapic( @@ -519,9 +514,6 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): self._transport.operations_client, {{ method.lro.response_type.ident }}, metadata_type={{ method.lro.metadata_type.ident }}, - {% if service.version %} - grpc_metadata=lro_metadata, - {% endif %} ) {% elif method.paged_result_field %} @@ -661,7 +653,6 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -783,7 +774,6 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( @@ -844,7 +834,6 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): gapic_v1.routing_header.to_grpc_metadata( (("resource", request_pb.resource),)), ) -{{ shared_macros.add_api_version_header_to_metadata(service.version) }} # Send the request. response = rpc( diff --git a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 index 6b259f12a714..e19793749d66 100644 --- a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 @@ -113,13 +113,6 @@ def test_delete_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_delete_operation_from_dict(): client = {{ service.client_name }}( @@ -205,13 +198,6 @@ def test_cancel_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_cancel_operation_from_dict(): client = {{ service.client_name }}( @@ -297,13 +283,6 @@ def test_wait_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_wait_operation_from_dict(): client = {{ service.client_name }}( @@ -390,13 +369,6 @@ def test_get_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_get_operation_from_dict(): client = {{ service.client_name }}( @@ -482,13 +454,6 @@ def test_list_operations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_list_operations_from_dict(): @@ -579,13 +544,6 @@ def test_list_locations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_list_locations_from_dict(): client = {{ service.client_name }}( @@ -670,13 +628,6 @@ def test_get_location_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations/abc",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_get_location_from_dict(): client = {{ service.client_name }}( @@ -770,13 +721,6 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_set_iam_policy_from_dict(): client = {{ service.client_name }}( @@ -867,13 +811,6 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_get_iam_policy_from_dict(): @@ -970,13 +907,6 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_test_iam_permissions_from_dict(): @@ -1072,13 +1002,6 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_set_iam_policy_from_dict(): client = {{ service.client_name }}( @@ -1170,13 +1093,6 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_get_iam_policy_from_dict(): @@ -1274,13 +1190,6 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} def test_test_iam_permissions_from_dict(): diff --git a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index 795d47fa0267..2b3c289a0595 100644 --- a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -665,11 +665,7 @@ def test_{{ method_name }}_api_version_header(transport_name): '__call__' ) as call: call.return_value = {{ method.output.ident }}() - {% if method.lro %} - response = client.{{ method_name }}() - {% else %} client.{{ method_name }}() - {% endif %} # Establish that the api version header was sent. _, _, kw = call.mock_calls[0] @@ -677,16 +673,6 @@ def test_{{ method_name }}_api_version_header(transport_name): version_header.API_VERSION_METADATA_KEY, "{{ service.version }}", ) in kw['metadata'] - {% if method.lro %} - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in response._refresh.keywords["metadata"] - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in response._cancel.keywords["metadata"] - {% endif %} else: pytest.skip("google-api-core>=2.19.0 is required for `google.api_core.version_header`") {% endif %}{# service.version #} diff --git a/packages/gapic-generator/tests/unit/generator/test_generator.py b/packages/gapic-generator/tests/unit/generator/test_generator.py index 4c5969f69cb0..5883245a38cd 100644 --- a/packages/gapic-generator/tests/unit/generator/test_generator.py +++ b/packages/gapic-generator/tests/unit/generator/test_generator.py @@ -1024,21 +1024,12 @@ def test_routing_headers_client_streaming( assert '("table_name", request.table_name)' in content -@pytest.mark.parametrize("use_ads_templates", (False, True)) @pytest.mark.parametrize("add_iam_methods", (False, True)) def test_api_version_header_lro_and_mixins( - use_ads_templates: bool, add_iam_methods: bool, ): """Verify x-goog-api-version metadata is passed to LRO from_gapic and mixin methods.""" - ads_templates_dir = os.path.abspath( - os.path.join( - os.path.dirname(__file__), "..", "..", "..", "gapic", "ads-templates" - ) - ) opts_parts = ["autogen-snippets=false"] - if use_ads_templates: - opts_parts.extend([f"python-gapic-templates={ads_templates_dir}", "old-naming"]) if add_iam_methods: opts_parts.append("add-iam-methods") opts = Options.build(",".join(opts_parts)) @@ -1174,7 +1165,7 @@ def test_api_version_header_lro_and_mixins( if name.endswith("/services/some_service/client.py") or name.endswith("/services/some_service/async_client.py") ] - assert len(client_files) == (1 if use_ads_templates else 2) + assert len(client_files) == 2 expected_Mixin_methods = ( "def list_operations(", From 3bc2f98c777d6b6f58ff10b5c2912597b31969f6 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 12 Nov 2026 17:02:38 -0700 Subject: [PATCH 3/5] removed conditional check --- .../%name_%version/%sub/test_%service.py.j2 | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index ec3a664b56e5..59f559a923f9 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -206,48 +206,42 @@ async def test_{{ method_name }}_api_version_header_async(transport_name="grpc") def test_{{ method_name }}_api_version_header(transport_name): client = {{ service.client_name }}(credentials=ga_credentials.AnonymousCredentials(), transport=transport_name) {% endif %} - # TODO: Make this test unconditional once the minimum supported version of - # google-api-core becomes 2.19.0 or higher. - api_core_major, api_core_minor = [int(part) for part in api_core_version.__version__.split(".")[0:2]] - if api_core_major > 2 or (api_core_major == 2 and api_core_minor >= 19): - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.{{ method.transport_safe_name|snake_case }}), - '__call__' - ) as call: - call.return_value = {{ method.output.ident }}() - {% if mode == "async" %} - {% if method.lro %} - response = await client.{{ method_name }}() - {% else %} - await client.{{ method_name }}() - {% endif %} + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.{{ method.transport_safe_name|snake_case }}), + '__call__' + ) as call: + call.return_value = {{ method.output.ident }}() + {% if mode == "async" %} + {% if method.lro %} + response = await client.{{ method_name }}() {% else %} - {% if method.lro %} - response = client.{{ method_name }}() - {% else %} - client.{{ method_name }}() - {% endif %} + await client.{{ method_name }}() + {% endif %} + {% else %} + {% if method.lro %} + response = client.{{ method_name }}() + {% else %} + client.{{ method_name }}() {% endif %} - - # Establish that the api version header was sent. - _, _, kw = call.mock_calls[0] - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw['metadata'] - {% if method.lro %} - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in response._refresh.keywords["metadata"] - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in response._cancel.keywords["metadata"] {% endif %} - else: - pytest.skip("google-api-core>=2.19.0 is required for `google.api_core.version_header`") + + # Establish that the api version header was sent. + _, _, kw = call.mock_calls[0] + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw['metadata'] + {% if method.lro %} + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._refresh.keywords["metadata"] + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._cancel.keywords["metadata"] + {% endif %} {% endfor %}{# mode #} {% endwith %} {% endfor %} From 56d29591cf130c559593e68557457fead28f3ea3 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 12 Nov 2026 17:11:38 -0700 Subject: [PATCH 4/5] removed unneeded test --- .../tests/unit/generator/test_generator.py | 187 ------------------ 1 file changed, 187 deletions(-) diff --git a/packages/gapic-generator/tests/unit/generator/test_generator.py b/packages/gapic-generator/tests/unit/generator/test_generator.py index 5883245a38cd..ef1692bf2f6c 100644 --- a/packages/gapic-generator/tests/unit/generator/test_generator.py +++ b/packages/gapic-generator/tests/unit/generator/test_generator.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import dataclasses import json import os from textwrap import dedent @@ -27,7 +26,6 @@ from google.api import http_pb2 from google.api import routing_pb2 from google.api import service_pb2 -from google.longrunning import operations_pb2 from google.protobuf import descriptor_pb2 from google.protobuf.compiler.plugin_pb2 import CodeGeneratorResponse @@ -1024,191 +1022,6 @@ def test_routing_headers_client_streaming( assert '("table_name", request.table_name)' in content -@pytest.mark.parametrize("add_iam_methods", (False, True)) -def test_api_version_header_lro_and_mixins( - add_iam_methods: bool, -): - """Verify x-goog-api-version metadata is passed to LRO from_gapic and mixin methods.""" - opts_parts = ["autogen-snippets=false"] - if add_iam_methods: - opts_parts.append("add-iam-methods") - opts = Options.build(",".join(opts_parts)) - - http_opt_uri = "/v1/{name=examples/*}/*" - service_yaml_config = { - "apis": [ - {"name": "google.cloud.location.Locations"}, - {"name": "google.longrunning.Operations"}, - {"name": "google.iam.v1.IAMPolicy"}, - ], - "http": { - "rules": [ - { - "selector": "google.cloud.location.Locations.ListLocations", - "get": http_opt_uri, - "body": "*", - }, - { - "selector": "google.cloud.location.Locations.GetLocation", - "get": http_opt_uri, - "body": "*", - }, - { - "selector": "google.longrunning.Operations.CancelOperation", - "post": http_opt_uri, - "body": "*", - }, - { - "selector": "google.longrunning.Operations.DeleteOperation", - "get": http_opt_uri, - "body": "*", - }, - { - "selector": "google.longrunning.Operations.WaitOperation", - "post": http_opt_uri, - "body": "*", - }, - { - "selector": "google.longrunning.Operations.GetOperation", - "post": http_opt_uri, - "body": "*", - }, - { - "selector": "google.longrunning.Operations.ListOperations", - "post": http_opt_uri, - "body": "*", - }, - { - "selector": "google.iam.v1.IAMPolicy.SetIamPolicy", - "post": "/v1/{resource=examples/*}/*", - "body": "*", - }, - { - "selector": "google.iam.v1.IAMPolicy.GetIamPolicy", - "get": "/v1/{resource=examples/*}/*", - "body": "*", - }, - { - "selector": "google.iam.v1.IAMPolicy.TestIamPermissions", - "post": "/v1/{resource=examples/*}/*", - "body": "*", - }, - ] - }, - } - opts = dataclasses.replace(opts, service_yaml_config=service_yaml_config) - generator_obj = generator.Generator(opts) - - service_options = descriptor_pb2.ServiceOptions() - service_options.Extensions[client_pb2.api_version] = "v1_20260331" - - method_options = descriptor_pb2.MethodOptions() - method_options.Extensions[annotations_pb2.http].CopyFrom( - http_pb2.HttpRule( - post="/v1/someLroMethod", - body="*", - ) - ) - method_options.Extensions[operations_pb2.operation_info].MergeFrom( - operations_pb2.OperationInfo( - response_type="google.cloud.hatstand.v1.SomeResponse", - metadata_type="google.cloud.hatstand.v1.SomeMetadata", - ) - ) - - lro_file_pb = descriptor_pb2.FileDescriptorProto( - name="google/longrunning/operations.proto", - package="google.longrunning", - message_type=[descriptor_pb2.DescriptorProto(name="Operation")], - ) - file_pb = descriptor_pb2.FileDescriptorProto( - name="some_service.proto", - package="google.cloud.hatstand.v1", - message_type=[ - descriptor_pb2.DescriptorProto(name="SomeRequest"), - descriptor_pb2.DescriptorProto(name="SomeResponse"), - descriptor_pb2.DescriptorProto(name="SomeMetadata"), - ], - service=[ - descriptor_pb2.ServiceDescriptorProto( - name="SomeService", - options=service_options, - method=[ - descriptor_pb2.MethodDescriptorProto( - name="SomeLroMethod", - input_type=".google.cloud.hatstand.v1.SomeRequest", - output_type=".google.longrunning.Operation", - options=method_options, - ) - ], - ) - ], - ) - lro_proto = api.Proto.build( - lro_file_pb, - file_to_generate=False, - naming=naming.NewNaming(name="Hatstand", version="v1"), - ) - api_schema = api.API.build( - [file_pb], - package="google.cloud.hatstand.v1", - opts=opts, - prior_protos={"google/longrunning/operations.proto": lro_proto}, - ) - - cgr = generator_obj.get_response(api_schema=api_schema, opts=opts) - files_by_name = {f.name: f.content for f in cgr.file} - - client_files = [ - content - for name, content in files_by_name.items() - if name.endswith("/services/some_service/client.py") - or name.endswith("/services/some_service/async_client.py") - ] - assert len(client_files) == 2 - - expected_Mixin_methods = ( - "def list_operations(", - "def get_operation(", - "def delete_operation(", - "def cancel_operation(", - "def wait_operation(", - "def set_iam_policy(", - "def get_iam_policy(", - "def test_iam_permissions(", - "def get_location(", - "def list_locations(", - ) - for content in client_files: - assert ( - 'lro_metadata = [version_header.to_api_version_header("v1_20260331")]' - in content - ) - assert "grpc_metadata=lro_metadata," in content - for method_sig in expected_Mixin_methods: - method_idx = content.index(method_sig) - next_def_idx = content.find("\n def ", method_idx + 1) - if next_def_idx == -1: - next_def_idx = content.find("\n async def ", method_idx + 1) - method_body = ( - content[method_idx:next_def_idx] - if next_def_idx != -1 - else content[method_idx:] - ) - assert ( - 'version_header.to_api_version_header("v1_20260331")' in method_body - ), f"Missing version header in {method_sig}" - - test_files = [ - content - for name, content in files_by_name.items() - if name.endswith("/test_some_service.py") - ] - assert len(test_files) == 1 - assert 'response._refresh.keywords["metadata"]' in test_files[0] - assert 'response._cancel.keywords["metadata"]' in test_files[0] - - def make_generator(opts_str: str = "") -> generator.Generator: return generator.Generator(Options.build(opts_str)) From f972b9316be9459441efc846a1832dcc8ed0b06c Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 12 Nov 2026 17:33:05 -0700 Subject: [PATCH 5/5] revert version check change --- .../%name_%version/%sub/_test_mixins.py.j2 | 146 ++++-------------- .../%name_%version/%sub/test_%service.py.j2 | 65 ++++---- 2 files changed, 59 insertions(+), 152 deletions(-) diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 index 39ad45e1644f..d71834b205fd 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2 @@ -1,3 +1,13 @@ +{% macro assert_api_version_header(service_version) -%} +{% if service_version %} + + if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service_version }}", + ) in kw["metadata"] +{%- endif -%} +{% endmacro -%} {% if api.has_operations_mixin and ('grpc' in opts.transport or 'grpc_asyncio' in opts.transport) %} {% if "DeleteOperation" in api.mixin_api_methods %} @@ -86,13 +96,7 @@ def test_delete_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -261,13 +265,7 @@ def test_cancel_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -435,13 +433,7 @@ def test_wait_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -610,13 +602,7 @@ def test_get_operation_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -785,13 +771,7 @@ def test_list_operations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -966,13 +946,7 @@ def test_list_locations_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -1142,13 +1116,7 @@ def test_get_location_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "name=locations/abc",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -1326,13 +1294,7 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -1501,13 +1463,7 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} @pytest.mark.asyncio @@ -1537,13 +1493,7 @@ async def test_get_iam_policy_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} def test_get_iam_policy_from_dict(): @@ -1712,13 +1662,7 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} @pytest.mark.asyncio @@ -1750,13 +1694,7 @@ async def test_test_iam_permissions_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} def test_test_iam_permissions_from_dict(): @@ -1933,13 +1871,7 @@ def test_set_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} {% endfor %} @@ -2109,13 +2041,7 @@ def test_get_iam_policy_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} @pytest.mark.asyncio @@ -2145,13 +2071,7 @@ async def test_get_iam_policy_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} def test_get_iam_policy_from_dict(): @@ -2321,13 +2241,7 @@ def test_test_iam_permissions_field_headers(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} @pytest.mark.asyncio @@ -2359,13 +2273,7 @@ async def test_test_iam_permissions_field_headers_async(): # Establish that the field header was sent. _, _, kw = call.mock_calls[0] assert ("x-goog-request-params", "resource=resource/value",) in kw["metadata"] - {% if service.version %} - if HAS_GOOGLE_API_CORE_VERSION_HEADER: # pragma: NO COVER - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw["metadata"] - {% endif %} +{{- assert_api_version_header(service.version) }} def test_test_iam_permissions_from_dict(): diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index 59f559a923f9..d05663397ad1 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -206,42 +206,41 @@ async def test_{{ method_name }}_api_version_header_async(transport_name="grpc") def test_{{ method_name }}_api_version_header(transport_name): client = {{ service.client_name }}(credentials=ga_credentials.AnonymousCredentials(), transport=transport_name) {% endif %} - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.{{ method.transport_safe_name|snake_case }}), - '__call__' - ) as call: - call.return_value = {{ method.output.ident }}() - {% if mode == "async" %} - {% if method.lro %} - response = await client.{{ method_name }}() - {% else %} - await client.{{ method_name }}() - {% endif %} - {% else %} - {% if method.lro %} - response = client.{{ method_name }}() + # TODO: Make this test unconditional once the minimum supported version of + # google-api-core becomes 2.19.0 or higher. + api_core_major, api_core_minor = [int(part) for part in api_core_version.__version__.split(".")[0:2]] + if api_core_major > 2 or (api_core_major == 2 and api_core_minor >= 19): + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.{{ method.transport_safe_name|snake_case }}), + '__call__' + ) as call: + call.return_value = {{ method.output.ident }}() + {% set response_prefix = "response = " if method.lro else "" %} + {% if mode == "async" %} + {{ response_prefix }}await client.{{ method_name }}() {% else %} - client.{{ method_name }}() + {{ response_prefix }}client.{{ method_name }}() {% endif %} - {% endif %} - # Establish that the api version header was sent. - _, _, kw = call.mock_calls[0] - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in kw['metadata'] - {% if method.lro %} - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in response._refresh.keywords["metadata"] - assert ( - version_header.API_VERSION_METADATA_KEY, - "{{ service.version }}", - ) in response._cancel.keywords["metadata"] - {% endif %} + # Establish that the api version header was sent. + _, _, kw = call.mock_calls[0] + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in kw['metadata'] + {% if method.lro %} + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._refresh.keywords["metadata"] + assert ( + version_header.API_VERSION_METADATA_KEY, + "{{ service.version }}", + ) in response._cancel.keywords["metadata"] + {% endif %} + else: + pytest.skip("google-api-core>=2.19.0 is required for `google.api_core.version_header`") {% endfor %}{# mode #} {% endwith %} {% endfor %}