Skip to content

ci: add REST only config to showcase unit nox session - #18957

Open
parthea wants to merge 5 commits into
mainfrom
rest-only-api-goldens
Open

parthea wants to merge 5 commits into
mainfrom
rest-only-api-goldens

Conversation

@parthea

@parthea parthea commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

This PR updates the showcase_unit nox session to include a REST only configuration.

Fixes #18969

This PR is needed to unblock #18955

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the transport configuration for the Redis integration test from 'grpc+rest' to 'rest' only, resulting in the removal of gRPC-related code, async clients, async pagers, and async code samples from the generated golden files. Feedback on the changes highlights that although the async client is no longer exported, the 'async_client.py' file is still being generated as dead code; the generator should be updated to completely omit this file when the configured transport does not support or export an async client.

I am having trouble creating individual review comments. Click here to see my feedback.

packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/async_client.py (306-332)

medium

With transport = "rest", CloudRedisAsyncClient is no longer exported in __init__.py, and all async code samples have been removed. However, the async_client.py file itself is still being generated. This results in dead code in the generated library. The generator should be updated to completely omit generating async_client.py when the configured transport (like REST-only) does not support or export an async client.

References
  1. Do not suggest manual code modifications, optimizations, or style fixes for generated files, as any changes should be implemented in the generator or templates to prevent them from being overwritten.

@parthea
parthea force-pushed the rest-only-api-goldens branch from 59517ee to 418976f Compare November 2, 2026 18:08
@parthea
parthea force-pushed the rest-only-api-goldens branch from 418976f to 3c21a6f Compare November 2, 2026 18:20
@parthea parthea changed the title ci: add REST only API to goldens ci: add REST only config to showcase unit nox session Nov 2, 2026
@parthea parthea closed this Nov 2, 2026
@parthea parthea reopened this Nov 2, 2026
@parthea parthea closed this Nov 2, 2026
@parthea parthea reopened this Nov 2, 2026
@parthea

parthea commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

The failing presubmit GitHub Actions Scan will be fixed via #18962

@parthea
parthea marked this pull request as ready for review November 3, 2026 02:56
@parthea
parthea requested a review from a team as a code owner November 3, 2026 02:56
@chalmerlowe

Copy link
Copy Markdown
Contributor

QUESTION/NIT: Is there a motivating bug OR Issue that this fixes? I did not see one linked in the PR description.

Comment thread packages/gapic-generator/noxfile.py Resolved
Comment thread packages/gapic-generator/noxfile.py Resolved
parthea and others added 2 commits November 3, 2026 11:30
Co-authored-by: Chalmer Lowe <chalmerlowe@google.com>
Co-authored-by: Chalmer Lowe <chalmerlowe@google.com>
@parthea

parthea commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor Author

QUESTION/NIT: Is there a motivating bug OR Issue that this fixes? I did not see one linked in the PR description.

Good point. I created #18969 and linked it in the PR description

Comment on lines +1434 to +1442
# Test _ignore_credentials=True skips ADC and host without port defaults to :443.
class IgnoreCredsTransport(transports.{{ service.name }}Transport):
_ignore_credentials = True

with mock.patch.object(google.auth, 'default', autospec=True) as adc:
transport = IgnoreCredsTransport(host="squid.clam.whelk")
adc.assert_not_called()
assert transport._credentials is None
assert transport.host == "squid.clam.whelk:443"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKER

The mix of assert statements in test_{{ service.name|snake_case }}_base_transport_with_adc() mixes two opposing behaviors (_ignore_credentials=False vs. _ignore_credentials=True + host port normalization) in one function. I recommend we separate these into two separate tests.

The test as written does test host="squid.clam.whelk" (verifying :443 is appended when no port is present), but I think it omits the companion boundary where host already includes a port (e.g., host="squid.clam.whelk:8080"), which exercises the ":" not in host branch in base transport init.

Lastly, I believe the preferred paradigm is to use spec_set=True if we are using autospec=True

Suggested change
# Test _ignore_credentials=True skips ADC and host without port defaults to :443.
class IgnoreCredsTransport(transports.{{ service.name }}Transport):
_ignore_credentials = True
with mock.patch.object(google.auth, 'default', autospec=True) as adc:
transport = IgnoreCredsTransport(host="squid.clam.whelk")
adc.assert_not_called()
assert transport._credentials is None
assert transport.host == "squid.clam.whelk:443"
# Test _ignore_credentials=True skips Application Default Credentials (ADC)
# and a host without a port defaults to :443.
@pytest.mark.parametrize(
"host,expected_host",
[
pytest.param("squid.clam.whelk", "squid.clam.whelk:443", id="host_without_port_defaults_to_443"),
pytest.param("squid.clam.whelk:8080", "squid.clam.whelk:8080", id="host_with_port_preserved"),
],
)
def test_{{ service.name|snake_case }}_base_transport_ignore_credentials(host, expected_host):
class IgnoreCredsTransport(transports.{{ service.name }}Transport):
_ignore_credentials = True
with mock.patch.object(
google.auth, "default", autospec=True, spec_set=True
) as adc:
transport = IgnoreCredsTransport(host=host)
adc.assert_not_called()
assert transport._credentials is None
assert transport.host == expected_host

Comment on lines +2301 to +2302
{{ async_decorator }}
{{ async_prefix }}def test_{{ method_name }}_empty_call_{{ transport_name }}():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION/SUGGESTION

I think a parametrization is likely a good candidate here. I think request can be either None OR an empty dict. If that is correct, we should exercise both, right?

Suggested change
{{ async_decorator }}
{{ async_prefix }}def test_{{ method_name }}_empty_call_{{ transport_name }}():
{{ async_decorator }}
@pytest.mark.parametrize(
"request_val",
[
pytest.param(None, id="none_request"),
pytest.param({}, id="empty_dict_request"),
],
)
{{ async_prefix }}def test_{{ method_name }}_empty_call_{{ transport_name }}():

I also think we would benefit by adding to the mock.patch.object:

autospec=True,
spec_set=True,

Of course we would need to incorporate request_val into the function:

{{ await_prefix }}client.{{ method_name }}(request=request_val)

_, args, _ = call.mock_calls[0]
{% for oneofs in method.flattened_oneof_fields().values() %}
{% with field = oneofs[-1] %}
assert args[0].{{ method.flattened_field_to_key[field.name] }} == {{ field.mock_value }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION

See note above.

Suggested change
assert args[0].{{ method.flattened_field_to_key[field.name] }} == {{ field.mock_value }}
assert args[1].{{ method.flattened_field_to_key[field.name] }} == {{ field.mock_value }}

with mock.patch.object(
type(client.transport.{{ method.transport_safe_name|snake_case }}),
"__call__",
) as call:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION

Adding autospec=True, spec_set=True enforces signature verification on the transport callable (and I believe it also shifts the bound self argument to args[0], placing the request protobuf at args[1])

Suggested change
) as call:
"__call__",
autospec=True,
spec_set=True,
) as call:

@chalmerlowe chalmerlowe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve pending resolution of the comments.
If you strongly disagree with any given comment, let me know and we can work something out.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coverage gap for REST only generated libraries

2 participants