diff --git a/.github/header-checker-lint.yml b/.github/header-checker-lint.yml
new file mode 100644
index 0000000..fc281c0
--- /dev/null
+++ b/.github/header-checker-lint.yml
@@ -0,0 +1,15 @@
+{"allowedCopyrightHolders": ["Google LLC"],
+ "allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"],
+ "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"],
+ "sourceFileExtensions": [
+ "ts",
+ "js",
+ "java",
+ "sh",
+ "Dockerfile",
+ "yaml",
+ "py",
+ "html",
+ "txt"
+ ]
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b9daa52..b4243ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,8 +50,10 @@ docs.metadata
# Virtual environment
env/
+
+# Test logs
coverage.xml
-sponge_log.xml
+*sponge_log.xml
# System test environment variables.
system_tests/local_test_setup
diff --git a/.kokoro/build.sh b/.kokoro/build.sh
index a6b7e75..ee27ebf 100755
--- a/.kokoro/build.sh
+++ b/.kokoro/build.sh
@@ -40,6 +40,16 @@ python3 -m pip uninstall --yes --quiet nox-automation
python3 -m pip install --upgrade --quiet nox
python3 -m nox --version
+# If this is a continuous build, send the test log to the FlakyBot.
+# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot.
+if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then
+ cleanup() {
+ chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot
+ $KOKORO_GFILE_DIR/linux_amd64/flakybot
+ }
+ trap cleanup EXIT HUP
+fi
+
# If NOX_SESSION is set, it only runs the specified session,
# otherwise run all the sessions.
if [[ -n "${NOX_SESSION:-}" ]]; then
diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh
index 306e9e7..30aba79 100755
--- a/.kokoro/test-samples.sh
+++ b/.kokoro/test-samples.sh
@@ -87,11 +87,11 @@ for file in samples/**/requirements.txt; do
python3.6 -m nox -s "$RUN_TESTS_SESSION"
EXIT=$?
- # If this is a periodic build, send the test log to the Build Cop Bot.
- # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/buildcop.
+ # If this is a periodic build, send the test log to the FlakyBot.
+ # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot.
if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then
- chmod +x $KOKORO_GFILE_DIR/linux_amd64/buildcop
- $KOKORO_GFILE_DIR/linux_amd64/buildcop
+ chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot
+ $KOKORO_GFILE_DIR/linux_amd64/flakybot
fi
if [[ $EXIT -ne 0 ]]; then
diff --git a/.kokoro/trampoline_v2.sh b/.kokoro/trampoline_v2.sh
index 719bcd5..4af6cdc 100755
--- a/.kokoro/trampoline_v2.sh
+++ b/.kokoro/trampoline_v2.sh
@@ -159,7 +159,7 @@ if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then
"KOKORO_GITHUB_COMMIT"
"KOKORO_GITHUB_PULL_REQUEST_NUMBER"
"KOKORO_GITHUB_PULL_REQUEST_COMMIT"
- # For Build Cop Bot
+ # For FlakyBot
"KOKORO_GITHUB_COMMIT_URL"
"KOKORO_GITHUB_PULL_REQUEST_URL"
)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b348ac..509cb89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [2.3.0](https://www.github.com/googleapis/python-secret-manager/compare/v2.2.0...v2.3.0) (2021-03-11)
+
+
+### Features
+
+* add topic field to Secret ([#80](https://www.github.com/googleapis/python-secret-manager/issues/80)) ([f83c035](https://www.github.com/googleapis/python-secret-manager/commit/f83c03517a7d32f5f53ea5511c41b855ab955eae))
+
## [2.2.0](https://www.github.com/googleapis/python-secret-manager/compare/v2.1.0...v2.2.0) (2021-01-20)
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 6000568..3e718d1 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -70,9 +70,14 @@ We use `nox `__ to instrument our tests.
- To test your changes, run unit tests with ``nox``::
$ nox -s unit-2.7
- $ nox -s unit-3.7
+ $ nox -s unit-3.8
$ ...
+- Args to pytest can be passed through the nox command separated by a `--`. For
+ example, to run a single test::
+
+ $ nox -s unit-3.8 -- -k
+
.. note::
The unit tests and system tests are described in the
@@ -93,8 +98,12 @@ On Debian/Ubuntu::
************
Coding Style
************
+- We use the automatic code formatter ``black``. You can run it using
+ the nox session ``blacken``. This will eliminate many lint errors. Run via::
+
+ $ nox -s blacken
-- PEP8 compliance, with exceptions defined in the linter configuration.
+- PEP8 compliance is required, with exceptions defined in the linter configuration.
If you have ``nox`` installed, you can test that you have not introduced
any non-compliant code via::
@@ -133,13 +142,18 @@ Running System Tests
- To run system tests, you can execute::
- $ nox -s system-3.7
+ # Run all system tests
+ $ nox -s system-3.8
$ nox -s system-2.7
+ # Run a single system test
+ $ nox -s system-3.8 -- -k
+
+
.. note::
System tests are only configured to run under Python 2.7 and
- Python 3.7. For expediency, we do not run them in older versions
+ Python 3.8. For expediency, we do not run them in older versions
of Python 3.
This alone will not run the tests. You'll need to change some local
diff --git a/MANIFEST.in b/MANIFEST.in
index e9e29d1..e783f4c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -16,10 +16,10 @@
# Generated by synthtool. DO NOT EDIT!
include README.rst LICENSE
-recursive-include google *.json *.proto
+recursive-include google *.json *.proto py.typed
recursive-include tests *
global-exclude *.py[co]
global-exclude __pycache__
# Exclude scripts for samples readmegen
-prune scripts/readme-gen
\ No newline at end of file
+prune scripts/readme-gen
diff --git a/google/cloud/secretmanager/__init__.py b/google/cloud/secretmanager/__init__.py
index 367a974..2e898cb 100644
--- a/google/cloud/secretmanager/__init__.py
+++ b/google/cloud/secretmanager/__init__.py
@@ -30,6 +30,7 @@
from google.cloud.secretmanager_v1.types.resources import Secret
from google.cloud.secretmanager_v1.types.resources import SecretPayload
from google.cloud.secretmanager_v1.types.resources import SecretVersion
+from google.cloud.secretmanager_v1.types.resources import Topic
from google.cloud.secretmanager_v1.types.service import AccessSecretVersionRequest
from google.cloud.secretmanager_v1.types.service import AccessSecretVersionResponse
from google.cloud.secretmanager_v1.types.service import AddSecretVersionRequest
@@ -70,5 +71,6 @@
"SecretManagerServiceClient",
"SecretPayload",
"SecretVersion",
+ "Topic",
"UpdateSecretRequest",
)
diff --git a/google/cloud/secretmanager_v1/__init__.py b/google/cloud/secretmanager_v1/__init__.py
index f0bc5f9..65f29c5 100644
--- a/google/cloud/secretmanager_v1/__init__.py
+++ b/google/cloud/secretmanager_v1/__init__.py
@@ -23,6 +23,7 @@
from .types.resources import Secret
from .types.resources import SecretPayload
from .types.resources import SecretVersion
+from .types.resources import Topic
from .types.service import AccessSecretVersionRequest
from .types.service import AccessSecretVersionResponse
from .types.service import AddSecretVersionRequest
@@ -62,6 +63,7 @@
"Secret",
"SecretPayload",
"SecretVersion",
+ "Topic",
"UpdateSecretRequest",
"SecretManagerServiceClient",
)
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 f0020b2..3ff45a1 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
@@ -63,6 +63,8 @@ class SecretManagerServiceAsyncClient:
parse_secret_version_path = staticmethod(
SecretManagerServiceClient.parse_secret_version_path
)
+ topic_path = staticmethod(SecretManagerServiceClient.topic_path)
+ parse_topic_path = staticmethod(SecretManagerServiceClient.parse_topic_path)
common_billing_account_path = staticmethod(
SecretManagerServiceClient.common_billing_account_path
@@ -93,8 +95,36 @@ class SecretManagerServiceAsyncClient:
SecretManagerServiceClient.parse_common_location_path
)
- from_service_account_info = SecretManagerServiceClient.from_service_account_info
- from_service_account_file = SecretManagerServiceClient.from_service_account_file
+ @classmethod
+ def from_service_account_info(cls, info: dict, *args, **kwargs):
+ """Creates an instance of this client using the provided credentials info.
+
+ Args:
+ info (dict): The service account private key info.
+ args: Additional arguments to pass to the constructor.
+ kwargs: Additional arguments to pass to the constructor.
+
+ Returns:
+ SecretManagerServiceAsyncClient: The constructed client.
+ """
+ return SecretManagerServiceClient.from_service_account_info.__func__(SecretManagerServiceAsyncClient, info, *args, **kwargs) # type: ignore
+
+ @classmethod
+ def from_service_account_file(cls, filename: str, *args, **kwargs):
+ """Creates an instance of this client using the provided credentials
+ file.
+
+ Args:
+ filename (str): The path to the service account private key json
+ file.
+ args: Additional arguments to pass to the constructor.
+ kwargs: Additional arguments to pass to the constructor.
+
+ Returns:
+ SecretManagerServiceAsyncClient: The constructed client.
+ """
+ return SecretManagerServiceClient.from_service_account_file.__func__(SecretManagerServiceAsyncClient, filename, *args, **kwargs) # type: ignore
+
from_service_account_json = from_service_account_file
@property
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 e56e5e4..a1eedea 100644
--- a/google/cloud/secretmanager_v1/services/secret_manager_service/client.py
+++ b/google/cloud/secretmanager_v1/services/secret_manager_service/client.py
@@ -199,6 +199,17 @@ def parse_secret_version_path(path: str) -> Dict[str, str]:
)
return m.groupdict() if m else {}
+ @staticmethod
+ def topic_path(project: str, topic: str,) -> str:
+ """Return a fully-qualified topic string."""
+ return "projects/{project}/topics/{topic}".format(project=project, topic=topic,)
+
+ @staticmethod
+ def parse_topic_path(path: str) -> Dict[str, str]:
+ """Parse a topic path into its component segments."""
+ m = re.match(r"^projects/(?P.+?)/topics/(?P.+?)$", path)
+ return m.groupdict() if m else {}
+
@staticmethod
def common_billing_account_path(billing_account: str,) -> str:
"""Return a fully-qualified billing_account string."""
@@ -313,21 +324,17 @@ def __init__(
util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))
)
- ssl_credentials = None
+ client_cert_source_func = None
is_mtls = False
if use_client_cert:
if client_options.client_cert_source:
- import grpc # type: ignore
-
- cert, key = client_options.client_cert_source()
- ssl_credentials = grpc.ssl_channel_credentials(
- certificate_chain=cert, private_key=key
- )
is_mtls = True
+ client_cert_source_func = client_options.client_cert_source
else:
- creds = SslCredentials()
- is_mtls = creds.is_mtls
- ssl_credentials = creds.ssl_credentials if is_mtls else None
+ is_mtls = mtls.has_default_client_cert_source()
+ client_cert_source_func = (
+ mtls.default_client_cert_source() if is_mtls else None
+ )
# Figure out which api endpoint to use.
if client_options.api_endpoint is not None:
@@ -370,7 +377,7 @@ def __init__(
credentials_file=client_options.credentials_file,
host=api_endpoint,
scopes=client_options.scopes,
- ssl_channel_credentials=ssl_credentials,
+ client_cert_source_for_mtls=client_cert_source_func,
quota_project_id=client_options.quota_project_id,
client_info=client_info,
)
@@ -1488,10 +1495,13 @@ def set_iam_policy(
"""
# Create or coerce a protobuf request object.
- # The request isn't a proto-plus wrapped type,
- # so it must be constructed via keyword expansion.
if isinstance(request, dict):
+ # The request isn't a proto-plus wrapped type,
+ # so it must be constructed via keyword expansion.
request = iam_policy.SetIamPolicyRequest(**request)
+ elif not request:
+ # Null request, just make one.
+ request = iam_policy.SetIamPolicyRequest()
# Wrap the RPC method; this adds retry and timeout information,
# and friendly error handling.
@@ -1593,10 +1603,13 @@ def get_iam_policy(
"""
# Create or coerce a protobuf request object.
- # The request isn't a proto-plus wrapped type,
- # so it must be constructed via keyword expansion.
if isinstance(request, dict):
+ # The request isn't a proto-plus wrapped type,
+ # so it must be constructed via keyword expansion.
request = iam_policy.GetIamPolicyRequest(**request)
+ elif not request:
+ # Null request, just make one.
+ request = iam_policy.GetIamPolicyRequest()
# Wrap the RPC method; this adds retry and timeout information,
# and friendly error handling.
@@ -1648,10 +1661,13 @@ def test_iam_permissions(
"""
# Create or coerce a protobuf request object.
- # The request isn't a proto-plus wrapped type,
- # so it must be constructed via keyword expansion.
if isinstance(request, dict):
+ # The request isn't a proto-plus wrapped type,
+ # so it must be constructed via keyword expansion.
request = iam_policy.TestIamPermissionsRequest(**request)
+ elif not request:
+ # Null request, just make one.
+ request = iam_policy.TestIamPermissionsRequest()
# Wrap the RPC method; this adds retry and timeout information,
# and friendly error handling.
diff --git a/google/cloud/secretmanager_v1/services/secret_manager_service/pagers.py b/google/cloud/secretmanager_v1/services/secret_manager_service/pagers.py
index db5a2a1..eda8432 100644
--- a/google/cloud/secretmanager_v1/services/secret_manager_service/pagers.py
+++ b/google/cloud/secretmanager_v1/services/secret_manager_service/pagers.py
@@ -15,7 +15,16 @@
# limitations under the License.
#
-from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple
+from typing import (
+ Any,
+ AsyncIterable,
+ Awaitable,
+ Callable,
+ Iterable,
+ Sequence,
+ Tuple,
+ Optional,
+)
from google.cloud.secretmanager_v1.types import resources
from google.cloud.secretmanager_v1.types import service
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 616cbe9..7c71715 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
@@ -67,6 +67,7 @@ def __init__(
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
+ client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id: Optional[str] = None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
@@ -97,6 +98,10 @@ def __init__(
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
+ client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
+ A callback to provide client certificate bytes and private key bytes,
+ both in PEM format. It is used to configure mutual TLS channel. It is
+ ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -113,6 +118,11 @@ def __init__(
"""
self._ssl_channel_credentials = ssl_channel_credentials
+ if api_mtls_endpoint:
+ warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
+ if client_cert_source:
+ warnings.warn("client_cert_source is deprecated", DeprecationWarning)
+
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
@@ -122,11 +132,6 @@ def __init__(
self._grpc_channel = channel
self._ssl_channel_credentials = None
elif api_mtls_endpoint:
- warnings.warn(
- "api_mtls_endpoint and client_cert_source are deprecated",
- DeprecationWarning,
- )
-
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
@@ -170,12 +175,18 @@ def __init__(
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
)
+ if client_cert_source_for_mtls and not ssl_channel_credentials:
+ cert, key = client_cert_source_for_mtls()
+ self._ssl_channel_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+
# create a new channel. The provided one is ignored.
self._grpc_channel = type(self).create_channel(
host,
credentials=credentials,
credentials_file=credentials_file,
- ssl_credentials=ssl_channel_credentials,
+ ssl_credentials=self._ssl_channel_credentials,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
options=[
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 14d7021..21bcdc7 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
@@ -111,6 +111,7 @@ def __init__(
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
+ client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id=None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
@@ -142,6 +143,10 @@ def __init__(
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
+ client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
+ A callback to provide client certificate bytes and private key bytes,
+ both in PEM format. It is used to configure mutual TLS channel. It is
+ ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -158,6 +163,11 @@ def __init__(
"""
self._ssl_channel_credentials = ssl_channel_credentials
+ if api_mtls_endpoint:
+ warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
+ if client_cert_source:
+ warnings.warn("client_cert_source is deprecated", DeprecationWarning)
+
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
@@ -167,11 +177,6 @@ def __init__(
self._grpc_channel = channel
self._ssl_channel_credentials = None
elif api_mtls_endpoint:
- warnings.warn(
- "api_mtls_endpoint and client_cert_source are deprecated",
- DeprecationWarning,
- )
-
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
@@ -215,12 +220,18 @@ def __init__(
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
)
+ if client_cert_source_for_mtls and not ssl_channel_credentials:
+ cert, key = client_cert_source_for_mtls()
+ self._ssl_channel_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+
# create a new channel. The provided one is ignored.
self._grpc_channel = type(self).create_channel(
host,
credentials=credentials,
credentials_file=credentials_file,
- ssl_credentials=ssl_channel_credentials,
+ ssl_credentials=self._ssl_channel_credentials,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
options=[
diff --git a/google/cloud/secretmanager_v1/types/__init__.py b/google/cloud/secretmanager_v1/types/__init__.py
index 3fe1200..20841fc 100644
--- a/google/cloud/secretmanager_v1/types/__init__.py
+++ b/google/cloud/secretmanager_v1/types/__init__.py
@@ -16,53 +16,55 @@
#
from .resources import (
- Secret,
- SecretVersion,
- Replication,
CustomerManagedEncryption,
- ReplicationStatus,
CustomerManagedEncryptionStatus,
+ Replication,
+ ReplicationStatus,
+ Secret,
SecretPayload,
+ SecretVersion,
+ Topic,
)
from .service import (
- ListSecretsRequest,
- ListSecretsResponse,
- CreateSecretRequest,
- AddSecretVersionRequest,
- GetSecretRequest,
- ListSecretVersionsRequest,
- ListSecretVersionsResponse,
- GetSecretVersionRequest,
- UpdateSecretRequest,
AccessSecretVersionRequest,
AccessSecretVersionResponse,
+ AddSecretVersionRequest,
+ CreateSecretRequest,
DeleteSecretRequest,
+ DestroySecretVersionRequest,
DisableSecretVersionRequest,
EnableSecretVersionRequest,
- DestroySecretVersionRequest,
+ GetSecretRequest,
+ GetSecretVersionRequest,
+ ListSecretsRequest,
+ ListSecretsResponse,
+ ListSecretVersionsRequest,
+ ListSecretVersionsResponse,
+ UpdateSecretRequest,
)
__all__ = (
- "Secret",
- "SecretVersion",
- "Replication",
"CustomerManagedEncryption",
- "ReplicationStatus",
"CustomerManagedEncryptionStatus",
+ "Replication",
+ "ReplicationStatus",
+ "Secret",
"SecretPayload",
- "ListSecretsRequest",
- "ListSecretsResponse",
- "CreateSecretRequest",
- "AddSecretVersionRequest",
- "GetSecretRequest",
- "ListSecretVersionsRequest",
- "ListSecretVersionsResponse",
- "GetSecretVersionRequest",
- "UpdateSecretRequest",
+ "SecretVersion",
+ "Topic",
"AccessSecretVersionRequest",
"AccessSecretVersionResponse",
+ "AddSecretVersionRequest",
+ "CreateSecretRequest",
"DeleteSecretRequest",
+ "DestroySecretVersionRequest",
"DisableSecretVersionRequest",
"EnableSecretVersionRequest",
- "DestroySecretVersionRequest",
+ "GetSecretRequest",
+ "GetSecretVersionRequest",
+ "ListSecretsRequest",
+ "ListSecretsResponse",
+ "ListSecretVersionsRequest",
+ "ListSecretVersionsResponse",
+ "UpdateSecretRequest",
)
diff --git a/google/cloud/secretmanager_v1/types/resources.py b/google/cloud/secretmanager_v1/types/resources.py
index 23b45cd..d782182 100644
--- a/google/cloud/secretmanager_v1/types/resources.py
+++ b/google/cloud/secretmanager_v1/types/resources.py
@@ -31,6 +31,7 @@
"CustomerManagedEncryption",
"ReplicationStatus",
"CustomerManagedEncryptionStatus",
+ "Topic",
"SecretPayload",
},
)
@@ -74,6 +75,11 @@ class Secret(proto.Message):
``[\p{Ll}\p{Lo}\p{N}_-]{0,63}``
No more than 64 labels can be assigned to a given resource.
+ topics (Sequence[google.cloud.secretmanager_v1.types.Topic]):
+ Optional. A list of up to 10 Pub/Sub topics
+ to which messages are published when control
+ plane operations are called on the secret or its
+ versions.
expire_time (google.protobuf.timestamp_pb2.Timestamp):
Optional. Timestamp in UTC when the
[Secret][google.cloud.secretmanager.v1.Secret] is scheduled
@@ -92,6 +98,8 @@ class Secret(proto.Message):
labels = proto.MapField(proto.STRING, proto.STRING, number=4)
+ topics = proto.RepeatedField(proto.MESSAGE, number=5, message="Topic",)
+
expire_time = proto.Field(
proto.MESSAGE, number=6, oneof="expiration", message=timestamp.Timestamp,
)
@@ -383,6 +391,22 @@ class CustomerManagedEncryptionStatus(proto.Message):
kms_key_version_name = proto.Field(proto.STRING, number=1)
+class Topic(proto.Message):
+ r"""A Pub/Sub topic which Secret Manager will publish to when
+ control plane events occur on this secret.
+
+ Attributes:
+ name (str):
+ Required. The resource name of the Pub/Sub topic that will
+ be published to, in the following format:
+ ``projects/*/topics/*``. For publication to succeed, the
+ Secret Manager P4SA must have ``pubsub.publisher``
+ permissions on the topic.
+ """
+
+ name = proto.Field(proto.STRING, number=1)
+
+
class SecretPayload(proto.Message):
r"""A secret payload resource in the Secret Manager API. This contains
the sensitive secret payload that is associated with a
diff --git a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/async_client.py b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/async_client.py
index 96f04dd..a0c2218 100644
--- a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/async_client.py
+++ b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/async_client.py
@@ -92,8 +92,36 @@ class SecretManagerServiceAsyncClient:
SecretManagerServiceClient.parse_common_location_path
)
- from_service_account_info = SecretManagerServiceClient.from_service_account_info
- from_service_account_file = SecretManagerServiceClient.from_service_account_file
+ @classmethod
+ def from_service_account_info(cls, info: dict, *args, **kwargs):
+ """Creates an instance of this client using the provided credentials info.
+
+ Args:
+ info (dict): The service account private key info.
+ args: Additional arguments to pass to the constructor.
+ kwargs: Additional arguments to pass to the constructor.
+
+ Returns:
+ SecretManagerServiceAsyncClient: The constructed client.
+ """
+ return SecretManagerServiceClient.from_service_account_info.__func__(SecretManagerServiceAsyncClient, info, *args, **kwargs) # type: ignore
+
+ @classmethod
+ def from_service_account_file(cls, filename: str, *args, **kwargs):
+ """Creates an instance of this client using the provided credentials
+ file.
+
+ Args:
+ filename (str): The path to the service account private key json
+ file.
+ args: Additional arguments to pass to the constructor.
+ kwargs: Additional arguments to pass to the constructor.
+
+ Returns:
+ SecretManagerServiceAsyncClient: The constructed client.
+ """
+ return SecretManagerServiceClient.from_service_account_file.__func__(SecretManagerServiceAsyncClient, filename, *args, **kwargs) # type: ignore
+
from_service_account_json = from_service_account_file
@property
diff --git a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/client.py b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/client.py
index 5d3a912..e2ff7c5 100644
--- a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/client.py
+++ b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/client.py
@@ -312,21 +312,17 @@ def __init__(
util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))
)
- ssl_credentials = None
+ client_cert_source_func = None
is_mtls = False
if use_client_cert:
if client_options.client_cert_source:
- import grpc # type: ignore
-
- cert, key = client_options.client_cert_source()
- ssl_credentials = grpc.ssl_channel_credentials(
- certificate_chain=cert, private_key=key
- )
is_mtls = True
+ client_cert_source_func = client_options.client_cert_source
else:
- creds = SslCredentials()
- is_mtls = creds.is_mtls
- ssl_credentials = creds.ssl_credentials if is_mtls else None
+ is_mtls = mtls.has_default_client_cert_source()
+ client_cert_source_func = (
+ mtls.default_client_cert_source() if is_mtls else None
+ )
# Figure out which api endpoint to use.
if client_options.api_endpoint is not None:
@@ -369,7 +365,7 @@ def __init__(
credentials_file=client_options.credentials_file,
host=api_endpoint,
scopes=client_options.scopes,
- ssl_channel_credentials=ssl_credentials,
+ client_cert_source_for_mtls=client_cert_source_func,
quota_project_id=client_options.quota_project_id,
client_info=client_info,
)
@@ -1483,10 +1479,13 @@ def set_iam_policy(
"""
# Create or coerce a protobuf request object.
- # The request isn't a proto-plus wrapped type,
- # so it must be constructed via keyword expansion.
if isinstance(request, dict):
+ # The request isn't a proto-plus wrapped type,
+ # so it must be constructed via keyword expansion.
request = iam_policy.SetIamPolicyRequest(**request)
+ elif not request:
+ # Null request, just make one.
+ request = iam_policy.SetIamPolicyRequest()
# Wrap the RPC method; this adds retry and timeout information,
# and friendly error handling.
@@ -1588,10 +1587,13 @@ def get_iam_policy(
"""
# Create or coerce a protobuf request object.
- # The request isn't a proto-plus wrapped type,
- # so it must be constructed via keyword expansion.
if isinstance(request, dict):
+ # The request isn't a proto-plus wrapped type,
+ # so it must be constructed via keyword expansion.
request = iam_policy.GetIamPolicyRequest(**request)
+ elif not request:
+ # Null request, just make one.
+ request = iam_policy.GetIamPolicyRequest()
# Wrap the RPC method; this adds retry and timeout information,
# and friendly error handling.
@@ -1643,10 +1645,13 @@ def test_iam_permissions(
"""
# Create or coerce a protobuf request object.
- # The request isn't a proto-plus wrapped type,
- # so it must be constructed via keyword expansion.
if isinstance(request, dict):
+ # The request isn't a proto-plus wrapped type,
+ # so it must be constructed via keyword expansion.
request = iam_policy.TestIamPermissionsRequest(**request)
+ elif not request:
+ # Null request, just make one.
+ request = iam_policy.TestIamPermissionsRequest()
# Wrap the RPC method; this adds retry and timeout information,
# and friendly error handling.
diff --git a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/pagers.py b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/pagers.py
index 32f4866..67d87f2 100644
--- a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/pagers.py
+++ b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/pagers.py
@@ -15,7 +15,16 @@
# limitations under the License.
#
-from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple
+from typing import (
+ Any,
+ AsyncIterable,
+ Awaitable,
+ Callable,
+ Iterable,
+ Sequence,
+ Tuple,
+ Optional,
+)
from google.cloud.secretmanager_v1beta1.types import resources
from google.cloud.secretmanager_v1beta1.types import service
diff --git a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc.py b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc.py
index e8ff977..3f82138 100644
--- a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc.py
+++ b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc.py
@@ -67,6 +67,7 @@ def __init__(
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
+ client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id: Optional[str] = None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
@@ -97,6 +98,10 @@ def __init__(
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
+ client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
+ A callback to provide client certificate bytes and private key bytes,
+ both in PEM format. It is used to configure mutual TLS channel. It is
+ ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -113,6 +118,11 @@ def __init__(
"""
self._ssl_channel_credentials = ssl_channel_credentials
+ if api_mtls_endpoint:
+ warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
+ if client_cert_source:
+ warnings.warn("client_cert_source is deprecated", DeprecationWarning)
+
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
@@ -122,11 +132,6 @@ def __init__(
self._grpc_channel = channel
self._ssl_channel_credentials = None
elif api_mtls_endpoint:
- warnings.warn(
- "api_mtls_endpoint and client_cert_source are deprecated",
- DeprecationWarning,
- )
-
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
@@ -170,12 +175,18 @@ def __init__(
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
)
+ if client_cert_source_for_mtls and not ssl_channel_credentials:
+ cert, key = client_cert_source_for_mtls()
+ self._ssl_channel_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+
# create a new channel. The provided one is ignored.
self._grpc_channel = type(self).create_channel(
host,
credentials=credentials,
credentials_file=credentials_file,
- ssl_credentials=ssl_channel_credentials,
+ ssl_credentials=self._ssl_channel_credentials,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
options=[
diff --git a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc_asyncio.py b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc_asyncio.py
index c9a76ec..c525386 100644
--- a/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc_asyncio.py
+++ b/google/cloud/secretmanager_v1beta1/services/secret_manager_service/transports/grpc_asyncio.py
@@ -111,6 +111,7 @@ def __init__(
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
ssl_channel_credentials: grpc.ChannelCredentials = None,
+ client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
quota_project_id=None,
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
@@ -142,6 +143,10 @@ def __init__(
``api_mtls_endpoint`` is None.
ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials
for grpc channel. It is ignored if ``channel`` is provided.
+ client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]):
+ A callback to provide client certificate bytes and private key bytes,
+ both in PEM format. It is used to configure mutual TLS channel. It is
+ ignored if ``channel`` or ``ssl_channel_credentials`` is provided.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
@@ -158,6 +163,11 @@ def __init__(
"""
self._ssl_channel_credentials = ssl_channel_credentials
+ if api_mtls_endpoint:
+ warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning)
+ if client_cert_source:
+ warnings.warn("client_cert_source is deprecated", DeprecationWarning)
+
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
@@ -167,11 +177,6 @@ def __init__(
self._grpc_channel = channel
self._ssl_channel_credentials = None
elif api_mtls_endpoint:
- warnings.warn(
- "api_mtls_endpoint and client_cert_source are deprecated",
- DeprecationWarning,
- )
-
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
@@ -215,12 +220,18 @@ def __init__(
scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
)
+ if client_cert_source_for_mtls and not ssl_channel_credentials:
+ cert, key = client_cert_source_for_mtls()
+ self._ssl_channel_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+
# create a new channel. The provided one is ignored.
self._grpc_channel = type(self).create_channel(
host,
credentials=credentials,
credentials_file=credentials_file,
- ssl_credentials=ssl_channel_credentials,
+ ssl_credentials=self._ssl_channel_credentials,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
options=[
diff --git a/google/cloud/secretmanager_v1beta1/types/__init__.py b/google/cloud/secretmanager_v1beta1/types/__init__.py
index c287f6d..8cce13e 100644
--- a/google/cloud/secretmanager_v1beta1/types/__init__.py
+++ b/google/cloud/secretmanager_v1beta1/types/__init__.py
@@ -16,47 +16,47 @@
#
from .resources import (
- Secret,
- SecretVersion,
Replication,
+ Secret,
SecretPayload,
+ SecretVersion,
)
from .service import (
- ListSecretsRequest,
- ListSecretsResponse,
- CreateSecretRequest,
- AddSecretVersionRequest,
- GetSecretRequest,
- ListSecretVersionsRequest,
- ListSecretVersionsResponse,
- GetSecretVersionRequest,
- UpdateSecretRequest,
AccessSecretVersionRequest,
AccessSecretVersionResponse,
+ AddSecretVersionRequest,
+ CreateSecretRequest,
DeleteSecretRequest,
+ DestroySecretVersionRequest,
DisableSecretVersionRequest,
EnableSecretVersionRequest,
- DestroySecretVersionRequest,
+ GetSecretRequest,
+ GetSecretVersionRequest,
+ ListSecretsRequest,
+ ListSecretsResponse,
+ ListSecretVersionsRequest,
+ ListSecretVersionsResponse,
+ UpdateSecretRequest,
)
__all__ = (
- "Secret",
- "SecretVersion",
"Replication",
+ "Secret",
"SecretPayload",
- "ListSecretsRequest",
- "ListSecretsResponse",
- "CreateSecretRequest",
- "AddSecretVersionRequest",
- "GetSecretRequest",
- "ListSecretVersionsRequest",
- "ListSecretVersionsResponse",
- "GetSecretVersionRequest",
- "UpdateSecretRequest",
+ "SecretVersion",
"AccessSecretVersionRequest",
"AccessSecretVersionResponse",
+ "AddSecretVersionRequest",
+ "CreateSecretRequest",
"DeleteSecretRequest",
+ "DestroySecretVersionRequest",
"DisableSecretVersionRequest",
"EnableSecretVersionRequest",
- "DestroySecretVersionRequest",
+ "GetSecretRequest",
+ "GetSecretVersionRequest",
+ "ListSecretsRequest",
+ "ListSecretsResponse",
+ "ListSecretVersionsRequest",
+ "ListSecretVersionsResponse",
+ "UpdateSecretRequest",
)
diff --git a/noxfile.py b/noxfile.py
index 32a8bcf..71ef308 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -86,12 +86,14 @@ def default(session):
session.install(
"mock", "pytest", "pytest-cov",
)
+
session.install("-e", ".")
# Run py.test against the unit tests.
session.run(
"py.test",
"--quiet",
+ f"--junitxml=unit_{session.python}_sponge_log.xml",
"--cov=google/cloud",
"--cov=tests/unit",
"--cov-append",
@@ -121,6 +123,9 @@ def system(session):
# Sanity check: Only run tests if the environment variable is set.
if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""):
session.skip("Credentials must be set via environment variable")
+ # Install pyopenssl for mTLS testing.
+ if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true":
+ session.install("pyopenssl")
system_test_exists = os.path.exists(system_test_path)
system_test_folder_exists = os.path.exists(system_test_folder_path)
@@ -140,9 +145,21 @@ def system(session):
# Run py.test against the system tests.
if system_test_exists:
- session.run("py.test", "--quiet", system_test_path, *session.posargs)
+ session.run(
+ "py.test",
+ "--quiet",
+ f"--junitxml=system_{session.python}_sponge_log.xml",
+ system_test_path,
+ *session.posargs,
+ )
if system_test_folder_exists:
- session.run("py.test", "--quiet", system_test_folder_path, *session.posargs)
+ session.run(
+ "py.test",
+ "--quiet",
+ f"--junitxml=system_{session.python}_sponge_log.xml",
+ system_test_folder_path,
+ *session.posargs,
+ )
@nox.session(python=DEFAULT_PYTHON_VERSION)
diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt
index eb838b6..ec14fe0 100644
--- a/samples/snippets/requirements.txt
+++ b/samples/snippets/requirements.txt
@@ -1 +1 @@
-google-cloud-secret-manager==2.1.0
\ No newline at end of file
+google-cloud-secret-manager==2.2.0
\ No newline at end of file
diff --git a/secretmanager-v1beta1-py.tar.gz b/secretmanager-v1beta1-py.tar.gz
new file mode 100644
index 0000000..e69de29
diff --git a/setup.py b/setup.py
index a20d264..b53b349 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@
name = "google-cloud-secret-manager"
description = "Secret Manager API API client library"
-version = "2.2.0"
+version = "2.3.0"
release_status = "Development Status :: 5 - Production/Stable"
dependencies = [
"google-api-core[grpc] >= 1.22.2, < 2.0.0dev",
diff --git a/synth.metadata b/synth.metadata
index c78eabd..45c7174 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -4,29 +4,29 @@
"git": {
"name": ".",
"remote": "https://github.com/googleapis/python-secret-manager.git",
- "sha": "9a2eef65040dbe52d2b23db02640d113c26e1297"
+ "sha": "0e29327d99f9774e6b7a942d8ba462d007b68bd4"
}
},
{
"git": {
"name": "googleapis",
"remote": "https://github.com/googleapis/googleapis.git",
- "sha": "9ecdacc9a00e1dd443b11bf10215d6e7648db8a7",
- "internalRef": "352563582"
+ "sha": "28a591963253d52ce3a25a918cafbdd9928de8cf",
+ "internalRef": "361662015"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "ba960d730416fe05c50547e975ce79fcee52c671"
+ "sha": "0780323da96d5a53925fe0547757181fe76e8f1e"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "ba960d730416fe05c50547e975ce79fcee52c671"
+ "sha": "0780323da96d5a53925fe0547757181fe76e8f1e"
}
}
],
@@ -58,6 +58,7 @@
".github/ISSUE_TEMPLATE/feature_request.md",
".github/ISSUE_TEMPLATE/support_request.md",
".github/PULL_REQUEST_TEMPLATE.md",
+ ".github/header-checker-lint.yml",
".github/release-please.yml",
".github/snippet-bot.yml",
".gitignore",
@@ -156,6 +157,7 @@
"scripts/readme-gen/templates/auth_api_key.tmpl.rst",
"scripts/readme-gen/templates/install_deps.tmpl.rst",
"scripts/readme-gen/templates/install_portaudio.tmpl.rst",
+ "secretmanager-v1beta1-py.tar.gz",
"setup.cfg",
"testing/.gitignore",
"tests/unit/gapic/secretmanager_v1/__init__.py",
diff --git a/testing/constraints-3.10.txt b/testing/constraints-3.10.txt
new file mode 100644
index 0000000..e69de29
diff --git a/testing/constraints-3.11.txt b/testing/constraints-3.11.txt
new file mode 100644
index 0000000..e69de29
diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt
new file mode 100644
index 0000000..23330fd
--- /dev/null
+++ b/testing/constraints-3.6.txt
@@ -0,0 +1,11 @@
+# This constraints file is used to check that lower bounds
+# are correct in setup.py
+# List *all* library dependencies and extras in this file.
+# Pin the version to the lower bound.
+#
+# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev",
+# Then this file should have foo==1.14.0
+google-api-core==1.22.2
+grpc-google-iam-v1==0.12.3
+proto-plus==1.4.0
+libcst==0.2.5
\ No newline at end of file
diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt
new file mode 100644
index 0000000..e69de29
diff --git a/testing/constraints-3.8.txt b/testing/constraints-3.8.txt
new file mode 100644
index 0000000..e69de29
diff --git a/testing/constraints-3.9.txt b/testing/constraints-3.9.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit/gapic/secretmanager_v1/__init__.py b/tests/unit/gapic/secretmanager_v1/__init__.py
index 8b13789..42ffdf2 100644
--- a/tests/unit/gapic/secretmanager_v1/__init__.py
+++ b/tests/unit/gapic/secretmanager_v1/__init__.py
@@ -1 +1,16 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
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 f01241a..f884c30 100644
--- a/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py
+++ b/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py
@@ -97,15 +97,19 @@ def test__get_default_mtls_endpoint():
)
-def test_secret_manager_service_client_from_service_account_info():
+@pytest.mark.parametrize(
+ "client_class", [SecretManagerServiceClient, SecretManagerServiceAsyncClient,]
+)
+def test_secret_manager_service_client_from_service_account_info(client_class):
creds = credentials.AnonymousCredentials()
with mock.patch.object(
service_account.Credentials, "from_service_account_info"
) as factory:
factory.return_value = creds
info = {"valid": True}
- client = SecretManagerServiceClient.from_service_account_info(info)
+ client = client_class.from_service_account_info(info)
assert client.transport._credentials == creds
+ assert isinstance(client, client_class)
assert client.transport._host == "secretmanager.googleapis.com:443"
@@ -121,9 +125,11 @@ def test_secret_manager_service_client_from_service_account_file(client_class):
factory.return_value = creds
client = client_class.from_service_account_file("dummy/file/path.json")
assert client.transport._credentials == creds
+ assert isinstance(client, client_class)
client = client_class.from_service_account_json("dummy/file/path.json")
assert client.transport._credentials == creds
+ assert isinstance(client, client_class)
assert client.transport._host == "secretmanager.googleapis.com:443"
@@ -188,7 +194,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -204,7 +210,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -220,7 +226,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -248,7 +254,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id="octopus",
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -309,29 +315,25 @@ def test_secret_manager_service_client_mtls_env_auto(
client_cert_source=client_cert_source_callback
)
with mock.patch.object(transport_class, "__init__") as patched:
- ssl_channel_creds = mock.Mock()
- with mock.patch(
- "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
- ):
- patched.return_value = None
- client = client_class(client_options=options)
+ patched.return_value = None
+ client = client_class(client_options=options)
- if use_client_cert_env == "false":
- expected_ssl_channel_creds = None
- expected_host = client.DEFAULT_ENDPOINT
- else:
- expected_ssl_channel_creds = ssl_channel_creds
- expected_host = client.DEFAULT_MTLS_ENDPOINT
+ if use_client_cert_env == "false":
+ expected_client_cert_source = None
+ expected_host = client.DEFAULT_ENDPOINT
+ else:
+ expected_client_cert_source = client_cert_source_callback
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=expected_host,
+ scopes=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
# Check the case ADC client cert is provided. Whether client cert is used depends on
# GOOGLE_API_USE_CLIENT_CERTIFICATE value.
@@ -340,66 +342,53 @@ def test_secret_manager_service_client_mtls_env_auto(
):
with mock.patch.object(transport_class, "__init__") as patched:
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=True,
):
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.ssl_credentials",
- new_callable=mock.PropertyMock,
- ) as ssl_credentials_mock:
- if use_client_cert_env == "false":
- is_mtls_mock.return_value = False
- ssl_credentials_mock.return_value = None
- expected_host = client.DEFAULT_ENDPOINT
- expected_ssl_channel_creds = None
- else:
- is_mtls_mock.return_value = True
- ssl_credentials_mock.return_value = mock.Mock()
- expected_host = client.DEFAULT_MTLS_ENDPOINT
- expected_ssl_channel_creds = (
- ssl_credentials_mock.return_value
- )
-
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ "google.auth.transport.mtls.default_client_cert_source",
+ return_value=client_cert_source_callback,
+ ):
+ if use_client_cert_env == "false":
+ expected_host = client.DEFAULT_ENDPOINT
+ expected_client_cert_source = None
+ else:
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
+ expected_client_cert_source = client_cert_source_callback
- # Check the case client_cert_source and ADC client cert are not provided.
- with mock.patch.dict(
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
- ):
- with mock.patch.object(transport_class, "__init__") as patched:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
- ):
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- is_mtls_mock.return_value = False
patched.return_value = None
client = client_class()
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
+ host=expected_host,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
+ # Check the case client_cert_source and ADC client cert are not provided.
+ with mock.patch.dict(
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
+ ):
+ with mock.patch.object(transport_class, "__init__") as patched:
+ with mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=False,
+ ):
+ patched.return_value = None
+ client = client_class()
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=client.DEFAULT_ENDPOINT,
+ scopes=None,
+ client_cert_source_for_mtls=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
+
@pytest.mark.parametrize(
"client_class,transport_class,transport_name",
@@ -429,7 +418,7 @@ def test_secret_manager_service_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -463,7 +452,7 @@ def test_secret_manager_service_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -482,7 +471,7 @@ def test_secret_manager_service_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -525,6 +514,22 @@ def test_list_secrets_from_dict():
test_list_secrets(request_type=dict)
+def test_list_secrets_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.list_secrets), "__call__") as call:
+ client.list_secrets()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.ListSecretsRequest()
+
+
@pytest.mark.asyncio
async def test_list_secrets_async(
transport: str = "grpc_asyncio", request_type=service.ListSecretsRequest
@@ -854,6 +859,22 @@ def test_create_secret_from_dict():
test_create_secret(request_type=dict)
+def test_create_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.create_secret), "__call__") as call:
+ client.create_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.CreateSecretRequest()
+
+
@pytest.mark.asyncio
async def test_create_secret_async(
transport: str = "grpc_asyncio", request_type=service.CreateSecretRequest
@@ -1075,6 +1096,24 @@ def test_add_secret_version_from_dict():
test_add_secret_version(request_type=dict)
+def test_add_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.add_secret_version), "__call__"
+ ) as call:
+ client.add_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.AddSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_add_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.AddSecretVersionRequest
@@ -1298,6 +1337,22 @@ def test_get_secret_from_dict():
test_get_secret(request_type=dict)
+def test_get_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.get_secret), "__call__") as call:
+ client.get_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.GetSecretRequest()
+
+
@pytest.mark.asyncio
async def test_get_secret_async(
transport: str = "grpc_asyncio", request_type=service.GetSecretRequest
@@ -1493,6 +1548,22 @@ def test_update_secret_from_dict():
test_update_secret(request_type=dict)
+def test_update_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.update_secret), "__call__") as call:
+ client.update_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.UpdateSecretRequest()
+
+
@pytest.mark.asyncio
async def test_update_secret_async(
transport: str = "grpc_asyncio", request_type=service.UpdateSecretRequest
@@ -1697,6 +1768,22 @@ def test_delete_secret_from_dict():
test_delete_secret(request_type=dict)
+def test_delete_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.delete_secret), "__call__") as call:
+ client.delete_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.DeleteSecretRequest()
+
+
@pytest.mark.asyncio
async def test_delete_secret_async(
transport: str = "grpc_asyncio", request_type=service.DeleteSecretRequest
@@ -1892,6 +1979,24 @@ def test_list_secret_versions_from_dict():
test_list_secret_versions(request_type=dict)
+def test_list_secret_versions_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.list_secret_versions), "__call__"
+ ) as call:
+ client.list_secret_versions()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.ListSecretVersionsRequest()
+
+
@pytest.mark.asyncio
async def test_list_secret_versions_async(
transport: str = "grpc_asyncio", request_type=service.ListSecretVersionsRequest
@@ -2259,6 +2364,24 @@ def test_get_secret_version_from_dict():
test_get_secret_version(request_type=dict)
+def test_get_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.get_secret_version), "__call__"
+ ) as call:
+ client.get_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.GetSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_get_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.GetSecretVersionRequest
@@ -2472,6 +2595,24 @@ def test_access_secret_version_from_dict():
test_access_secret_version(request_type=dict)
+def test_access_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.access_secret_version), "__call__"
+ ) as call:
+ client.access_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.AccessSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_access_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.AccessSecretVersionRequest
@@ -2685,6 +2826,24 @@ def test_disable_secret_version_from_dict():
test_disable_secret_version(request_type=dict)
+def test_disable_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.disable_secret_version), "__call__"
+ ) as call:
+ client.disable_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.DisableSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_disable_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.DisableSecretVersionRequest
@@ -2902,6 +3061,24 @@ def test_enable_secret_version_from_dict():
test_enable_secret_version(request_type=dict)
+def test_enable_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.enable_secret_version), "__call__"
+ ) as call:
+ client.enable_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.EnableSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_enable_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.EnableSecretVersionRequest
@@ -3119,6 +3296,24 @@ def test_destroy_secret_version_from_dict():
test_destroy_secret_version(request_type=dict)
+def test_destroy_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.destroy_secret_version), "__call__"
+ ) as call:
+ client.destroy_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.DestroySecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_destroy_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.DestroySecretVersionRequest
@@ -3332,6 +3527,22 @@ def test_set_iam_policy_from_dict():
test_set_iam_policy(request_type=dict)
+def test_set_iam_policy_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call:
+ client.set_iam_policy()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == iam_policy.SetIamPolicyRequest()
+
+
@pytest.mark.asyncio
async def test_set_iam_policy_async(
transport: str = "grpc_asyncio", request_type=iam_policy.SetIamPolicyRequest
@@ -3476,6 +3687,22 @@ def test_get_iam_policy_from_dict():
test_get_iam_policy(request_type=dict)
+def test_get_iam_policy_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call:
+ client.get_iam_policy()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == iam_policy.GetIamPolicyRequest()
+
+
@pytest.mark.asyncio
async def test_get_iam_policy_async(
transport: str = "grpc_asyncio", request_type=iam_policy.GetIamPolicyRequest
@@ -3622,6 +3849,24 @@ def test_test_iam_permissions_from_dict():
test_test_iam_permissions(request_type=dict)
+def test_test_iam_permissions_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.test_iam_permissions), "__call__"
+ ) as call:
+ client.test_iam_permissions()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == iam_policy.TestIamPermissionsRequest()
+
+
@pytest.mark.asyncio
async def test_test_iam_permissions_async(
transport: str = "grpc_asyncio", request_type=iam_policy.TestIamPermissionsRequest
@@ -3910,6 +4155,53 @@ def test_secret_manager_service_transport_auth_adc():
)
+@pytest.mark.parametrize(
+ "transport_class",
+ [
+ transports.SecretManagerServiceGrpcTransport,
+ transports.SecretManagerServiceGrpcAsyncIOTransport,
+ ],
+)
+def test_secret_manager_service_grpc_transport_client_cert_source_for_mtls(
+ transport_class,
+):
+ cred = credentials.AnonymousCredentials()
+
+ # Check ssl_channel_credentials is used if provided.
+ with mock.patch.object(transport_class, "create_channel") as mock_create_channel:
+ mock_ssl_channel_creds = mock.Mock()
+ transport_class(
+ host="squid.clam.whelk",
+ credentials=cred,
+ ssl_channel_credentials=mock_ssl_channel_creds,
+ )
+ mock_create_channel.assert_called_once_with(
+ "squid.clam.whelk:443",
+ credentials=cred,
+ credentials_file=None,
+ scopes=("https://www.googleapis.com/auth/cloud-platform",),
+ ssl_credentials=mock_ssl_channel_creds,
+ quota_project_id=None,
+ options=[
+ ("grpc.max_send_message_length", -1),
+ ("grpc.max_receive_message_length", -1),
+ ],
+ )
+
+ # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls
+ # is used.
+ with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()):
+ with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred:
+ transport_class(
+ credentials=cred,
+ client_cert_source_for_mtls=client_cert_source_callback,
+ )
+ expected_cert, expected_key = client_cert_source_callback()
+ mock_ssl_cred.assert_called_once_with(
+ certificate_chain=expected_cert, private_key=expected_key
+ )
+
+
def test_secret_manager_service_host_no_port():
client = SecretManagerServiceClient(
credentials=credentials.AnonymousCredentials(),
@@ -3954,6 +4246,8 @@ def test_secret_manager_service_grpc_asyncio_transport_channel():
assert transport._ssl_channel_credentials == None
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[
@@ -4006,6 +4300,8 @@ def test_secret_manager_service_transport_channel_mtls_with_client_cert_source(
assert transport._ssl_channel_credentials == mock_ssl_cred
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[
@@ -4100,8 +4396,29 @@ def test_parse_secret_version_path():
assert expected == actual
+def test_topic_path():
+ project = "scallop"
+ topic = "abalone"
+
+ expected = "projects/{project}/topics/{topic}".format(project=project, topic=topic,)
+ actual = SecretManagerServiceClient.topic_path(project, topic)
+ assert expected == actual
+
+
+def test_parse_topic_path():
+ expected = {
+ "project": "squid",
+ "topic": "clam",
+ }
+ path = SecretManagerServiceClient.topic_path(**expected)
+
+ # Check that the path construction is reversible.
+ actual = SecretManagerServiceClient.parse_topic_path(path)
+ assert expected == actual
+
+
def test_common_billing_account_path():
- billing_account = "scallop"
+ billing_account = "whelk"
expected = "billingAccounts/{billing_account}".format(
billing_account=billing_account,
@@ -4112,7 +4429,7 @@ def test_common_billing_account_path():
def test_parse_common_billing_account_path():
expected = {
- "billing_account": "abalone",
+ "billing_account": "octopus",
}
path = SecretManagerServiceClient.common_billing_account_path(**expected)
@@ -4122,7 +4439,7 @@ def test_parse_common_billing_account_path():
def test_common_folder_path():
- folder = "squid"
+ folder = "oyster"
expected = "folders/{folder}".format(folder=folder,)
actual = SecretManagerServiceClient.common_folder_path(folder)
@@ -4131,7 +4448,7 @@ def test_common_folder_path():
def test_parse_common_folder_path():
expected = {
- "folder": "clam",
+ "folder": "nudibranch",
}
path = SecretManagerServiceClient.common_folder_path(**expected)
@@ -4141,7 +4458,7 @@ def test_parse_common_folder_path():
def test_common_organization_path():
- organization = "whelk"
+ organization = "cuttlefish"
expected = "organizations/{organization}".format(organization=organization,)
actual = SecretManagerServiceClient.common_organization_path(organization)
@@ -4150,7 +4467,7 @@ def test_common_organization_path():
def test_parse_common_organization_path():
expected = {
- "organization": "octopus",
+ "organization": "mussel",
}
path = SecretManagerServiceClient.common_organization_path(**expected)
@@ -4160,7 +4477,7 @@ def test_parse_common_organization_path():
def test_common_project_path():
- project = "oyster"
+ project = "winkle"
expected = "projects/{project}".format(project=project,)
actual = SecretManagerServiceClient.common_project_path(project)
@@ -4169,7 +4486,7 @@ def test_common_project_path():
def test_parse_common_project_path():
expected = {
- "project": "nudibranch",
+ "project": "nautilus",
}
path = SecretManagerServiceClient.common_project_path(**expected)
@@ -4179,8 +4496,8 @@ def test_parse_common_project_path():
def test_common_location_path():
- project = "cuttlefish"
- location = "mussel"
+ project = "scallop"
+ location = "abalone"
expected = "projects/{project}/locations/{location}".format(
project=project, location=location,
@@ -4191,8 +4508,8 @@ def test_common_location_path():
def test_parse_common_location_path():
expected = {
- "project": "winkle",
- "location": "nautilus",
+ "project": "squid",
+ "location": "clam",
}
path = SecretManagerServiceClient.common_location_path(**expected)
diff --git a/tests/unit/gapic/secretmanager_v1beta1/__init__.py b/tests/unit/gapic/secretmanager_v1beta1/__init__.py
index 8b13789..42ffdf2 100644
--- a/tests/unit/gapic/secretmanager_v1beta1/__init__.py
+++ b/tests/unit/gapic/secretmanager_v1beta1/__init__.py
@@ -1 +1,16 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
diff --git a/tests/unit/gapic/secretmanager_v1beta1/test_secret_manager_service.py b/tests/unit/gapic/secretmanager_v1beta1/test_secret_manager_service.py
index 64bc147..a096d89 100644
--- a/tests/unit/gapic/secretmanager_v1beta1/test_secret_manager_service.py
+++ b/tests/unit/gapic/secretmanager_v1beta1/test_secret_manager_service.py
@@ -98,15 +98,19 @@ def test__get_default_mtls_endpoint():
)
-def test_secret_manager_service_client_from_service_account_info():
+@pytest.mark.parametrize(
+ "client_class", [SecretManagerServiceClient, SecretManagerServiceAsyncClient,]
+)
+def test_secret_manager_service_client_from_service_account_info(client_class):
creds = credentials.AnonymousCredentials()
with mock.patch.object(
service_account.Credentials, "from_service_account_info"
) as factory:
factory.return_value = creds
info = {"valid": True}
- client = SecretManagerServiceClient.from_service_account_info(info)
+ client = client_class.from_service_account_info(info)
assert client.transport._credentials == creds
+ assert isinstance(client, client_class)
assert client.transport._host == "secretmanager.googleapis.com:443"
@@ -122,9 +126,11 @@ def test_secret_manager_service_client_from_service_account_file(client_class):
factory.return_value = creds
client = client_class.from_service_account_file("dummy/file/path.json")
assert client.transport._credentials == creds
+ assert isinstance(client, client_class)
client = client_class.from_service_account_json("dummy/file/path.json")
assert client.transport._credentials == creds
+ assert isinstance(client, client_class)
assert client.transport._host == "secretmanager.googleapis.com:443"
@@ -189,7 +195,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -205,7 +211,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -221,7 +227,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -249,7 +255,7 @@ def test_secret_manager_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id="octopus",
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -310,29 +316,25 @@ def test_secret_manager_service_client_mtls_env_auto(
client_cert_source=client_cert_source_callback
)
with mock.patch.object(transport_class, "__init__") as patched:
- ssl_channel_creds = mock.Mock()
- with mock.patch(
- "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
- ):
- patched.return_value = None
- client = client_class(client_options=options)
+ patched.return_value = None
+ client = client_class(client_options=options)
- if use_client_cert_env == "false":
- expected_ssl_channel_creds = None
- expected_host = client.DEFAULT_ENDPOINT
- else:
- expected_ssl_channel_creds = ssl_channel_creds
- expected_host = client.DEFAULT_MTLS_ENDPOINT
+ if use_client_cert_env == "false":
+ expected_client_cert_source = None
+ expected_host = client.DEFAULT_ENDPOINT
+ else:
+ expected_client_cert_source = client_cert_source_callback
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=expected_host,
+ scopes=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
# Check the case ADC client cert is provided. Whether client cert is used depends on
# GOOGLE_API_USE_CLIENT_CERTIFICATE value.
@@ -341,66 +343,53 @@ def test_secret_manager_service_client_mtls_env_auto(
):
with mock.patch.object(transport_class, "__init__") as patched:
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=True,
):
with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.ssl_credentials",
- new_callable=mock.PropertyMock,
- ) as ssl_credentials_mock:
- if use_client_cert_env == "false":
- is_mtls_mock.return_value = False
- ssl_credentials_mock.return_value = None
- expected_host = client.DEFAULT_ENDPOINT
- expected_ssl_channel_creds = None
- else:
- is_mtls_mock.return_value = True
- ssl_credentials_mock.return_value = mock.Mock()
- expected_host = client.DEFAULT_MTLS_ENDPOINT
- expected_ssl_channel_creds = (
- ssl_credentials_mock.return_value
- )
-
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=expected_host,
- scopes=None,
- ssl_channel_credentials=expected_ssl_channel_creds,
- quota_project_id=None,
- client_info=transports.base.DEFAULT_CLIENT_INFO,
- )
+ "google.auth.transport.mtls.default_client_cert_source",
+ return_value=client_cert_source_callback,
+ ):
+ if use_client_cert_env == "false":
+ expected_host = client.DEFAULT_ENDPOINT
+ expected_client_cert_source = None
+ else:
+ expected_host = client.DEFAULT_MTLS_ENDPOINT
+ expected_client_cert_source = client_cert_source_callback
- # Check the case client_cert_source and ADC client cert are not provided.
- with mock.patch.dict(
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
- ):
- with mock.patch.object(transport_class, "__init__") as patched:
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
- ):
- with mock.patch(
- "google.auth.transport.grpc.SslCredentials.is_mtls",
- new_callable=mock.PropertyMock,
- ) as is_mtls_mock:
- is_mtls_mock.return_value = False
patched.return_value = None
client = client_class()
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
+ host=expected_host,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=expected_client_cert_source,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
+ # Check the case client_cert_source and ADC client cert are not provided.
+ with mock.patch.dict(
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env}
+ ):
+ with mock.patch.object(transport_class, "__init__") as patched:
+ with mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
+ return_value=False,
+ ):
+ patched.return_value = None
+ client = client_class()
+ patched.assert_called_once_with(
+ credentials=None,
+ credentials_file=None,
+ host=client.DEFAULT_ENDPOINT,
+ scopes=None,
+ client_cert_source_for_mtls=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
+
@pytest.mark.parametrize(
"client_class,transport_class,transport_name",
@@ -430,7 +419,7 @@ def test_secret_manager_service_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -464,7 +453,7 @@ def test_secret_manager_service_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -483,7 +472,7 @@ def test_secret_manager_service_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- ssl_channel_credentials=None,
+ client_cert_source_for_mtls=None,
quota_project_id=None,
client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -526,6 +515,22 @@ def test_list_secrets_from_dict():
test_list_secrets(request_type=dict)
+def test_list_secrets_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.list_secrets), "__call__") as call:
+ client.list_secrets()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.ListSecretsRequest()
+
+
@pytest.mark.asyncio
async def test_list_secrets_async(
transport: str = "grpc_asyncio", request_type=service.ListSecretsRequest
@@ -853,6 +858,22 @@ def test_create_secret_from_dict():
test_create_secret(request_type=dict)
+def test_create_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.create_secret), "__call__") as call:
+ client.create_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.CreateSecretRequest()
+
+
@pytest.mark.asyncio
async def test_create_secret_async(
transport: str = "grpc_asyncio", request_type=service.CreateSecretRequest
@@ -1074,6 +1095,24 @@ def test_add_secret_version_from_dict():
test_add_secret_version(request_type=dict)
+def test_add_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.add_secret_version), "__call__"
+ ) as call:
+ client.add_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.AddSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_add_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.AddSecretVersionRequest
@@ -1295,6 +1334,22 @@ def test_get_secret_from_dict():
test_get_secret(request_type=dict)
+def test_get_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.get_secret), "__call__") as call:
+ client.get_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.GetSecretRequest()
+
+
@pytest.mark.asyncio
async def test_get_secret_async(
transport: str = "grpc_asyncio", request_type=service.GetSecretRequest
@@ -1488,6 +1543,22 @@ def test_update_secret_from_dict():
test_update_secret(request_type=dict)
+def test_update_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.update_secret), "__call__") as call:
+ client.update_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.UpdateSecretRequest()
+
+
@pytest.mark.asyncio
async def test_update_secret_async(
transport: str = "grpc_asyncio", request_type=service.UpdateSecretRequest
@@ -1692,6 +1763,22 @@ def test_delete_secret_from_dict():
test_delete_secret(request_type=dict)
+def test_delete_secret_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.delete_secret), "__call__") as call:
+ client.delete_secret()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.DeleteSecretRequest()
+
+
@pytest.mark.asyncio
async def test_delete_secret_async(
transport: str = "grpc_asyncio", request_type=service.DeleteSecretRequest
@@ -1887,6 +1974,24 @@ def test_list_secret_versions_from_dict():
test_list_secret_versions(request_type=dict)
+def test_list_secret_versions_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.list_secret_versions), "__call__"
+ ) as call:
+ client.list_secret_versions()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.ListSecretVersionsRequest()
+
+
@pytest.mark.asyncio
async def test_list_secret_versions_async(
transport: str = "grpc_asyncio", request_type=service.ListSecretVersionsRequest
@@ -2254,6 +2359,24 @@ def test_get_secret_version_from_dict():
test_get_secret_version(request_type=dict)
+def test_get_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.get_secret_version), "__call__"
+ ) as call:
+ client.get_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.GetSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_get_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.GetSecretVersionRequest
@@ -2467,6 +2590,24 @@ def test_access_secret_version_from_dict():
test_access_secret_version(request_type=dict)
+def test_access_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.access_secret_version), "__call__"
+ ) as call:
+ client.access_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.AccessSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_access_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.AccessSecretVersionRequest
@@ -2680,6 +2821,24 @@ def test_disable_secret_version_from_dict():
test_disable_secret_version(request_type=dict)
+def test_disable_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.disable_secret_version), "__call__"
+ ) as call:
+ client.disable_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.DisableSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_disable_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.DisableSecretVersionRequest
@@ -2897,6 +3056,24 @@ def test_enable_secret_version_from_dict():
test_enable_secret_version(request_type=dict)
+def test_enable_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.enable_secret_version), "__call__"
+ ) as call:
+ client.enable_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.EnableSecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_enable_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.EnableSecretVersionRequest
@@ -3114,6 +3291,24 @@ def test_destroy_secret_version_from_dict():
test_destroy_secret_version(request_type=dict)
+def test_destroy_secret_version_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.destroy_secret_version), "__call__"
+ ) as call:
+ client.destroy_secret_version()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == service.DestroySecretVersionRequest()
+
+
@pytest.mark.asyncio
async def test_destroy_secret_version_async(
transport: str = "grpc_asyncio", request_type=service.DestroySecretVersionRequest
@@ -3327,6 +3522,22 @@ def test_set_iam_policy_from_dict():
test_set_iam_policy(request_type=dict)
+def test_set_iam_policy_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call:
+ client.set_iam_policy()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == iam_policy.SetIamPolicyRequest()
+
+
@pytest.mark.asyncio
async def test_set_iam_policy_async(
transport: str = "grpc_asyncio", request_type=iam_policy.SetIamPolicyRequest
@@ -3471,6 +3682,22 @@ def test_get_iam_policy_from_dict():
test_get_iam_policy(request_type=dict)
+def test_get_iam_policy_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call:
+ client.get_iam_policy()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == iam_policy.GetIamPolicyRequest()
+
+
@pytest.mark.asyncio
async def test_get_iam_policy_async(
transport: str = "grpc_asyncio", request_type=iam_policy.GetIamPolicyRequest
@@ -3617,6 +3844,24 @@ def test_test_iam_permissions_from_dict():
test_test_iam_permissions(request_type=dict)
+def test_test_iam_permissions_empty_call():
+ # This test is a coverage failsafe to make sure that totally empty calls,
+ # i.e. request == None and no flattened fields passed, work.
+ client = SecretManagerServiceClient(
+ credentials=credentials.AnonymousCredentials(), transport="grpc",
+ )
+
+ # Mock the actual call within the gRPC stub, and fake the request.
+ with mock.patch.object(
+ type(client.transport.test_iam_permissions), "__call__"
+ ) as call:
+ client.test_iam_permissions()
+ call.assert_called()
+ _, args, _ = call.mock_calls[0]
+
+ assert args[0] == iam_policy.TestIamPermissionsRequest()
+
+
@pytest.mark.asyncio
async def test_test_iam_permissions_async(
transport: str = "grpc_asyncio", request_type=iam_policy.TestIamPermissionsRequest
@@ -3905,6 +4150,53 @@ def test_secret_manager_service_transport_auth_adc():
)
+@pytest.mark.parametrize(
+ "transport_class",
+ [
+ transports.SecretManagerServiceGrpcTransport,
+ transports.SecretManagerServiceGrpcAsyncIOTransport,
+ ],
+)
+def test_secret_manager_service_grpc_transport_client_cert_source_for_mtls(
+ transport_class,
+):
+ cred = credentials.AnonymousCredentials()
+
+ # Check ssl_channel_credentials is used if provided.
+ with mock.patch.object(transport_class, "create_channel") as mock_create_channel:
+ mock_ssl_channel_creds = mock.Mock()
+ transport_class(
+ host="squid.clam.whelk",
+ credentials=cred,
+ ssl_channel_credentials=mock_ssl_channel_creds,
+ )
+ mock_create_channel.assert_called_once_with(
+ "squid.clam.whelk:443",
+ credentials=cred,
+ credentials_file=None,
+ scopes=("https://www.googleapis.com/auth/cloud-platform",),
+ ssl_credentials=mock_ssl_channel_creds,
+ quota_project_id=None,
+ options=[
+ ("grpc.max_send_message_length", -1),
+ ("grpc.max_receive_message_length", -1),
+ ],
+ )
+
+ # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls
+ # is used.
+ with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()):
+ with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred:
+ transport_class(
+ credentials=cred,
+ client_cert_source_for_mtls=client_cert_source_callback,
+ )
+ expected_cert, expected_key = client_cert_source_callback()
+ mock_ssl_cred.assert_called_once_with(
+ certificate_chain=expected_cert, private_key=expected_key
+ )
+
+
def test_secret_manager_service_host_no_port():
client = SecretManagerServiceClient(
credentials=credentials.AnonymousCredentials(),
@@ -3949,6 +4241,8 @@ def test_secret_manager_service_grpc_asyncio_transport_channel():
assert transport._ssl_channel_credentials == None
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[
@@ -4001,6 +4295,8 @@ def test_secret_manager_service_transport_channel_mtls_with_client_cert_source(
assert transport._ssl_channel_credentials == mock_ssl_cred
+# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
+# removed from grpc/grpc_asyncio transport constructor.
@pytest.mark.parametrize(
"transport_class",
[