Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 0ff4584

Browse files
committed
test: add async REST URL query params encoding tests and update goldens
Add async REST transport versions of URL query params encoding tests to achieve 100% code coverage for rest_asyncio.py. Update integration test golden files to reflect the $alt query parameter encoding fix.
1 parent c6bbe1a commit 0ff4584

21 files changed

Lines changed: 6572 additions & 362 deletions

File tree

gapic/templates/tests/unit/gapic/%name_%version/%sub/_test_mixins.py.j2

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,4 +2171,369 @@ def test_test_iam_permissions_rest_url_query_params_encoding():
21712171

21722172
{% endif %} {# iam_mixin #}
21732173

2174+
{% if rest_async_io_enabled %}
2175+
{# Async REST URL encoding tests for mixin methods #}
2176+
2177+
{% if api.has_operations_mixin %}
2178+
2179+
{% if "ListOperations" in api.mixin_api_methods %}
2180+
@pytest.mark.asyncio
2181+
async def test_list_operations_rest_asyncio_url_query_params_encoding():
2182+
if not HAS_ASYNC_REST_EXTRA:
2183+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2184+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2185+
method_class = transport.list_operations.__class__
2186+
get_response_fn = method_class._get_response
2187+
2188+
mock_session = mock.AsyncMock()
2189+
mock_response = mock.Mock()
2190+
mock_response.status_code = 200
2191+
mock_session.get.return_value = mock_response
2192+
2193+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2194+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2195+
2196+
transcoded_request = {
2197+
'uri': '/v1/test/operations',
2198+
'method': 'get',
2199+
}
2200+
2201+
await get_response_fn(
2202+
host='https://example.com',
2203+
metadata=[],
2204+
query_params={},
2205+
session=mock_session,
2206+
timeout=None,
2207+
transcoded_request=transcoded_request,
2208+
)
2209+
2210+
assert mock_session.get.called
2211+
call_url = mock_session.get.call_args.args[0]
2212+
assert '$alt=json' in call_url
2213+
assert '%24alt' not in call_url
2214+
assert 'foo=bar' in call_url
2215+
{% endif %}
2216+
2217+
{% if "GetOperation" in api.mixin_api_methods %}
2218+
@pytest.mark.asyncio
2219+
async def test_get_operation_rest_asyncio_url_query_params_encoding():
2220+
if not HAS_ASYNC_REST_EXTRA:
2221+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2222+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2223+
method_class = transport.get_operation.__class__
2224+
get_response_fn = method_class._get_response
2225+
2226+
mock_session = mock.AsyncMock()
2227+
mock_response = mock.Mock()
2228+
mock_response.status_code = 200
2229+
mock_session.get.return_value = mock_response
2230+
2231+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2232+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2233+
2234+
transcoded_request = {
2235+
'uri': '/v1/test/operations/op1',
2236+
'method': 'get',
2237+
}
2238+
2239+
await get_response_fn(
2240+
host='https://example.com',
2241+
metadata=[],
2242+
query_params={},
2243+
session=mock_session,
2244+
timeout=None,
2245+
transcoded_request=transcoded_request,
2246+
)
2247+
2248+
assert mock_session.get.called
2249+
call_url = mock_session.get.call_args.args[0]
2250+
assert '$alt=json' in call_url
2251+
assert '%24alt' not in call_url
2252+
assert 'foo=bar' in call_url
2253+
{% endif %}
2254+
2255+
{% if "DeleteOperation" in api.mixin_api_methods %}
2256+
@pytest.mark.asyncio
2257+
async def test_delete_operation_rest_asyncio_url_query_params_encoding():
2258+
if not HAS_ASYNC_REST_EXTRA:
2259+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2260+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2261+
method_class = transport.delete_operation.__class__
2262+
get_response_fn = method_class._get_response
2263+
2264+
mock_session = mock.AsyncMock()
2265+
mock_response = mock.Mock()
2266+
mock_response.status_code = 200
2267+
mock_session.delete.return_value = mock_response
2268+
2269+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2270+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2271+
2272+
transcoded_request = {
2273+
'uri': '/v1/test/operations/op1',
2274+
'method': 'delete',
2275+
}
2276+
2277+
await get_response_fn(
2278+
host='https://example.com',
2279+
metadata=[],
2280+
query_params={},
2281+
session=mock_session,
2282+
timeout=None,
2283+
transcoded_request=transcoded_request,
2284+
)
2285+
2286+
assert mock_session.delete.called
2287+
call_url = mock_session.delete.call_args.args[0]
2288+
assert '$alt=json' in call_url
2289+
assert '%24alt' not in call_url
2290+
assert 'foo=bar' in call_url
2291+
{% endif %}
2292+
2293+
{% if "CancelOperation" in api.mixin_api_methods %}
2294+
@pytest.mark.asyncio
2295+
async def test_cancel_operation_rest_asyncio_url_query_params_encoding():
2296+
if not HAS_ASYNC_REST_EXTRA:
2297+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2298+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2299+
method_class = transport.cancel_operation.__class__
2300+
get_response_fn = method_class._get_response
2301+
2302+
mock_session = mock.AsyncMock()
2303+
mock_response = mock.Mock()
2304+
mock_response.status_code = 200
2305+
mock_session.post.return_value = mock_response
2306+
2307+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2308+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2309+
2310+
transcoded_request = {
2311+
'uri': '/v1/test/operations/op1:cancel',
2312+
'method': 'post',
2313+
'body': {},
2314+
}
2315+
2316+
await get_response_fn(
2317+
host='https://example.com',
2318+
metadata=[],
2319+
query_params={},
2320+
session=mock_session,
2321+
timeout=None,
2322+
transcoded_request=transcoded_request,
2323+
body={},
2324+
)
2325+
2326+
assert mock_session.post.called
2327+
call_url = mock_session.post.call_args.args[0]
2328+
assert '$alt=json' in call_url
2329+
assert '%24alt' not in call_url
2330+
assert 'foo=bar' in call_url
2331+
{% endif %}
2332+
2333+
{% endif %} {# operations_mixin #}
2334+
2335+
{% if api.has_location_mixin %}
2336+
2337+
{% if "ListLocations" in api.mixin_api_methods %}
2338+
@pytest.mark.asyncio
2339+
async def test_list_locations_rest_asyncio_url_query_params_encoding():
2340+
if not HAS_ASYNC_REST_EXTRA:
2341+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2342+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2343+
method_class = transport.list_locations.__class__
2344+
get_response_fn = method_class._get_response
2345+
2346+
mock_session = mock.AsyncMock()
2347+
mock_response = mock.Mock()
2348+
mock_response.status_code = 200
2349+
mock_session.get.return_value = mock_response
2350+
2351+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2352+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2353+
2354+
transcoded_request = {
2355+
'uri': '/v1/projects/p1/locations',
2356+
'method': 'get',
2357+
}
2358+
2359+
await get_response_fn(
2360+
host='https://example.com',
2361+
metadata=[],
2362+
query_params={},
2363+
session=mock_session,
2364+
timeout=None,
2365+
transcoded_request=transcoded_request,
2366+
)
2367+
2368+
assert mock_session.get.called
2369+
call_url = mock_session.get.call_args.args[0]
2370+
assert '$alt=json' in call_url
2371+
assert '%24alt' not in call_url
2372+
assert 'foo=bar' in call_url
2373+
{% endif %}
2374+
2375+
{% if "GetLocation" in api.mixin_api_methods %}
2376+
@pytest.mark.asyncio
2377+
async def test_get_location_rest_asyncio_url_query_params_encoding():
2378+
if not HAS_ASYNC_REST_EXTRA:
2379+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2380+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2381+
method_class = transport.get_location.__class__
2382+
get_response_fn = method_class._get_response
2383+
2384+
mock_session = mock.AsyncMock()
2385+
mock_response = mock.Mock()
2386+
mock_response.status_code = 200
2387+
mock_session.get.return_value = mock_response
2388+
2389+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2390+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2391+
2392+
transcoded_request = {
2393+
'uri': '/v1/projects/p1/locations/l1',
2394+
'method': 'get',
2395+
}
2396+
2397+
await get_response_fn(
2398+
host='https://example.com',
2399+
metadata=[],
2400+
query_params={},
2401+
session=mock_session,
2402+
timeout=None,
2403+
transcoded_request=transcoded_request,
2404+
)
2405+
2406+
assert mock_session.get.called
2407+
call_url = mock_session.get.call_args.args[0]
2408+
assert '$alt=json' in call_url
2409+
assert '%24alt' not in call_url
2410+
assert 'foo=bar' in call_url
2411+
{% endif %}
2412+
2413+
{% endif %} {# location_mixin #}
2414+
2415+
{% if api.has_iam_mixin or opts.add_iam_methods %}
2416+
2417+
{% if "SetIamPolicy" in api.mixin_api_methods or opts.add_iam_methods %}
2418+
@pytest.mark.asyncio
2419+
async def test_set_iam_policy_rest_asyncio_url_query_params_encoding():
2420+
if not HAS_ASYNC_REST_EXTRA:
2421+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2422+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2423+
method_class = transport.set_iam_policy.__class__
2424+
get_response_fn = method_class._get_response
2425+
2426+
mock_session = mock.AsyncMock()
2427+
mock_response = mock.Mock()
2428+
mock_response.status_code = 200
2429+
mock_session.post.return_value = mock_response
2430+
2431+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2432+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2433+
2434+
transcoded_request = {
2435+
'uri': '/v1/resource:setIamPolicy',
2436+
'method': 'post',
2437+
'body': {},
2438+
}
2439+
2440+
await get_response_fn(
2441+
host='https://example.com',
2442+
metadata=[],
2443+
query_params={},
2444+
session=mock_session,
2445+
timeout=None,
2446+
transcoded_request=transcoded_request,
2447+
body={},
2448+
)
2449+
2450+
assert mock_session.post.called
2451+
call_url = mock_session.post.call_args.args[0]
2452+
assert '$alt=json' in call_url
2453+
assert '%24alt' not in call_url
2454+
assert 'foo=bar' in call_url
2455+
{% endif %}
2456+
2457+
{% if "GetIamPolicy" in api.mixin_api_methods or opts.add_iam_methods %}
2458+
@pytest.mark.asyncio
2459+
async def test_get_iam_policy_rest_asyncio_url_query_params_encoding():
2460+
if not HAS_ASYNC_REST_EXTRA:
2461+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2462+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2463+
method_class = transport.get_iam_policy.__class__
2464+
get_response_fn = method_class._get_response
2465+
2466+
mock_session = mock.AsyncMock()
2467+
mock_response = mock.Mock()
2468+
mock_response.status_code = 200
2469+
mock_session.get.return_value = mock_response
2470+
2471+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2472+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2473+
2474+
transcoded_request = {
2475+
'uri': '/v1/resource:getIamPolicy',
2476+
'method': 'get',
2477+
}
2478+
2479+
await get_response_fn(
2480+
host='https://example.com',
2481+
metadata=[],
2482+
query_params={},
2483+
session=mock_session,
2484+
timeout=None,
2485+
transcoded_request=transcoded_request,
2486+
)
2487+
2488+
assert mock_session.get.called
2489+
call_url = mock_session.get.call_args.args[0]
2490+
assert '$alt=json' in call_url
2491+
assert '%24alt' not in call_url
2492+
assert 'foo=bar' in call_url
2493+
{% endif %}
2494+
2495+
{% if "TestIamPermissions" in api.mixin_api_methods or opts.add_iam_methods %}
2496+
@pytest.mark.asyncio
2497+
async def test_test_iam_permissions_rest_asyncio_url_query_params_encoding():
2498+
if not HAS_ASYNC_REST_EXTRA:
2499+
pytest.skip("the library must be installed with the `async_rest` extra to test this feature.")
2500+
transport = transports.Async{{ service.name }}RestTransport(credentials=async_anonymous_credentials())
2501+
method_class = transport.test_iam_permissions.__class__
2502+
get_response_fn = method_class._get_response
2503+
2504+
mock_session = mock.AsyncMock()
2505+
mock_response = mock.Mock()
2506+
mock_response.status_code = 200
2507+
mock_session.post.return_value = mock_response
2508+
2509+
with mock.patch.object(rest_helpers, 'flatten_query_params') as mock_flatten:
2510+
mock_flatten.return_value = [('$alt', 'json;enum-encoding=int'), ('foo', 'bar')]
2511+
2512+
transcoded_request = {
2513+
'uri': '/v1/resource:testIamPermissions',
2514+
'method': 'post',
2515+
'body': {},
2516+
}
2517+
2518+
await get_response_fn(
2519+
host='https://example.com',
2520+
metadata=[],
2521+
query_params={},
2522+
session=mock_session,
2523+
timeout=None,
2524+
transcoded_request=transcoded_request,
2525+
body={},
2526+
)
2527+
2528+
assert mock_session.post.called
2529+
call_url = mock_session.post.call_args.args[0]
2530+
assert '$alt=json' in call_url
2531+
assert '%24alt' not in call_url
2532+
assert 'foo=bar' in call_url
2533+
{% endif %}
2534+
2535+
{% endif %} {# iam_mixin #}
2536+
2537+
{% endif %} {# rest_async_io_enabled #}
2538+
21742539
{% endif %} {# rest transport #}

gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,10 +1118,10 @@ def test_{{ service.client_name|snake_case }}_create_channel_credentials_file(cl
11181118

11191119
{% for method in service.methods.values() if 'rest' in opts.transport %}
11201120
{% if method.extended_lro %}
1121-
{{ test_macros.rest_required_tests(method, service, numeric_enums=opts.rest_numeric_enums, full_extended_lro=True) }}
1121+
{{ test_macros.rest_required_tests(method, service, numeric_enums=opts.rest_numeric_enums, full_extended_lro=True, rest_async_io_enabled=rest_async_io_enabled) }}
11221122

11231123
{% endif %}
1124-
{{ test_macros.rest_required_tests(method, service, numeric_enums=opts.rest_numeric_enums) }}
1124+
{{ test_macros.rest_required_tests(method, service, numeric_enums=opts.rest_numeric_enums, rest_async_io_enabled=rest_async_io_enabled) }}
11251125

11261126
{% endfor -%} {#- method in methods for rest #}
11271127

0 commit comments

Comments
 (0)