33{% block content %}
44
55import os
6+ {% if api .all_method_settings .values ()|map (attribute ="auto_populated_fields" , default =[])|list %}
7+ import re
8+ {% endif %}
69# try/except added for compatibility with python < 3.8
710try:
811 from unittest import mock
@@ -67,6 +70,7 @@ from google.iam.v1 import policy_pb2 # type: ignore
6770{% endif %}
6871{% endfilter %}
6972
73+ {% with uuid 4_re = "[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}" %}
7074
7175def client_cert_source_callback():
7276 return b"cert bytes", b"key bytes"
@@ -513,6 +517,7 @@ def test_{{ service.client_name|snake_case }}_create_channel_credentials_file(cl
513517 dict,
514518])
515519def test_{{ method_name }}(request_type, transport: str = 'grpc'):
520+ {% with auto_populated_field_sample_value = "explicit value for autopopulate-able field" %}
516521 client = {{ service.client_name }}(
517522 credentials=ga_credentials.AnonymousCredentials(),
518523 transport=transport,
@@ -521,6 +526,18 @@ def test_{{ method_name }}(request_type, transport: str = 'grpc'):
521526 # Everything is optional in proto3 as far as the runtime is concerned,
522527 # and we are mocking out the actual API, so just send an empty request.
523528 request = request_type()
529+
530+ {# Set UUID4 fields so that they are not automatically populated. #}
531+ {% with method_settings = api .all_method_settings .get (method .meta .address .proto ) %}
532+ {% if method_settings is not none %}
533+ {% for auto_populated_field in method_settings .auto_populated_fields %}
534+ if isinstance(request, dict):
535+ request['{{ auto_populated_field }}'] = "{{ auto_populated_field_sample_value }}"
536+ else:
537+ request.{{ auto_populated_field }} = "{{ auto_populated_field_sample_value }}"
538+ {% endfor %}
539+ {% endif %} {# if method_settings is not none #}
540+ {% endwith %} {# method_settings #}
524541 {% if method .client_streaming %}
525542 requests = [request]
526543 {% endif %}
@@ -568,7 +585,15 @@ def test_{{ method_name }}(request_type, transport: str = 'grpc'):
568585 {% if method .client_streaming %}
569586 assert next(args[0]) == request
570587 {% else %}
571- assert args[0] == {{ method.input.ident }}()
588+ request = {{ method.input.ident }}()
589+ {% with method_settings = api .all_method_settings .get (method .meta .address .proto ) %}
590+ {% if method_settings is not none %}
591+ {% for auto_populated_field in method_settings .auto_populated_fields %}
592+ request.{{ auto_populated_field }} = "{{ auto_populated_field_sample_value }}"
593+ {% endfor %}
594+ {% endif %} {# if method_settings is not none #}
595+ {% endwith %} {# method_settings #}
596+ assert args[0] == request
572597 {% endif %}
573598
574599 # Establish that the response is the type that we expect.
@@ -608,6 +633,7 @@ def test_{{ method_name }}(request_type, transport: str = 'grpc'):
608633 {% endif %} {# end oneof/optional #}
609634 {% endfor %}
610635 {% endif %}
636+ {% endwith %} {# auto_populated_field_sample_value #}
611637
612638
613639{% if not method .client_streaming %}
@@ -629,8 +655,59 @@ def test_{{ method_name }}_empty_call():
629655 {% if method .client_streaming %}
630656 assert next(args[0]) == request
631657 {% else %}
658+ {% with method_settings = api .all_method_settings .get (method .meta .address .proto ) %}
659+ {% if method_settings is not none %}
660+ {% for auto_populated_field in method_settings .auto_populated_fields %}
661+ # Ensure that the uuid4 field is set according to AIP 4235
662+ assert re.match(r"{{ uuid4_re }}", args[0].{{ auto_populated_field }})
663+ # clear UUID field so that the check below succeeds
664+ args[0].{{ auto_populated_field }} = None
665+ {% endfor %}
666+ {% endif %} {# if method_settings is not none #}
667+ {% endwith %} {# method_settings #}
632668 assert args[0] == {{ method.input.ident }}()
633669 {% endif %}
670+
671+
672+ def test_{{ method_name }}_non_empty_request_with_auto_populated_field():
673+ # This test is a coverage failsafe to make sure that UUID4 fields are
674+ # automatically populated, according to AIP-4235, with non-empty requests.
675+ client = {{ service.client_name }}(
676+ credentials=ga_credentials.AnonymousCredentials(),
677+ transport='grpc',
678+ )
679+
680+ # Populate all string fields in the request which are not UUID4
681+ # since we want to check that UUID4 are populated automatically
682+ # if they meet the requirements of AIP 4235.
683+ request = {{ method.input.ident }}(
684+ {% for field in method .input .fields .values () if field .ident |string () == "str" and not field .uuid 4 %}
685+ {{ field.name }}={{ field.mock_value }},
686+ {% endfor %}
687+ )
688+
689+ # Mock the actual call within the gRPC stub, and fake the request.
690+ with mock.patch.object(
691+ type(client.transport.{{ method.transport_safe_name|snake_case }}),
692+ '__call__') as call:
693+ client.{{ method_name }}(request=request)
694+ call.assert_called()
695+ _, args, _ = call.mock_calls[0]
696+ {% with method_settings = api .all_method_settings .get (method .meta .address .proto ) %}
697+ {% if method_settings is not none %}
698+ {% for auto_populated_field in method_settings .auto_populated_fields %}
699+ # Ensure that the uuid4 field is set according to AIP 4235
700+ assert re.match(r"{{ uuid4_re }}", args[0].{{ auto_populated_field }})
701+ # clear UUID field so that the check below succeeds
702+ args[0].{{ auto_populated_field }} = None
703+ {% endfor %}
704+ {% endif %} {# if method_settings is not none #}
705+ {% endwith %} {# method_settings #}
706+ assert args[0] == {{ method.input.ident }}(
707+ {% for field in method .input .fields .values () if field .ident |string () == "str" and not field .uuid 4 %}
708+ {{ field.name }}={{ field.mock_value }},
709+ {% endfor %}
710+ )
634711{% endif %}
635712
636713
@@ -2364,4 +2441,5 @@ def test_client_ctx():
23642441 pass
23652442 close.assert_called()
23662443
2444+ {% endwith %} {# uuid4_re #}
23672445{% endblock %}
0 commit comments