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 cb5f9c4d77df..0399b5e331a4 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 @@ -1114,10 +1114,10 @@ def test_{{ service.client_name|snake_case }}_create_channel_credentials_file(cl {% for method in service.methods.values() if 'rest' in opts.transport %} {% if method.extended_lro %} -{{ test_macros.rest_required_tests(method, service, numeric_enums=opts.rest_numeric_enums, full_extended_lro=True) }} +{{ test_macros.rest_required_tests(api, method, service, numeric_enums=opts.rest_numeric_enums, full_extended_lro=True) }} {% endif %} -{{ test_macros.rest_required_tests(method, service, numeric_enums=opts.rest_numeric_enums) }} +{{ test_macros.rest_required_tests(api, method, service, numeric_enums=opts.rest_numeric_enums) }} {% endfor -%} {#- method in methods for rest #} diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_macros.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_macros.j2 index ff6a15014e10..c1bc8893df6f 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_macros.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_macros.j2 @@ -1018,7 +1018,7 @@ def test_{{ method_name }}_raw_page_lro(): {% endif %}{# method.paged_result_field #}{% endwith %} {% endmacro %} -{% macro rest_required_tests(method, service, numeric_enums=False, full_extended_lro=False) %} +{% macro rest_required_tests(api, method, service, numeric_enums=False, full_extended_lro=False) %} {% with method_name = method.client_method_name|snake_case + "_unary" if method.extended_lro and not full_extended_lro else method.client_method_name|snake_case, method_output = method.extended_lro.operation_type if method.extended_lro and not full_extended_lro else method.output %}{% if method.http_options %} {# TODO(kbandes): remove this if condition when lro and client streaming are supported. #} {% if not method.client_streaming %} @@ -1218,6 +1218,24 @@ def test_{{ method_name }}_rest_required_fields(request_type={{ method.input.ide ('$alt', 'json;enum-encoding=int') {% endif %} ] + {% with method_settings = api.all_method_settings.get(method.meta.address.proto) %} + {% if method_settings is not none %} + {% for auto_populated_field in method_settings.auto_populated_fields %} + # Ensure that the uuid4 field is set according to AIP 4235 + # and remove it so the expected/actual comparison succeeds. + # Otherwise, the actual will differ from the expected since + # this field was automatically populated. + found_field = None + for i, (key, value) in enumerate(req.call_args.kwargs['params']): + if key == "{{ auto_populated_field|camel_case }}": + assert re.match(r"{{ get_uuid4_re() }}", value) + found_field = i + break + if found_field is not None: + del req.call_args.kwargs['params'][found_field] + {% endfor %} + {% endif %} + {% endwith %} actual_params = req.call_args.kwargs['params'] assert expected_params == actual_params diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/async_client.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/async_client.py index fa743e28de70..3e773abb4bf8 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/async_client.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/async_client.py @@ -17,6 +17,7 @@ from collections import OrderedDict import re from typing import Dict, Callable, Mapping, MutableMapping, MutableSequence, Optional, Sequence, Tuple, Type, Union +import uuid from google.cloud.storagebatchoperations_v1 import gapic_version as package_version @@ -620,6 +621,9 @@ async def sample_create_job(): )), ) + if not request.request_id: + request.request_id = str(uuid.uuid4()) + # Validate the universe domain. self._client._validate_universe_domain() @@ -724,6 +728,9 @@ async def sample_delete_job(): )), ) + if not request.request_id: + request.request_id = str(uuid.uuid4()) + # Validate the universe domain. self._client._validate_universe_domain() @@ -824,6 +831,9 @@ async def sample_cancel_job(): )), ) + if not request.request_id: + request.request_id = str(uuid.uuid4()) + # Validate the universe domain. self._client._validate_universe_domain() diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py index 298d4b24467c..c01ac435ad6c 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py @@ -20,6 +20,7 @@ import os import re from typing import Dict, Callable, Mapping, MutableMapping, MutableSequence, Optional, Sequence, Tuple, Type, Union, cast +import uuid import warnings from google.cloud.storagebatchoperations_v1 import gapic_version as package_version @@ -1004,6 +1005,9 @@ def sample_create_job(): )), ) + if not request.request_id: + request.request_id = str(uuid.uuid4()) + # Validate the universe domain. self._validate_universe_domain() @@ -1107,6 +1111,9 @@ def sample_delete_job(): )), ) + if not request.request_id: + request.request_id = str(uuid.uuid4()) + # Validate the universe domain. self._validate_universe_domain() @@ -1206,6 +1213,9 @@ def sample_cancel_job(): )), ) + if not request.request_id: + request.request_id = str(uuid.uuid4()) + # Validate the universe domain. self._validate_universe_domain() diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py index b0110ab7446d..b3f7dc9a9e68 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py @@ -14,6 +14,7 @@ # limitations under the License. # import os +import re from unittest import mock from unittest.mock import AsyncMock @@ -1813,6 +1814,10 @@ def test_create_job(request_type, transport: str = 'grpc'): # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. request = request_type() + if isinstance(request, dict): + request['request_id'] = "explicit value for autopopulate-able field" + else: + request.request_id = "explicit value for autopopulate-able field" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -1826,6 +1831,7 @@ def test_create_job(request_type, transport: str = 'grpc'): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] request = storage_batch_operations.CreateJobRequest() + request.request_id = "explicit value for autopopulate-able field" assert args[0] == request # Establish that the response is the type that we expect. @@ -1856,6 +1862,10 @@ def test_create_job_non_empty_request_with_auto_populated_field(): client.create_job(request=request) call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None assert args[0] == storage_batch_operations.CreateJobRequest( parent='parent_value', job_id='job_id_value', @@ -1947,6 +1957,10 @@ async def test_create_job_async(transport: str = 'grpc_asyncio', request_type=st # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. request = request_type() + if isinstance(request, dict): + request['request_id'] = "explicit value for autopopulate-able field" + else: + request.request_id = "explicit value for autopopulate-able field" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -1962,6 +1976,7 @@ async def test_create_job_async(transport: str = 'grpc_asyncio', request_type=st assert len(call.mock_calls) _, args, _ = call.mock_calls[0] request = storage_batch_operations.CreateJobRequest() + request.request_id = "explicit value for autopopulate-able field" assert args[0] == request # Establish that the response is the type that we expect. @@ -2152,6 +2167,10 @@ def test_delete_job(request_type, transport: str = 'grpc'): # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. request = request_type() + if isinstance(request, dict): + request['request_id'] = "explicit value for autopopulate-able field" + else: + request.request_id = "explicit value for autopopulate-able field" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2165,6 +2184,7 @@ def test_delete_job(request_type, transport: str = 'grpc'): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] request = storage_batch_operations.DeleteJobRequest() + request.request_id = "explicit value for autopopulate-able field" assert args[0] == request # Establish that the response is the type that we expect. @@ -2194,6 +2214,10 @@ def test_delete_job_non_empty_request_with_auto_populated_field(): client.delete_job(request=request) call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None assert args[0] == storage_batch_operations.DeleteJobRequest( name='name_value', ) @@ -2274,6 +2298,10 @@ async def test_delete_job_async(transport: str = 'grpc_asyncio', request_type=st # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. request = request_type() + if isinstance(request, dict): + request['request_id'] = "explicit value for autopopulate-able field" + else: + request.request_id = "explicit value for autopopulate-able field" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2287,6 +2315,7 @@ async def test_delete_job_async(transport: str = 'grpc_asyncio', request_type=st assert len(call.mock_calls) _, args, _ = call.mock_calls[0] request = storage_batch_operations.DeleteJobRequest() + request.request_id = "explicit value for autopopulate-able field" assert args[0] == request # Establish that the response is the type that we expect. @@ -2455,6 +2484,10 @@ def test_cancel_job(request_type, transport: str = 'grpc'): # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. request = request_type() + if isinstance(request, dict): + request['request_id'] = "explicit value for autopopulate-able field" + else: + request.request_id = "explicit value for autopopulate-able field" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2469,6 +2502,7 @@ def test_cancel_job(request_type, transport: str = 'grpc'): assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] request = storage_batch_operations.CancelJobRequest() + request.request_id = "explicit value for autopopulate-able field" assert args[0] == request # Establish that the response is the type that we expect. @@ -2498,6 +2532,10 @@ def test_cancel_job_non_empty_request_with_auto_populated_field(): client.cancel_job(request=request) call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None assert args[0] == storage_batch_operations.CancelJobRequest( name='name_value', ) @@ -2578,6 +2616,10 @@ async def test_cancel_job_async(transport: str = 'grpc_asyncio', request_type=st # Everything is optional in proto3 as far as the runtime is concerned, # and we are mocking out the actual API, so just send an empty request. request = request_type() + if isinstance(request, dict): + request['request_id'] = "explicit value for autopopulate-able field" + else: + request.request_id = "explicit value for autopopulate-able field" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2592,6 +2634,7 @@ async def test_cancel_job_async(transport: str = 'grpc_asyncio', request_type=st assert len(call.mock_calls) _, args, _ = call.mock_calls[0] request = storage_batch_operations.CancelJobRequest() + request.request_id = "explicit value for autopopulate-able field" assert args[0] == request # Establish that the response is the type that we expect. @@ -4089,6 +4132,18 @@ def test_create_job_rest_required_fields(request_type=storage_batch_operations.C "", ), ] + # Ensure that the uuid4 field is set according to AIP 4235 + # and remove it so the expected/actual comparison succeeds. + # Otherwise, the actual will differ from the expected since + # this field was automatically populated. + found_field = None + for i, (key, value) in enumerate(req.call_args.kwargs['params']): + if key == "requestId": + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", value) + found_field = i + break + if found_field is not None: + del req.call_args.kwargs['params'][found_field] actual_params = req.call_args.kwargs['params'] assert expected_params == actual_params @@ -4256,6 +4311,18 @@ def test_delete_job_rest_required_fields(request_type=storage_batch_operations.D expected_params = [ ] + # Ensure that the uuid4 field is set according to AIP 4235 + # and remove it so the expected/actual comparison succeeds. + # Otherwise, the actual will differ from the expected since + # this field was automatically populated. + found_field = None + for i, (key, value) in enumerate(req.call_args.kwargs['params']): + if key == "requestId": + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", value) + found_field = i + break + if found_field is not None: + del req.call_args.kwargs['params'][found_field] actual_params = req.call_args.kwargs['params'] assert expected_params == actual_params @@ -4421,6 +4488,18 @@ def test_cancel_job_rest_required_fields(request_type=storage_batch_operations.C expected_params = [ ] + # Ensure that the uuid4 field is set according to AIP 4235 + # and remove it so the expected/actual comparison succeeds. + # Otherwise, the actual will differ from the expected since + # this field was automatically populated. + found_field = None + for i, (key, value) in enumerate(req.call_args.kwargs['params']): + if key == "requestId": + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", value) + found_field = i + break + if found_field is not None: + del req.call_args.kwargs['params'][found_field] actual_params = req.call_args.kwargs['params'] assert expected_params == actual_params @@ -5048,6 +5127,10 @@ def test_create_job_empty_call_grpc(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.CreateJobRequest() assert args[0] == request_msg @@ -5071,6 +5154,10 @@ def test_delete_job_empty_call_grpc(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.DeleteJobRequest() assert args[0] == request_msg @@ -5094,6 +5181,10 @@ def test_cancel_job_empty_call_grpc(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.CancelJobRequest() assert args[0] == request_msg @@ -5241,6 +5332,10 @@ async def test_create_job_empty_call_grpc_asyncio(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.CreateJobRequest() assert args[0] == request_msg @@ -5266,6 +5361,10 @@ async def test_delete_job_empty_call_grpc_asyncio(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.DeleteJobRequest() assert args[0] == request_msg @@ -5292,6 +5391,10 @@ async def test_cancel_job_empty_call_grpc_asyncio(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.CancelJobRequest() assert args[0] == request_msg @@ -6546,6 +6649,10 @@ def test_create_job_empty_call_rest(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.CreateJobRequest() assert args[0] == request_msg @@ -6568,6 +6675,10 @@ def test_delete_job_empty_call_rest(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.DeleteJobRequest() assert args[0] == request_msg @@ -6590,6 +6701,10 @@ def test_cancel_job_empty_call_rest(): # Establish that the underlying stub method was called. call.assert_called() _, args, _ = call.mock_calls[0] + # Ensure that the uuid4 field is set according to AIP 4235 + assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", args[0].request_id) + # clear UUID field so that the check below succeeds + args[0].request_id = None request_msg = storage_batch_operations.CancelJobRequest() assert args[0] == request_msg diff --git a/packages/gapic-generator/tests/integration/storagebatchoperations_v1.yaml b/packages/gapic-generator/tests/integration/storagebatchoperations_v1.yaml index 56cdc70278df..3e75ec7c3f7f 100644 --- a/packages/gapic-generator/tests/integration/storagebatchoperations_v1.yaml +++ b/packages/gapic-generator/tests/integration/storagebatchoperations_v1.yaml @@ -56,6 +56,16 @@ authentication: https://www.googleapis.com/auth/cloud-platform publishing: + method_settings: + - selector: google.cloud.storagebatchoperations.v1.StorageBatchOperations.CreateJob + auto_populated_fields: + - request_id + - selector: google.cloud.storagebatchoperations.v1.StorageBatchOperations.CancelJob + auto_populated_fields: + - request_id + - selector: google.cloud.storagebatchoperations.v1.StorageBatchOperations.DeleteJob + auto_populated_fields: + - request_id new_issue_uri: https://issuetracker.google.com/issues/new?component=815827&template=1395449 documentation_uri: https://cloud.google.com/storage/docs/batch-operations/overview api_short_name: storagebatchoperations