From 6ec898e4d671344a3f4a8322417d38c8cf606f1b Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Fri, 14 May 2021 15:56:58 -0600 Subject: [PATCH] feat: Etags in Secret Manager (#116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Etags in Secret Manager Users can now use etags for optimistic concurrency control when modifying Secret or SecretVersion. PiperOrigin-RevId: 373836373 Source-Link: https://github.com/googleapis/googleapis/commit/bff807490f09712527b1af607160a4f7ae48702e Source-Link: https://github.com/googleapis/googleapis-gen/commit/174c036e0697d01dd21a22b210e820b602a00265 * 🦉 Updates from OwlBot Co-authored-by: Owl Bot --- .../secret_manager_service/async_client.py | 15 ++-- .../services/secret_manager_service/client.py | 15 ++-- .../secret_manager_service/transports/grpc.py | 8 +- .../transports/grpc_asyncio.py | 8 +- .../cloud/secretmanager_v1/types/resources.py | 11 ++- .../cloud/secretmanager_v1/types/service.py | 34 ++++++++- scripts/fixup_secretmanager_v1_keywords.py | 8 +- .../test_secret_manager_service.py | 74 +++++++++++++++---- 8 files changed, 133 insertions(+), 40 deletions(-) diff --git a/google/cloud/secretmanager_v1/services/secret_manager_service/async_client.py b/google/cloud/secretmanager_v1/services/secret_manager_service/async_client.py index b14dbd3..eec4552 100644 --- a/google/cloud/secretmanager_v1/services/secret_manager_service/async_client.py +++ b/google/cloud/secretmanager_v1/services/secret_manager_service/async_client.py @@ -783,8 +783,8 @@ async def get_secret_version( r"""Gets metadata for a [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Args: @@ -795,8 +795,9 @@ async def get_secret_version( Required. The resource name of the [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] in the format ``projects/*/secrets/*/versions/*``. + ``projects/*/secrets/*/versions/latest`` is an alias to - the ``latest`` + the most recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. This corresponds to the ``name`` field @@ -864,8 +865,8 @@ async def access_secret_version( [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. This call returns the secret data. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Args: @@ -877,6 +878,10 @@ async def access_secret_version( [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] in the format ``projects/*/secrets/*/versions/*``. + ``projects/*/secrets/*/versions/latest`` is an alias to + the most recently created + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/secretmanager_v1/services/secret_manager_service/client.py b/google/cloud/secretmanager_v1/services/secret_manager_service/client.py index d16e14b..90b459c 100644 --- a/google/cloud/secretmanager_v1/services/secret_manager_service/client.py +++ b/google/cloud/secretmanager_v1/services/secret_manager_service/client.py @@ -987,8 +987,8 @@ def get_secret_version( r"""Gets metadata for a [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Args: @@ -999,8 +999,9 @@ def get_secret_version( Required. The resource name of the [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] in the format ``projects/*/secrets/*/versions/*``. + ``projects/*/secrets/*/versions/latest`` is an alias to - the ``latest`` + the most recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. This corresponds to the ``name`` field @@ -1068,8 +1069,8 @@ def access_secret_version( [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. This call returns the secret data. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Args: @@ -1081,6 +1082,10 @@ def access_secret_version( [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] in the format ``projects/*/secrets/*/versions/*``. + ``projects/*/secrets/*/versions/latest`` is an alias to + the most recently created + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc.py b/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc.py index 99550bc..e952c51 100644 --- a/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc.py +++ b/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc.py @@ -429,8 +429,8 @@ def get_secret_version( Gets metadata for a [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Returns: @@ -463,8 +463,8 @@ def access_secret_version( [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. This call returns the secret data. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Returns: diff --git a/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc_asyncio.py b/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc_asyncio.py index 2335886..7422ce8 100644 --- a/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc_asyncio.py +++ b/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc_asyncio.py @@ -441,8 +441,8 @@ def get_secret_version( Gets metadata for a [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Returns: @@ -476,8 +476,8 @@ def access_secret_version( [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. This call returns the secret data. - ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + ``projects/*/secrets/*/versions/latest`` is an alias to the most + recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. Returns: diff --git a/google/cloud/secretmanager_v1/types/resources.py b/google/cloud/secretmanager_v1/types/resources.py index a81b3b9..d445501 100644 --- a/google/cloud/secretmanager_v1/types/resources.py +++ b/google/cloud/secretmanager_v1/types/resources.py @@ -86,6 +86,9 @@ class Secret(proto.Message): ttl (google.protobuf.duration_pb2.Duration): Input only. The TTL for the [Secret][google.cloud.secretmanager.v1.Secret]. + etag (str): + Optional. Etag of the currently stored + [Secret][google.cloud.secretmanager.v1.Secret]. rotation (google.cloud.secretmanager_v1.types.Rotation): Optional. Rotation policy attached to the [Secret][google.cloud.secretmanager.v1.Secret]. May be @@ -103,6 +106,7 @@ class Secret(proto.Message): ttl = proto.Field( proto.MESSAGE, number=7, oneof="expiration", message=duration_pb2.Duration, ) + etag = proto.Field(proto.STRING, number=8,) rotation = proto.Field(proto.MESSAGE, number=9, message="Rotation",) @@ -135,6 +139,9 @@ class SecretVersion(proto.Message): replication_status (google.cloud.secretmanager_v1.types.ReplicationStatus): The replication status of the [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. + etag (str): + Output only. Etag of the currently stored + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. """ class State(proto.Enum): @@ -156,6 +163,7 @@ class State(proto.Enum): replication_status = proto.Field( proto.MESSAGE, number=5, message="ReplicationStatus", ) + etag = proto.Field(proto.STRING, number=6,) class Replication(proto.Message): @@ -408,7 +416,8 @@ class Rotation(proto.Message): next_rotation_time (google.protobuf.timestamp_pb2.Timestamp): Optional. Timestamp in UTC at which the [Secret][google.cloud.secretmanager.v1.Secret] is scheduled - to rotate. + to rotate. Cannot be set to less than 300s (5 min) in the + future and at most 3153600000s (100 years). [next_rotation_time][google.cloud.secretmanager.v1.Rotation.next_rotation_time] MUST be set if diff --git a/google/cloud/secretmanager_v1/types/service.py b/google/cloud/secretmanager_v1/types/service.py index b50d878..7ddeed3 100644 --- a/google/cloud/secretmanager_v1/types/service.py +++ b/google/cloud/secretmanager_v1/types/service.py @@ -219,8 +219,9 @@ class GetSecretVersionRequest(proto.Message): Required. The resource name of the [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] in the format ``projects/*/secrets/*/versions/*``. + ``projects/*/secrets/*/versions/latest`` is an alias to the - ``latest`` + most recently created [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. """ @@ -254,6 +255,10 @@ class AccessSecretVersionRequest(proto.Message): Required. The resource name of the [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] in the format ``projects/*/secrets/*/versions/*``. + + ``projects/*/secrets/*/versions/latest`` is an alias to the + most recently created + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. """ name = proto.Field(proto.STRING, number=1,) @@ -285,9 +290,15 @@ class DeleteSecretRequest(proto.Message): Required. The resource name of the [Secret][google.cloud.secretmanager.v1.Secret] to delete in the format ``projects/*/secrets/*``. + etag (str): + Optional. Etag of the + [Secret][google.cloud.secretmanager.v1.Secret]. The request + succeeds if it matches the etag of the currently stored + secret object. If the etag is omitted, the request succeeds. """ name = proto.Field(proto.STRING, number=1,) + etag = proto.Field(proto.STRING, number=2,) class DisableSecretVersionRequest(proto.Message): @@ -300,9 +311,16 @@ class DisableSecretVersionRequest(proto.Message): [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] to disable in the format ``projects/*/secrets/*/versions/*``. + etag (str): + Optional. Etag of the + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. + The request succeeds if it matches the etag of the currently + stored secret version object. If the etag is omitted, the + request succeeds. """ name = proto.Field(proto.STRING, number=1,) + etag = proto.Field(proto.STRING, number=2,) class EnableSecretVersionRequest(proto.Message): @@ -314,9 +332,16 @@ class EnableSecretVersionRequest(proto.Message): Required. The resource name of the [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] to enable in the format ``projects/*/secrets/*/versions/*``. + etag (str): + Optional. Etag of the + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. + The request succeeds if it matches the etag of the currently + stored secret version object. If the etag is omitted, the + request succeeds. """ name = proto.Field(proto.STRING, number=1,) + etag = proto.Field(proto.STRING, number=2,) class DestroySecretVersionRequest(proto.Message): @@ -329,9 +354,16 @@ class DestroySecretVersionRequest(proto.Message): [SecretVersion][google.cloud.secretmanager.v1.SecretVersion] to destroy in the format ``projects/*/secrets/*/versions/*``. + etag (str): + Optional. Etag of the + [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. + The request succeeds if it matches the etag of the currently + stored secret version object. If the etag is omitted, the + request succeeds. """ name = proto.Field(proto.STRING, number=1,) + etag = proto.Field(proto.STRING, number=2,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/scripts/fixup_secretmanager_v1_keywords.py b/scripts/fixup_secretmanager_v1_keywords.py index 33732bf..6f922e8 100644 --- a/scripts/fixup_secretmanager_v1_keywords.py +++ b/scripts/fixup_secretmanager_v1_keywords.py @@ -42,10 +42,10 @@ class secretmanagerCallTransformer(cst.CSTTransformer): 'access_secret_version': ('name', ), 'add_secret_version': ('parent', 'payload', ), 'create_secret': ('parent', 'secret_id', 'secret', ), - 'delete_secret': ('name', ), - 'destroy_secret_version': ('name', ), - 'disable_secret_version': ('name', ), - 'enable_secret_version': ('name', ), + 'delete_secret': ('name', 'etag', ), + 'destroy_secret_version': ('name', 'etag', ), + 'disable_secret_version': ('name', 'etag', ), + 'enable_secret_version': ('name', 'etag', ), 'get_iam_policy': ('resource', 'options', ), 'get_secret': ('name', ), 'get_secret_version': ('name', ), diff --git a/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py b/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py index 3c6ce61..4fb6181 100644 --- a/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py +++ b/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py @@ -863,7 +863,9 @@ def test_create_secret( with mock.patch.object(type(client.transport.create_secret), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = resources.Secret( - name="name_value", expire_time=timestamp_pb2.Timestamp(seconds=751), + name="name_value", + etag="etag_value", + expire_time=timestamp_pb2.Timestamp(seconds=751), ) response = client.create_secret(request) @@ -875,6 +877,7 @@ def test_create_secret( # Establish that the response is the type that we expect. assert isinstance(response, resources.Secret) assert response.name == "name_value" + assert response.etag == "etag_value" def test_create_secret_from_dict(): @@ -912,7 +915,7 @@ async def test_create_secret_async( with mock.patch.object(type(client.transport.create_secret), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - resources.Secret(name="name_value",) + resources.Secret(name="name_value", etag="etag_value",) ) response = await client.create_secret(request) @@ -924,6 +927,7 @@ async def test_create_secret_async( # Establish that the response is the type that we expect. assert isinstance(response, resources.Secret) assert response.name == "name_value" + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -1089,7 +1093,9 @@ def test_add_secret_version( ) as call: # Designate an appropriate return value for the call. call.return_value = resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) response = client.add_secret_version(request) @@ -1102,6 +1108,7 @@ def test_add_secret_version( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" def test_add_secret_version_from_dict(): @@ -1144,7 +1151,9 @@ async def test_add_secret_version_async( # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) ) response = await client.add_secret_version(request) @@ -1158,6 +1167,7 @@ async def test_add_secret_version_async( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -1323,7 +1333,9 @@ def test_get_secret(transport: str = "grpc", request_type=service.GetSecretReque with mock.patch.object(type(client.transport.get_secret), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = resources.Secret( - name="name_value", expire_time=timestamp_pb2.Timestamp(seconds=751), + name="name_value", + etag="etag_value", + expire_time=timestamp_pb2.Timestamp(seconds=751), ) response = client.get_secret(request) @@ -1335,6 +1347,7 @@ def test_get_secret(transport: str = "grpc", request_type=service.GetSecretReque # Establish that the response is the type that we expect. assert isinstance(response, resources.Secret) assert response.name == "name_value" + assert response.etag == "etag_value" def test_get_secret_from_dict(): @@ -1372,7 +1385,7 @@ async def test_get_secret_async( with mock.patch.object(type(client.transport.get_secret), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - resources.Secret(name="name_value",) + resources.Secret(name="name_value", etag="etag_value",) ) response = await client.get_secret(request) @@ -1384,6 +1397,7 @@ async def test_get_secret_async( # Establish that the response is the type that we expect. assert isinstance(response, resources.Secret) assert response.name == "name_value" + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -1529,7 +1543,9 @@ def test_update_secret( with mock.patch.object(type(client.transport.update_secret), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = resources.Secret( - name="name_value", expire_time=timestamp_pb2.Timestamp(seconds=751), + name="name_value", + etag="etag_value", + expire_time=timestamp_pb2.Timestamp(seconds=751), ) response = client.update_secret(request) @@ -1541,6 +1557,7 @@ def test_update_secret( # Establish that the response is the type that we expect. assert isinstance(response, resources.Secret) assert response.name == "name_value" + assert response.etag == "etag_value" def test_update_secret_from_dict(): @@ -1578,7 +1595,7 @@ async def test_update_secret_async( with mock.patch.object(type(client.transport.update_secret), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - resources.Secret(name="name_value",) + resources.Secret(name="name_value", etag="etag_value",) ) response = await client.update_secret(request) @@ -1590,6 +1607,7 @@ async def test_update_secret_async( # Establish that the response is the type that we expect. assert isinstance(response, resources.Secret) assert response.name == "name_value" + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -2331,7 +2349,9 @@ def test_get_secret_version( ) as call: # Designate an appropriate return value for the call. call.return_value = resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) response = client.get_secret_version(request) @@ -2344,6 +2364,7 @@ def test_get_secret_version( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" def test_get_secret_version_from_dict(): @@ -2386,7 +2407,9 @@ async def test_get_secret_version_async( # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) ) response = await client.get_secret_version(request) @@ -2400,6 +2423,7 @@ async def test_get_secret_version_async( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -2781,7 +2805,9 @@ def test_disable_secret_version( ) as call: # Designate an appropriate return value for the call. call.return_value = resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) response = client.disable_secret_version(request) @@ -2794,6 +2820,7 @@ def test_disable_secret_version( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" def test_disable_secret_version_from_dict(): @@ -2836,7 +2863,9 @@ async def test_disable_secret_version_async( # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) ) response = await client.disable_secret_version(request) @@ -2850,6 +2879,7 @@ async def test_disable_secret_version_async( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -3009,7 +3039,9 @@ def test_enable_secret_version( ) as call: # Designate an appropriate return value for the call. call.return_value = resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) response = client.enable_secret_version(request) @@ -3022,6 +3054,7 @@ def test_enable_secret_version( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" def test_enable_secret_version_from_dict(): @@ -3064,7 +3097,9 @@ async def test_enable_secret_version_async( # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) ) response = await client.enable_secret_version(request) @@ -3078,6 +3113,7 @@ async def test_enable_secret_version_async( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" @pytest.mark.asyncio @@ -3237,7 +3273,9 @@ def test_destroy_secret_version( ) as call: # Designate an appropriate return value for the call. call.return_value = resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) response = client.destroy_secret_version(request) @@ -3250,6 +3288,7 @@ def test_destroy_secret_version( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" def test_destroy_secret_version_from_dict(): @@ -3292,7 +3331,9 @@ async def test_destroy_secret_version_async( # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( resources.SecretVersion( - name="name_value", state=resources.SecretVersion.State.ENABLED, + name="name_value", + state=resources.SecretVersion.State.ENABLED, + etag="etag_value", ) ) response = await client.destroy_secret_version(request) @@ -3306,6 +3347,7 @@ async def test_destroy_secret_version_async( assert isinstance(response, resources.SecretVersion) assert response.name == "name_value" assert response.state == resources.SecretVersion.State.ENABLED + assert response.etag == "etag_value" @pytest.mark.asyncio