From 13a6b3aed35b5af85aea047922aa219258460a58 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Thu, 24 Jun 2021 15:31:08 -0700 Subject: [PATCH] =?UTF-8?q?fix(bazel):=20Re-enable=20Python=20=C2=B5gen=20?= =?UTF-8?q?integration=20tests=20post=20monolith=20rule=20removal=20(#926)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(bazel): Re-enable Python µgen integration tests post monolith rule removal * fix: update googleapis hash * fix: update asset goldens (due to googleapis hash update) --- .github/workflows/tests.yaml | 6 +- repositories.bzl | 4 +- .../asset/google/cloud/asset/__init__.py | 6 + .../asset/google/cloud/asset_v1/__init__.py | 6 + .../google/cloud/asset_v1/gapic_metadata.json | 10 + .../services/asset_service/async_client.py | 173 +++++++- .../asset_v1/services/asset_service/client.py | 173 +++++++- .../asset_v1/services/asset_service/pagers.py | 122 +++++ .../services/asset_service/transports/base.py | 14 + .../services/asset_service/transports/grpc.py | 27 ++ .../asset_service/transports/grpc_asyncio.py | 27 ++ .../google/cloud/asset_v1/types/__init__.py | 6 + .../cloud/asset_v1/types/asset_service.py | 312 +++++++++++-- .../google/cloud/asset_v1/types/assets.py | 243 +++++++++- ...sset_v1_asset_service_list_assets_async.py | 45 ++ ...asset_v1_asset_service_list_assets_sync.py | 45 ++ .../asset/scripts/fixup_asset_v1_keywords.py | 3 +- .../unit/gapic/asset_v1/test_asset_service.py | 418 ++++++++++++++++++ 18 files changed, 1546 insertions(+), 94 deletions(-) create mode 100644 tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_async.py create mode 100644 tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_sync.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 8d47dd3a8d..2ff05a9095 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -344,10 +344,8 @@ jobs: env: BAZEL_VERSION: 3.5.0 BAZEL_BINARY: bazel_3.5.0-linux-x86_64.deb - # Temporarily disable integration tests due to a circular Bazel rule dependency. - # TODO(miraleung): Uncomment these once the monolith is gone from googleapis. - #- name: Integration Tests - #run: bazel test tests/integration:asset tests/integration:credentials tests/integration:logging tests/integration:redis + - name: Integration Tests + run: bazel test tests/integration:asset tests/integration:credentials tests/integration:logging tests/integration:redis style-check: runs-on: ubuntu-latest diff --git a/repositories.bzl b/repositories.bzl index 19a1a867b6..83ba719f34 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -65,8 +65,8 @@ def gapic_generator_python(): _maybe( http_archive, name = "com_google_googleapis", - strip_prefix = "googleapis-51fe6432d4076a4c101f561967df4bf1f27818e1", - urls = ["https://github.com/googleapis/googleapis/archive/51fe6432d4076a4c101f561967df4bf1f27818e1.zip"], + strip_prefix = "googleapis-ffc531383747ebb702dad3db237ef5fdea796363", + urls = ["https://github.com/googleapis/googleapis/archive/ffc531383747ebb702dad3db237ef5fdea796363.zip"], ) def gapic_generator_register_toolchains(): diff --git a/tests/integration/goldens/asset/google/cloud/asset/__init__.py b/tests/integration/goldens/asset/google/cloud/asset/__init__.py index d823276527..815c196c23 100644 --- a/tests/integration/goldens/asset/google/cloud/asset/__init__.py +++ b/tests/integration/goldens/asset/google/cloud/asset/__init__.py @@ -35,6 +35,8 @@ from google.cloud.asset_v1.types.asset_service import GetFeedRequest from google.cloud.asset_v1.types.asset_service import IamPolicyAnalysisOutputConfig from google.cloud.asset_v1.types.asset_service import IamPolicyAnalysisQuery +from google.cloud.asset_v1.types.asset_service import ListAssetsRequest +from google.cloud.asset_v1.types.asset_service import ListAssetsResponse from google.cloud.asset_v1.types.asset_service import ListFeedsRequest from google.cloud.asset_v1.types.asset_service import ListFeedsResponse from google.cloud.asset_v1.types.asset_service import OutputConfig @@ -48,6 +50,7 @@ from google.cloud.asset_v1.types.asset_service import UpdateFeedRequest from google.cloud.asset_v1.types.asset_service import ContentType from google.cloud.asset_v1.types.assets import Asset +from google.cloud.asset_v1.types.assets import ConditionEvaluation from google.cloud.asset_v1.types.assets import IamPolicyAnalysisResult from google.cloud.asset_v1.types.assets import IamPolicyAnalysisState from google.cloud.asset_v1.types.assets import IamPolicySearchResult @@ -76,6 +79,8 @@ 'GetFeedRequest', 'IamPolicyAnalysisOutputConfig', 'IamPolicyAnalysisQuery', + 'ListAssetsRequest', + 'ListAssetsResponse', 'ListFeedsRequest', 'ListFeedsResponse', 'OutputConfig', @@ -89,6 +94,7 @@ 'UpdateFeedRequest', 'ContentType', 'Asset', + 'ConditionEvaluation', 'IamPolicyAnalysisResult', 'IamPolicyAnalysisState', 'IamPolicySearchResult', diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py b/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py index 3988eaad25..35fdc0668d 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/__init__.py @@ -35,6 +35,8 @@ from .types.asset_service import GetFeedRequest from .types.asset_service import IamPolicyAnalysisOutputConfig from .types.asset_service import IamPolicyAnalysisQuery +from .types.asset_service import ListAssetsRequest +from .types.asset_service import ListAssetsResponse from .types.asset_service import ListFeedsRequest from .types.asset_service import ListFeedsResponse from .types.asset_service import OutputConfig @@ -48,6 +50,7 @@ from .types.asset_service import UpdateFeedRequest from .types.asset_service import ContentType from .types.assets import Asset +from .types.assets import ConditionEvaluation from .types.assets import IamPolicyAnalysisResult from .types.assets import IamPolicyAnalysisState from .types.assets import IamPolicySearchResult @@ -67,6 +70,7 @@ 'BatchGetAssetsHistoryRequest', 'BatchGetAssetsHistoryResponse', 'BigQueryDestination', +'ConditionEvaluation', 'ContentType', 'CreateFeedRequest', 'DeleteFeedRequest', @@ -82,6 +86,8 @@ 'IamPolicyAnalysisResult', 'IamPolicyAnalysisState', 'IamPolicySearchResult', +'ListAssetsRequest', +'ListAssetsResponse', 'ListFeedsRequest', 'ListFeedsResponse', 'OutputConfig', diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/gapic_metadata.json b/tests/integration/goldens/asset/google/cloud/asset_v1/gapic_metadata.json index a80eb281c4..eebf25a106 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/gapic_metadata.json +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/gapic_metadata.json @@ -45,6 +45,11 @@ "get_feed" ] }, + "ListAssets": { + "methods": [ + "list_assets" + ] + }, "ListFeeds": { "methods": [ "list_feeds" @@ -105,6 +110,11 @@ "get_feed" ] }, + "ListAssets": { + "methods": [ + "list_assets" + ] + }, "ListFeeds": { "methods": [ "list_feeds" diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py index 099a951d17..054bfe5565 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py @@ -229,6 +229,95 @@ async def export_assets(self, # Done; return the response. return response + async def list_assets(self, + request: asset_service.ListAssetsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListAssetsAsyncPager: + r"""Lists assets with time and resource types and returns + paged results in response. + + Args: + request (:class:`google.cloud.asset_v1.types.ListAssetsRequest`): + The request object. ListAssets request. + parent (:class:`str`): + Required. Name of the organization or project the assets + belong to. Format: "organizations/[organization-number]" + (such as "organizations/123"), "projects/[project-id]" + (such as "projects/my-project-id"), or + "projects/[project-number]" (such as "projects/12345"). + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.asset_v1.services.asset_service.pagers.ListAssetsAsyncPager: + ListAssets response. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError("If the `request` argument is set, then none of " + "the individual field arguments should be set.") + + request = asset_service.ListAssetsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_assets, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListAssetsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + async def batch_get_assets_history(self, request: asset_service.BatchGetAssetsHistoryRequest = None, *, @@ -732,7 +821,7 @@ async def search_all_resources(self, Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllResources`` `__ + ```cloudasset.assets.searchAllResources`` `__ permission on the desired scope. The allowed values are: @@ -748,40 +837,48 @@ async def search_all_resources(self, should not be set. query (:class:`str`): Optional. The query statement. See `how to construct a - query `__ + query `__ for more information. If not specified or empty, it will search all the resources within the specified ``scope``. - Note that the query string is compared against each - Cloud IAM policy binding, including its members, roles, - and Cloud IAM conditions. The returned Cloud IAM - policies will only contain the bindings that match your - query. To learn more about the IAM policy structure, see - `IAM policy - doc `__. Examples: - ``name:Important`` to find Cloud resources whose name contains "Important" as a word. + - ``name=Important`` to find the Cloud resource whose + name is exactly "Important". - ``displayName:Impor*`` to find Cloud resources whose - display name contains "Impor" as a prefix. - - ``description:*por*`` to find Cloud resources whose - description contains "por" as a substring. + display name contains "Impor" as a prefix of any word + in the field. - ``location:us-west*`` to find Cloud resources whose - location is prefixed with "us-west". + location contains both "us" and "west" as prefixes. - ``labels:prod`` to find Cloud resources whose labels contain "prod" as a key or value. - ``labels.env:prod`` to find Cloud resources that have a label "env" and its value is "prod". - ``labels.env:*`` to find Cloud resources that have a label "env". + - ``kmsKey:key`` to find Cloud resources encrypted with + a customer-managed encryption key whose name contains + the word "key". + - ``state:ACTIVE`` to find Cloud resources whose state + contains "ACTIVE" as a word. + - ``NOT state:ACTIVE`` to find {{gcp_name}} resources + whose state doesn't contain "ACTIVE" as a word. + - ``createTime<1609459200`` to find Cloud resources + that were created before "2021-01-01 00:00:00 UTC". + 1609459200 is the epoch timestamp of "2021-01-01 + 00:00:00 UTC" in seconds. + - ``updateTime>1609459200`` to find Cloud resources + that were updated after "2021-01-01 00:00:00 UTC". + 1609459200 is the epoch timestamp of "2021-01-01 + 00:00:00 UTC" in seconds. - ``Important`` to find Cloud resources that contain "Important" as a word in any of the searchable fields. - ``Impor*`` to find Cloud resources that contain - "Impor" as a prefix in any of the searchable fields. - - ``*por*`` to find Cloud resources that contain "por" - as a substring in any of the searchable fields. + "Impor" as a prefix of any word in any of the + searchable fields. - ``Important location:(us-west1 OR global)`` to find Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in @@ -796,6 +893,20 @@ async def search_all_resources(self, `searchable asset types `__. + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type + ends with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ + for all supported regular expression syntax. If the + regular expression does not match any supported asset + type, an INVALID_ARGUMENT error will be returned. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -896,7 +1007,7 @@ async def search_all_iam_policies(self, Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllIamPolicies`` `__ + ```cloudasset.assets.searchAllIamPolicies`` `__ permission on the desired scope. The allowed values are: @@ -915,7 +1026,13 @@ async def search_all_iam_policies(self, query `__ for more information. If not specified or empty, it will search all the IAM policies within the specified - ``scope``. + ``scope``. Note that the query string is compared + against each Cloud IAM policy binding, including its + members, roles, and Cloud IAM conditions. The returned + Cloud IAM policies will only contain the bindings that + match your query. To learn more about the IAM policy + structure, see `IAM policy + doc `__. Examples: @@ -923,6 +1040,9 @@ async def search_all_iam_policies(self, that specify user "amy@gmail.com". - ``policy:roles/compute.admin`` to find IAM policy bindings that specify the Compute Admin role. + - ``policy:comp*`` to find IAM policy bindings that + contain "comp" as a prefix of any word in the + binding. - ``policy.role.permissions:storage.buckets.update`` to find IAM policy bindings that specify a role containing "storage.buckets.update" permission. Note @@ -930,19 +1050,30 @@ async def search_all_iam_policies(self, to a role's included permissions, policy bindings that specify this role will be dropped from the search results. + - ``policy.role.permissions:upd*`` to find IAM policy + bindings that specify a role containing "upd" as a + prefix of any word in the role permission. Note that + if callers don't have ``iam.roles.get`` access to a + role's included permissions, policy bindings that + specify this role will be dropped from the search + results. - ``resource:organizations/123456`` to find IAM policy bindings that are set on "organizations/123456". + - ``resource=//cloudresourcemanager.googleapis.com/projects/myproject`` + to find IAM policy bindings that are set on the + project named "myproject". - ``Important`` to find IAM policy bindings that contain "Important" as a word in any of the searchable fields (except for the included permissions). - - ``*por*`` to find IAM policy bindings that contain - "por" as a substring in any of the searchable fields - (except for the included permissions). - ``resource:(instance1 OR instance2) policy:amy`` to find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user "amy". + - ``roles:roles/compute.admin`` to find IAM policy + bindings that specify the Compute Admin role. + - ``memberTypes:user`` to find IAM policy bindings that + contain the "user" member type. This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py index 1b86808fbd..aa285d830e 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py @@ -426,6 +426,95 @@ def export_assets(self, # Done; return the response. return response + def list_assets(self, + request: asset_service.ListAssetsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListAssetsPager: + r"""Lists assets with time and resource types and returns + paged results in response. + + Args: + request (google.cloud.asset_v1.types.ListAssetsRequest): + The request object. ListAssets request. + parent (str): + Required. Name of the organization or project the assets + belong to. Format: "organizations/[organization-number]" + (such as "organizations/123"), "projects/[project-id]" + (such as "projects/my-project-id"), or + "projects/[project-number]" (such as "projects/12345"). + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.asset_v1.services.asset_service.pagers.ListAssetsPager: + ListAssets response. + Iterating over this object will yield + results and resolve additional pages + automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError('If the `request` argument is set, then none of ' + 'the individual field arguments should be set.') + + # Minor optimization to avoid making a copy if the user passes + # in a asset_service.ListAssetsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, asset_service.ListAssetsRequest): + request = asset_service.ListAssetsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_assets] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ("parent", request.parent), + )), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListAssetsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + def batch_get_assets_history(self, request: asset_service.BatchGetAssetsHistoryRequest = None, *, @@ -902,7 +991,7 @@ def search_all_resources(self, Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllResources`` `__ + ```cloudasset.assets.searchAllResources`` `__ permission on the desired scope. The allowed values are: @@ -918,40 +1007,48 @@ def search_all_resources(self, should not be set. query (str): Optional. The query statement. See `how to construct a - query `__ + query `__ for more information. If not specified or empty, it will search all the resources within the specified ``scope``. - Note that the query string is compared against each - Cloud IAM policy binding, including its members, roles, - and Cloud IAM conditions. The returned Cloud IAM - policies will only contain the bindings that match your - query. To learn more about the IAM policy structure, see - `IAM policy - doc `__. Examples: - ``name:Important`` to find Cloud resources whose name contains "Important" as a word. + - ``name=Important`` to find the Cloud resource whose + name is exactly "Important". - ``displayName:Impor*`` to find Cloud resources whose - display name contains "Impor" as a prefix. - - ``description:*por*`` to find Cloud resources whose - description contains "por" as a substring. + display name contains "Impor" as a prefix of any word + in the field. - ``location:us-west*`` to find Cloud resources whose - location is prefixed with "us-west". + location contains both "us" and "west" as prefixes. - ``labels:prod`` to find Cloud resources whose labels contain "prod" as a key or value. - ``labels.env:prod`` to find Cloud resources that have a label "env" and its value is "prod". - ``labels.env:*`` to find Cloud resources that have a label "env". + - ``kmsKey:key`` to find Cloud resources encrypted with + a customer-managed encryption key whose name contains + the word "key". + - ``state:ACTIVE`` to find Cloud resources whose state + contains "ACTIVE" as a word. + - ``NOT state:ACTIVE`` to find {{gcp_name}} resources + whose state doesn't contain "ACTIVE" as a word. + - ``createTime<1609459200`` to find Cloud resources + that were created before "2021-01-01 00:00:00 UTC". + 1609459200 is the epoch timestamp of "2021-01-01 + 00:00:00 UTC" in seconds. + - ``updateTime>1609459200`` to find Cloud resources + that were updated after "2021-01-01 00:00:00 UTC". + 1609459200 is the epoch timestamp of "2021-01-01 + 00:00:00 UTC" in seconds. - ``Important`` to find Cloud resources that contain "Important" as a word in any of the searchable fields. - ``Impor*`` to find Cloud resources that contain - "Impor" as a prefix in any of the searchable fields. - - ``*por*`` to find Cloud resources that contain "por" - as a substring in any of the searchable fields. + "Impor" as a prefix of any word in any of the + searchable fields. - ``Important location:(us-west1 OR global)`` to find Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in @@ -966,6 +1063,20 @@ def search_all_resources(self, `searchable asset types `__. + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type + ends with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ + for all supported regular expression syntax. If the + regular expression does not match any supported asset + type, an INVALID_ARGUMENT error will be returned. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1059,7 +1170,7 @@ def search_all_iam_policies(self, Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllIamPolicies`` `__ + ```cloudasset.assets.searchAllIamPolicies`` `__ permission on the desired scope. The allowed values are: @@ -1078,7 +1189,13 @@ def search_all_iam_policies(self, query `__ for more information. If not specified or empty, it will search all the IAM policies within the specified - ``scope``. + ``scope``. Note that the query string is compared + against each Cloud IAM policy binding, including its + members, roles, and Cloud IAM conditions. The returned + Cloud IAM policies will only contain the bindings that + match your query. To learn more about the IAM policy + structure, see `IAM policy + doc `__. Examples: @@ -1086,6 +1203,9 @@ def search_all_iam_policies(self, that specify user "amy@gmail.com". - ``policy:roles/compute.admin`` to find IAM policy bindings that specify the Compute Admin role. + - ``policy:comp*`` to find IAM policy bindings that + contain "comp" as a prefix of any word in the + binding. - ``policy.role.permissions:storage.buckets.update`` to find IAM policy bindings that specify a role containing "storage.buckets.update" permission. Note @@ -1093,19 +1213,30 @@ def search_all_iam_policies(self, to a role's included permissions, policy bindings that specify this role will be dropped from the search results. + - ``policy.role.permissions:upd*`` to find IAM policy + bindings that specify a role containing "upd" as a + prefix of any word in the role permission. Note that + if callers don't have ``iam.roles.get`` access to a + role's included permissions, policy bindings that + specify this role will be dropped from the search + results. - ``resource:organizations/123456`` to find IAM policy bindings that are set on "organizations/123456". + - ``resource=//cloudresourcemanager.googleapis.com/projects/myproject`` + to find IAM policy bindings that are set on the + project named "myproject". - ``Important`` to find IAM policy bindings that contain "Important" as a word in any of the searchable fields (except for the included permissions). - - ``*por*`` to find IAM policy bindings that contain - "por" as a substring in any of the searchable fields - (except for the included permissions). - ``resource:(instance1 OR instance2) policy:amy`` to find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user "amy". + - ``roles:roles/compute.admin`` to find IAM policy + bindings that specify the Compute Admin role. + - ``memberTypes:user`` to find IAM policy bindings that + contain the "user" member type. This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/pagers.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/pagers.py index 01ea865a49..c09af15cdf 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/pagers.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/pagers.py @@ -19,6 +19,128 @@ from google.cloud.asset_v1.types import assets +class ListAssetsPager: + """A pager for iterating through ``list_assets`` requests. + + This class thinly wraps an initial + :class:`google.cloud.asset_v1.types.ListAssetsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``assets`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListAssets`` requests and continue to iterate + through the ``assets`` field on the + corresponding responses. + + All the usual :class:`google.cloud.asset_v1.types.ListAssetsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., asset_service.ListAssetsResponse], + request: asset_service.ListAssetsRequest, + response: asset_service.ListAssetsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.asset_v1.types.ListAssetsRequest): + The initial request object. + response (google.cloud.asset_v1.types.ListAssetsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = asset_service.ListAssetsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[asset_service.ListAssetsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[assets.Asset]: + for page in self.pages: + yield from page.assets + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + +class ListAssetsAsyncPager: + """A pager for iterating through ``list_assets`` requests. + + This class thinly wraps an initial + :class:`google.cloud.asset_v1.types.ListAssetsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``assets`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListAssets`` requests and continue to iterate + through the ``assets`` field on the + corresponding responses. + + All the usual :class:`google.cloud.asset_v1.types.ListAssetsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + def __init__(self, + method: Callable[..., Awaitable[asset_service.ListAssetsResponse]], + request: asset_service.ListAssetsRequest, + response: asset_service.ListAssetsResponse, + *, + metadata: Sequence[Tuple[str, str]] = ()): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.asset_v1.types.ListAssetsRequest): + The initial request object. + response (google.cloud.asset_v1.types.ListAssetsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = asset_service.ListAssetsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[asset_service.ListAssetsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[assets.Asset]: + async def async_generator(): + async for page in self.pages: + for response in page.assets: + yield response + + return async_generator() + + def __repr__(self) -> str: + return '{0}<{1!r}>'.format(self.__class__.__name__, self._response) + + class SearchAllResourcesPager: """A pager for iterating through ``search_all_resources`` requests. diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/base.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/base.py index 21e813df40..6d94cb3550 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/base.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/base.py @@ -154,6 +154,11 @@ def _prep_wrapped_messages(self, client_info): default_timeout=60.0, client_info=client_info, ), + self.list_assets: gapic_v1.method.wrap_method( + self.list_assets, + default_timeout=None, + client_info=client_info, + ), self.batch_get_assets_history: gapic_v1.method.wrap_method( self.batch_get_assets_history, default_retry=retries.Retry( @@ -268,6 +273,15 @@ def export_assets(self) -> Callable[ ]]: raise NotImplementedError() + @property + def list_assets(self) -> Callable[ + [asset_service.ListAssetsRequest], + Union[ + asset_service.ListAssetsResponse, + Awaitable[asset_service.ListAssetsResponse] + ]]: + raise NotImplementedError() + @property def batch_get_assets_history(self) -> Callable[ [asset_service.BatchGetAssetsHistoryRequest], diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc.py index 1fedd3cc19..60326ac61d 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc.py @@ -275,6 +275,33 @@ def export_assets(self) -> Callable[ ) return self._stubs['export_assets'] + @property + def list_assets(self) -> Callable[ + [asset_service.ListAssetsRequest], + asset_service.ListAssetsResponse]: + r"""Return a callable for the list assets method over gRPC. + + Lists assets with time and resource types and returns + paged results in response. + + Returns: + Callable[[~.ListAssetsRequest], + ~.ListAssetsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_assets' not in self._stubs: + self._stubs['list_assets'] = self.grpc_channel.unary_unary( + '/google.cloud.asset.v1.AssetService/ListAssets', + request_serializer=asset_service.ListAssetsRequest.serialize, + response_deserializer=asset_service.ListAssetsResponse.deserialize, + ) + return self._stubs['list_assets'] + @property def batch_get_assets_history(self) -> Callable[ [asset_service.BatchGetAssetsHistoryRequest], diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py index cac5701160..748505dd03 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py @@ -279,6 +279,33 @@ def export_assets(self) -> Callable[ ) return self._stubs['export_assets'] + @property + def list_assets(self) -> Callable[ + [asset_service.ListAssetsRequest], + Awaitable[asset_service.ListAssetsResponse]]: + r"""Return a callable for the list assets method over gRPC. + + Lists assets with time and resource types and returns + paged results in response. + + Returns: + Callable[[~.ListAssetsRequest], + Awaitable[~.ListAssetsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if 'list_assets' not in self._stubs: + self._stubs['list_assets'] = self.grpc_channel.unary_unary( + '/google.cloud.asset.v1.AssetService/ListAssets', + request_serializer=asset_service.ListAssetsRequest.serialize, + response_deserializer=asset_service.ListAssetsResponse.deserialize, + ) + return self._stubs['list_assets'] + @property def batch_get_assets_history(self) -> Callable[ [asset_service.BatchGetAssetsHistoryRequest], diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/types/__init__.py b/tests/integration/goldens/asset/google/cloud/asset_v1/types/__init__.py index 02a737df6f..f20e222422 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/types/__init__.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/types/__init__.py @@ -32,6 +32,8 @@ GetFeedRequest, IamPolicyAnalysisOutputConfig, IamPolicyAnalysisQuery, + ListAssetsRequest, + ListAssetsResponse, ListFeedsRequest, ListFeedsResponse, OutputConfig, @@ -47,6 +49,7 @@ ) from .assets import ( Asset, + ConditionEvaluation, IamPolicyAnalysisResult, IamPolicyAnalysisState, IamPolicySearchResult, @@ -75,6 +78,8 @@ 'GetFeedRequest', 'IamPolicyAnalysisOutputConfig', 'IamPolicyAnalysisQuery', + 'ListAssetsRequest', + 'ListAssetsResponse', 'ListFeedsRequest', 'ListFeedsResponse', 'OutputConfig', @@ -88,6 +93,7 @@ 'UpdateFeedRequest', 'ContentType', 'Asset', + 'ConditionEvaluation', 'IamPolicyAnalysisResult', 'IamPolicyAnalysisState', 'IamPolicySearchResult', diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/types/asset_service.py b/tests/integration/goldens/asset/google/cloud/asset_v1/types/asset_service.py index 3bc5782010..8ecee480f8 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/types/asset_service.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/types/asset_service.py @@ -28,6 +28,8 @@ 'ContentType', 'ExportAssetsRequest', 'ExportAssetsResponse', + 'ListAssetsRequest', + 'ListAssetsResponse', 'BatchGetAssetsHistoryRequest', 'BatchGetAssetsHistoryResponse', 'CreateFeedRequest', @@ -183,6 +185,124 @@ class ExportAssetsResponse(proto.Message): ) +class ListAssetsRequest(proto.Message): + r"""ListAssets request. + Attributes: + parent (str): + Required. Name of the organization or project the assets + belong to. Format: "organizations/[organization-number]" + (such as "organizations/123"), "projects/[project-id]" (such + as "projects/my-project-id"), or "projects/[project-number]" + (such as "projects/12345"). + read_time (google.protobuf.timestamp_pb2.Timestamp): + Timestamp to take an asset snapshot. This can + only be set to a timestamp between the current + time and the current time minus 35 days + (inclusive). If not specified, the current time + will be used. Due to delays in resource data + collection and indexing, there is a volatile + window during which running the same query may + get different results. + asset_types (Sequence[str]): + A list of asset types to take a snapshot for. For example: + "compute.googleapis.com/Disk". + + Regular expression is also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type ends + with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ for + all supported regular expression syntax. If the regular + expression does not match any supported asset type, an + INVALID_ARGUMENT error will be returned. + + If specified, only matching assets will be returned, + otherwise, it will snapshot all asset types. See + `Introduction to Cloud Asset + Inventory `__ + for all supported asset types. + content_type (google.cloud.asset_v1.types.ContentType): + Asset content type. If not specified, no + content but the asset name will be returned. + page_size (int): + The maximum number of assets to be returned + in a single response. Default is 100, minimum is + 1, and maximum is 1000. + page_token (str): + The ``next_page_token`` returned from the previous + ``ListAssetsResponse``, or unspecified for the first + ``ListAssetsRequest``. It is a continuation of a prior + ``ListAssets`` call, and the API should return the next page + of assets. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + read_time = proto.Field( + proto.MESSAGE, + number=2, + message=timestamp_pb2.Timestamp, + ) + asset_types = proto.RepeatedField( + proto.STRING, + number=3, + ) + content_type = proto.Field( + proto.ENUM, + number=4, + enum='ContentType', + ) + page_size = proto.Field( + proto.INT32, + number=5, + ) + page_token = proto.Field( + proto.STRING, + number=6, + ) + + +class ListAssetsResponse(proto.Message): + r"""ListAssets response. + Attributes: + read_time (google.protobuf.timestamp_pb2.Timestamp): + Time the snapshot was taken. + assets (Sequence[google.cloud.asset_v1.types.Asset]): + Assets. + next_page_token (str): + Token to retrieve the next page of results. + It expires 72 hours after the page token for the + first page is generated. Set to empty if there + are no remaining results. + """ + + @property + def raw_page(self): + return self + + read_time = proto.Field( + proto.MESSAGE, + number=1, + message=timestamp_pb2.Timestamp, + ) + assets = proto.RepeatedField( + proto.MESSAGE, + number=2, + message=gca_assets.Asset, + ) + next_page_token = proto.Field( + proto.STRING, + number=3, + ) + + class BatchGetAssetsHistoryRequest(proto.Message): r"""Batch get assets history request. Attributes: @@ -441,6 +561,11 @@ class GcsDestination(proto.Message): See `Viewing and Editing Object Metadata `__ for more information. + + If the specified Cloud Storage object already exists and + there is no + `hold `__, + it will be overwritten with the exported result. uri_prefix (str): The uri prefix of all generated Cloud Storage objects. Example: "gs://bucket_name/object_name_prefix". Each object @@ -718,7 +843,7 @@ class SearchAllResourcesRequest(proto.Message): Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllResources`` `__ + ```cloudasset.assets.searchAllResources`` `__ permission on the desired scope. The allowed values are: @@ -730,38 +855,46 @@ class SearchAllResourcesRequest(proto.Message): "organizations/123456") query (str): Optional. The query statement. See `how to construct a - query `__ + query `__ for more information. If not specified or empty, it will search all the resources within the specified ``scope``. - Note that the query string is compared against each Cloud - IAM policy binding, including its members, roles, and Cloud - IAM conditions. The returned Cloud IAM policies will only - contain the bindings that match your query. To learn more - about the IAM policy structure, see `IAM policy - doc `__. Examples: - ``name:Important`` to find Cloud resources whose name contains "Important" as a word. + - ``name=Important`` to find the Cloud resource whose name + is exactly "Important". - ``displayName:Impor*`` to find Cloud resources whose - display name contains "Impor" as a prefix. - - ``description:*por*`` to find Cloud resources whose - description contains "por" as a substring. + display name contains "Impor" as a prefix of any word in + the field. - ``location:us-west*`` to find Cloud resources whose - location is prefixed with "us-west". + location contains both "us" and "west" as prefixes. - ``labels:prod`` to find Cloud resources whose labels contain "prod" as a key or value. - ``labels.env:prod`` to find Cloud resources that have a label "env" and its value is "prod". - ``labels.env:*`` to find Cloud resources that have a label "env". + - ``kmsKey:key`` to find Cloud resources encrypted with a + customer-managed encryption key whose name contains the + word "key". + - ``state:ACTIVE`` to find Cloud resources whose state + contains "ACTIVE" as a word. + - ``NOT state:ACTIVE`` to find {{gcp_name}} resources whose + state doesn't contain "ACTIVE" as a word. + - ``createTime<1609459200`` to find Cloud resources that + were created before "2021-01-01 00:00:00 UTC". 1609459200 + is the epoch timestamp of "2021-01-01 00:00:00 UTC" in + seconds. + - ``updateTime>1609459200`` to find Cloud resources that + were updated after "2021-01-01 00:00:00 UTC". 1609459200 + is the epoch timestamp of "2021-01-01 00:00:00 UTC" in + seconds. - ``Important`` to find Cloud resources that contain "Important" as a word in any of the searchable fields. - ``Impor*`` to find Cloud resources that contain "Impor" - as a prefix in any of the searchable fields. - - ``*por*`` to find Cloud resources that contain "por" as a - substring in any of the searchable fields. + as a prefix of any word in any of the searchable fields. - ``Important location:(us-west1 OR global)`` to find Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in the @@ -770,6 +903,20 @@ class SearchAllResourcesRequest(proto.Message): Optional. A list of asset types that this request searches for. If empty, it will search all the `searchable asset types `__. + + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots resources whose + asset type starts with "compute.googleapis.com". + - ".*Instance" snapshots resources whose asset type ends + with "Instance". + - ".*Instance.*" snapshots resources whose asset type + contains "Instance". + + See `RE2 `__ for + all supported regular expression syntax. If the regular + expression does not match any supported asset type, an + INVALID_ARGUMENT error will be returned. page_size (int): Optional. The page size for search result pagination. Page size is capped at 500 even if a larger value is given. If @@ -784,16 +931,28 @@ class SearchAllResourcesRequest(proto.Message): the previous response. The values of all other method parameters, must be identical to those in the previous call. order_by (str): - Optional. A comma separated list of fields specifying the + Optional. A comma-separated list of fields specifying the sorting order of the results. The default order is ascending. Add " DESC" after the field name to indicate descending order. Redundant space characters are ignored. - Example: "location DESC, name". Only string fields in the - response are sortable, including ``name``, ``displayName``, - ``description``, ``location``. All the other fields such as - repeated fields (e.g., ``networkTags``), map fields (e.g., - ``labels``) and struct fields (e.g., - ``additionalAttributes``) are not supported. + Example: "location DESC, name". Only singular primitive + fields in the response are sortable: + + - name + - assetType + - project + - displayName + - description + - location + - kmsKey + - createTime + - updateTime + - state + - parentFullResourceName + - parentAssetType All the other fields such as repeated + fields (e.g., ``networkTags``), map fields (e.g., + ``labels``) and struct fields (e.g., + ``additionalAttributes``) are not supported. """ scope = proto.Field( @@ -858,7 +1017,7 @@ class SearchAllIamPoliciesRequest(proto.Message): Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the - ```cloudasset.assets.searchAllIamPolicies`` `__ + ```cloudasset.assets.searchAllIamPolicies`` `__ permission on the desired scope. The allowed values are: @@ -873,6 +1032,12 @@ class SearchAllIamPoliciesRequest(proto.Message): query `__ for more information. If not specified or empty, it will search all the IAM policies within the specified ``scope``. + Note that the query string is compared against each Cloud + IAM policy binding, including its members, roles, and Cloud + IAM conditions. The returned Cloud IAM policies will only + contain the bindings that match your query. To learn more + about the IAM policy structure, see `IAM policy + doc `__. Examples: @@ -880,23 +1045,35 @@ class SearchAllIamPoliciesRequest(proto.Message): specify user "amy@gmail.com". - ``policy:roles/compute.admin`` to find IAM policy bindings that specify the Compute Admin role. + - ``policy:comp*`` to find IAM policy bindings that contain + "comp" as a prefix of any word in the binding. - ``policy.role.permissions:storage.buckets.update`` to find IAM policy bindings that specify a role containing "storage.buckets.update" permission. Note that if callers don't have ``iam.roles.get`` access to a role's included permissions, policy bindings that specify this role will be dropped from the search results. + - ``policy.role.permissions:upd*`` to find IAM policy + bindings that specify a role containing "upd" as a prefix + of any word in the role permission. Note that if callers + don't have ``iam.roles.get`` access to a role's included + permissions, policy bindings that specify this role will + be dropped from the search results. - ``resource:organizations/123456`` to find IAM policy bindings that are set on "organizations/123456". + - ``resource=//cloudresourcemanager.googleapis.com/projects/myproject`` + to find IAM policy bindings that are set on the project + named "myproject". - ``Important`` to find IAM policy bindings that contain "Important" as a word in any of the searchable fields (except for the included permissions). - - ``*por*`` to find IAM policy bindings that contain "por" - as a substring in any of the searchable fields (except - for the included permissions). - ``resource:(instance1 OR instance2) policy:amy`` to find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user "amy". + - ``roles:roles/compute.admin`` to find IAM policy bindings + that specify the Compute Admin role. + - ``memberTypes:user`` to find IAM policy bindings that + contain the "user" member type. page_size (int): Optional. The page size for search result pagination. Page size is capped at 500 even if a larger value is given. If @@ -910,6 +1087,39 @@ class SearchAllIamPoliciesRequest(proto.Message): be the value of ``next_page_token`` from the previous response. The values of all other method parameters must be identical to those in the previous call. + asset_types (Sequence[str]): + Optional. A list of asset types that the IAM policies are + attached to. If empty, it will search the IAM policies that + are attached to all the `searchable asset + types `__. + + Regular expressions are also supported. For example: + + - "compute.googleapis.com.*" snapshots IAM policies + attached to asset type starts with + "compute.googleapis.com". + - ".*Instance" snapshots IAM policies attached to asset + type ends with "Instance". + - ".*Instance.*" snapshots IAM policies attached to asset + type contains "Instance". + + See `RE2 `__ for + all supported regular expression syntax. If the regular + expression does not match any supported asset type, an + INVALID_ARGUMENT error will be returned. + order_by (str): + Optional. A comma-separated list of fields specifying the + sorting order of the results. The default order is + ascending. Add " DESC" after the field name to indicate + descending order. Redundant space characters are ignored. + Example: "assetType DESC, resource". Only singular primitive + fields in the response are sortable: + + - resource + - assetType + - project All the other fields such as repeated fields + (e.g., ``folders``) and non-primitive fields (e.g., + ``policy``) are not supported. """ scope = proto.Field( @@ -928,6 +1138,14 @@ class SearchAllIamPoliciesRequest(proto.Message): proto.STRING, number=4, ) + asset_types = proto.RepeatedField( + proto.STRING, + number=5, + ) + order_by = proto.Field( + proto.STRING, + number=7, + ) class SearchAllIamPoliciesResponse(proto.Message): @@ -960,7 +1178,7 @@ def raw_page(self): class IamPolicyAnalysisQuery(proto.Message): - r"""IAM policy analysis query message. + r"""## IAM policy analysis query message. Attributes: scope (str): Required. The relative name of the root asset. Only @@ -987,6 +1205,9 @@ class IamPolicyAnalysisQuery(proto.Message): analysis. This is optional. options (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.Options): Optional. The query options. + condition_context (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.ConditionContext): + Optional. The hypothetical context for IAM + conditions evaluation. """ class ResourceSelector(proto.Message): @@ -1172,6 +1393,23 @@ class Options(proto.Message): number=6, ) + class ConditionContext(proto.Message): + r"""The IAM conditions context. + Attributes: + access_time (google.protobuf.timestamp_pb2.Timestamp): + The hypothetical access timestamp to evaluate IAM + conditions. Note that this value must not be earlier than + the current time; otherwise, an INVALID_ARGUMENT error will + be returned. + """ + + access_time = proto.Field( + proto.MESSAGE, + number=1, + oneof='TimeContext', + message=timestamp_pb2.Timestamp, + ) + scope = proto.Field( proto.STRING, number=1, @@ -1196,6 +1434,11 @@ class Options(proto.Message): number=5, message=Options, ) + condition_context = proto.Field( + proto.MESSAGE, + number=6, + message=ConditionContext, + ) class AnalyzeIamPolicyRequest(proto.Message): @@ -1323,11 +1566,16 @@ class GcsDestination(proto.Message): Attributes: uri (str): Required. The uri of the Cloud Storage object. It's the same - uri that is used by gsutil. For example: - "gs://bucket_name/object_name". See [Quickstart: Using the - gsutil tool] - (https://cloud.google.com/storage/docs/quickstart-gsutil) - for examples. + uri that is used by gsutil. Example: + "gs://bucket_name/object_name". See `Viewing and Editing + Object + Metadata `__ + for more information. + + If the specified Cloud Storage object already exists and + there is no + `hold `__, + it will be overwritten with the analysis result. """ uri = proto.Field( diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/types/assets.py b/tests/integration/goldens/asset/google/cloud/asset_v1/types/assets.py index 6c4611e717..b2b5a9156b 100644 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/types/assets.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/types/assets.py @@ -36,6 +36,7 @@ 'ResourceSearchResult', 'IamPolicySearchResult', 'IamPolicyAnalysisState', + 'ConditionEvaluation', 'IamPolicyAnalysisResult', }, ) @@ -124,7 +125,8 @@ class Asset(proto.Message): hierarchy `__, a resource outside the Google Cloud resource hierarchy (such as Google Kubernetes Engine clusters and objects), or a policy (e.g. - Cloud IAM policy). See `Supported asset + Cloud IAM policy), or a relationship (e.g. an + INSTANCE_TO_INSTANCEGROUP relationship). See `Supported asset types `__ for more information. @@ -353,14 +355,40 @@ class ResourceSearchResult(proto.Message): - specify the ``asset_type`` field in your search request. project (str): The project that this resource belongs to, in the form of - projects/{PROJECT_NUMBER}. + projects/{PROJECT_NUMBER}. This field is available when the + resource belongs to a project. - To search against the ``project``: + To search against ``project``: + - use a field query. Example: ``project:12345`` + - use a free text query. Example: ``12345`` - specify the ``scope`` field as this project in your search request. + folders (Sequence[str]): + The folder(s) that this resource belongs to, in the form of + folders/{FOLDER_NUMBER}. This field is available when the + resource belongs to one or more folders. + + To search against ``folders``: + + - use a field query. Example: ``folders:(123 OR 456)`` + - use a free text query. Example: ``123`` + - specify the ``scope`` field as this folder in your search + request. + organization (str): + The organization that this resource belongs to, in the form + of organizations/{ORGANIZATION_NUMBER}. This field is + available when the resource belongs to an organization. + + To search against ``organization``: + + - use a field query. Example: ``organization:123`` + - use a free text query. Example: ``123`` + - specify the ``scope`` field as this organization in your + search request. display_name (str): - The display name of this resource. + The display name of this resource. This field is available + only when the resource's proto contains it. To search against the ``display_name``: @@ -368,17 +396,18 @@ class ResourceSearchResult(proto.Message): - use a free text query. Example: ``"My Instance"`` description (str): One or more paragraphs of text description of this resource. - Maximum length could be up to 1M bytes. + Maximum length could be up to 1M bytes. This field is + available only when the resource's proto contains it. To search against the ``description``: - use a field query. Example: - ``description:"*important instance*"`` - - use a free text query. Example: - ``"*important instance*"`` + ``description:"important instance"`` + - use a free text query. Example: ``"important instance"`` location (str): Location can be ``global``, regional like ``us-east1``, or - zonal like ``us-west1-b``. + zonal like ``us-west1-b``. This field is available only when + the resource's proto contains it. To search against the ``location``: @@ -388,7 +417,8 @@ class ResourceSearchResult(proto.Message): Labels associated with this resource. See `Labelling and grouping GCP resources `__ - for more information. + for more information. This field is available only when the + resource's proto contains it. To search against the ``labels``: @@ -406,12 +436,78 @@ class ResourceSearchResult(proto.Message): network tags are a type of annotations used to group GCP resources. See `Labelling GCP resources `__ - for more information. + for more information. This field is available only when the + resource's proto contains it. To search against the ``network_tags``: - use a field query. Example: ``networkTags:internal`` - use a free text query. Example: ``internal`` + kms_key (str): + The Cloud KMS + `CryptoKey `__ + name or + `CryptoKeyVersion `__ + name. This field is available only when the resource's proto + contains it. + + To search against the ``kms_key``: + + - use a field query. Example: ``kmsKey:key`` + - use a free text query. Example: ``key`` + create_time (google.protobuf.timestamp_pb2.Timestamp): + The create timestamp of this resource, at which the resource + was created. The granularity is in seconds. Timestamp.nanos + will always be 0. This field is available only when the + resource's proto contains it. + + To search against ``create_time``: + + - use a field query. + + - value in seconds since unix epoch. Example: + ``createTime > 1609459200`` + - value in date string. Example: + ``createTime > 2021-01-01`` + - value in date-time string (must be quoted). Example: + ``createTime > "2021-01-01T00:00:00"`` + update_time (google.protobuf.timestamp_pb2.Timestamp): + The last update timestamp of this resource, at which the + resource was last modified or deleted. The granularity is in + seconds. Timestamp.nanos will always be 0. This field is + available only when the resource's proto contains it. + + To search against ``update_time``: + + - use a field query. + + - value in seconds since unix epoch. Example: + ``updateTime < 1609459200`` + - value in date string. Example: + ``updateTime < 2021-01-01`` + - value in date-time string (must be quoted). Example: + ``updateTime < "2021-01-01T00:00:00"`` + state (str): + The state of this resource. Different resources types have + different state definitions that are mapped from various + fields of different resource types. This field is available + only when the resource's proto contains it. + + Example: If the resource is an instance provided by Compute + Engine, its state will include PROVISIONING, STAGING, + RUNNING, STOPPING, SUSPENDING, SUSPENDED, REPAIRING, and + TERMINATED. See ``status`` definition in `API + Reference `__. + If the resource is a project provided by Cloud Resource + Manager, its state will include LIFECYCLE_STATE_UNSPECIFIED, + ACTIVE, DELETE_REQUESTED and DELETE_IN_PROGRESS. See + ``lifecycleState`` definition in `API + Reference `__. + + To search against the ``state``: + + - use a field query. Example: ``state:RUNNING`` + - use a free text query. Example: ``RUNNING`` additional_attributes (google.protobuf.struct_pb2.Struct): The additional searchable attributes of this resource. The attributes may vary from one resource type to another. @@ -421,7 +517,7 @@ class ResourceSearchResult(proto.Message): provided by the corresponding GCP service (e.g., Compute Engine). see `API references and supported searchable attributes `__ - for more information. + to see which fields are included. You can search values of these fields through free text search. However, you should not consume the field @@ -434,6 +530,23 @@ class ResourceSearchResult(proto.Message): Example: to search ``additional_attributes = { dnsName: "foobar" }``, you can issue a query ``foobar``. + parent_full_resource_name (str): + The full resource name of this resource's parent, if it has + one. To search against the ``parent_full_resource_name``: + + - use a field query. Example: + ``parentFullResourceName:"project-name"`` + - use a free text query. Example: ``project-name`` + parent_asset_type (str): + The type of this resource's immediate parent, if there is + one. + + To search against the ``parent_asset_type``: + + - use a field query. Example: + ``parentAssetType:"cloudresourcemanager.googleapis.com/Project"`` + - use a free text query. Example: + ``cloudresourcemanager.googleapis.com/Project`` """ name = proto.Field( @@ -448,6 +561,14 @@ class ResourceSearchResult(proto.Message): proto.STRING, number=3, ) + folders = proto.RepeatedField( + proto.STRING, + number=17, + ) + organization = proto.Field( + proto.STRING, + number=18, + ) display_name = proto.Field( proto.STRING, number=4, @@ -469,11 +590,37 @@ class ResourceSearchResult(proto.Message): proto.STRING, number=8, ) + kms_key = proto.Field( + proto.STRING, + number=10, + ) + create_time = proto.Field( + proto.MESSAGE, + number=11, + message=timestamp_pb2.Timestamp, + ) + update_time = proto.Field( + proto.MESSAGE, + number=12, + message=timestamp_pb2.Timestamp, + ) + state = proto.Field( + proto.STRING, + number=13, + ) additional_attributes = proto.Field( proto.MESSAGE, number=9, message=struct_pb2.Struct, ) + parent_full_resource_name = proto.Field( + proto.STRING, + number=19, + ) + parent_asset_type = proto.Field( + proto.STRING, + number=103, + ) class IamPolicySearchResult(proto.Message): @@ -493,18 +640,47 @@ class IamPolicySearchResult(proto.Message): - use a field query. Example: ``resource:organizations/123`` + asset_type (str): + The type of the resource associated with this IAM policy. + Example: ``compute.googleapis.com/Disk``. + + To search against the ``asset_type``: + + - specify the ``asset_types`` field in your search request. project (str): The project that the associated GCP resource belongs to, in the form of projects/{PROJECT_NUMBER}. If an IAM policy is set on a resource (like VM instance, Cloud Storage bucket), the project field will indicate the project that contains the resource. If an IAM policy is set on a folder or - orgnization, the project field will be empty. + orgnization, this field will be empty. To search against the ``project``: - specify the ``scope`` field as this project in your search request. + folders (Sequence[str]): + The folder(s) that the IAM policy belongs to, in the form of + folders/{FOLDER_NUMBER}. This field is available when the + IAM policy belongs to one or more folders. + + To search against ``folders``: + + - use a field query. Example: ``folders:(123 OR 456)`` + - use a free text query. Example: ``123`` + - specify the ``scope`` field as this folder in your search + request. + organization (str): + The organization that the IAM policy belongs to, in the form + of organizations/{ORGANIZATION_NUMBER}. This field is + available when the IAM policy belongs to an organization. + + To search against ``organization``: + + - use a field query. Example: ``organization:123`` + - use a free text query. Example: ``123`` + - specify the ``scope`` field as this organization in your + search request. policy (google.iam.v1.policy_pb2.Policy): The IAM policy directly set on the given resource. Note that the original IAM policy can contain multiple bindings. This @@ -569,10 +745,22 @@ class Permissions(proto.Message): proto.STRING, number=1, ) + asset_type = proto.Field( + proto.STRING, + number=5, + ) project = proto.Field( proto.STRING, number=2, ) + folders = proto.RepeatedField( + proto.STRING, + number=6, + ) + organization = proto.Field( + proto.STRING, + number=7, + ) policy = proto.Field( proto.MESSAGE, number=3, @@ -616,6 +804,26 @@ class IamPolicyAnalysisState(proto.Message): ) +class ConditionEvaluation(proto.Message): + r"""The Condition evaluation. + Attributes: + evaluation_value (google.cloud.asset_v1.types.ConditionEvaluation.EvaluationValue): + The evaluation result. + """ + class EvaluationValue(proto.Enum): + r"""Value of this expression.""" + EVALUATION_VALUE_UNSPECIFIED = 0 + TRUE = 1 + FALSE = 2 + CONDITIONAL = 3 + + evaluation_value = proto.Field( + proto.ENUM, + number=1, + enum=EvaluationValue, + ) + + class IamPolicyAnalysisResult(proto.Message): r"""IAM Policy analysis result, consisting of one IAM policy binding and derived access control lists. @@ -786,6 +994,10 @@ class AccessControlList(proto.Message): contains the full resource name of a child resource. This field is present only if the output_resource_edges option is enabled in request. + condition_evaluation (google.cloud.asset_v1.types.ConditionEvaluation): + Condition evaluation for this + AccessControlList, if there is a condition + defined in the above IAM policy binding. """ resources = proto.RepeatedField( @@ -803,6 +1015,11 @@ class AccessControlList(proto.Message): number=3, message='IamPolicyAnalysisResult.Edge', ) + condition_evaluation = proto.Field( + proto.MESSAGE, + number=4, + message='ConditionEvaluation', + ) class IdentityList(proto.Message): r"""The identities and group edges. diff --git a/tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_async.py b/tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_async.py new file mode 100644 index 0000000000..3f79199a33 --- /dev/null +++ b/tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_async.py @@ -0,0 +1,45 @@ +# -*- 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for ListAssets +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-asset + + +# [START cloudasset_generated_asset_v1_AssetService_ListAssets_async] +from google.cloud import asset_v1 + + +async def sample_list_assets(): + """Snippet for list_assets""" + + # Create a client + client = asset_v1.AssetServiceAsyncClient() + + # Initialize request argument(s) + request = asset_v1.ListAssetsRequest( + ) + + # Make the request + page_result = client.list_assets(request=request) + async for response in page_result: + print("{}".format(response)) + +# [END cloudasset_generated_asset_v1_AssetService_ListAssets_async] diff --git a/tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_sync.py b/tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_sync.py new file mode 100644 index 0000000000..78dfb91b9e --- /dev/null +++ b/tests/integration/goldens/asset/samples/generated_samples/cloudasset_generated_asset_v1_asset_service_list_assets_sync.py @@ -0,0 +1,45 @@ +# -*- 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for ListAssets +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-asset + + +# [START cloudasset_generated_asset_v1_AssetService_ListAssets_sync] +from google.cloud import asset_v1 + + +def sample_list_assets(): + """Snippet for list_assets""" + + # Create a client + client = asset_v1.AssetServiceClient() + + # Initialize request argument(s) + request = asset_v1.ListAssetsRequest( + ) + + # Make the request + page_result = client.list_assets(request=request) + for response in page_result: + print("{}".format(response)) + +# [END cloudasset_generated_asset_v1_AssetService_ListAssets_sync] diff --git a/tests/integration/goldens/asset/scripts/fixup_asset_v1_keywords.py b/tests/integration/goldens/asset/scripts/fixup_asset_v1_keywords.py index b0cdcf3f4a..4a9e79e96c 100644 --- a/tests/integration/goldens/asset/scripts/fixup_asset_v1_keywords.py +++ b/tests/integration/goldens/asset/scripts/fixup_asset_v1_keywords.py @@ -46,8 +46,9 @@ class assetCallTransformer(cst.CSTTransformer): 'delete_feed': ('name', ), 'export_assets': ('parent', 'output_config', 'read_time', 'asset_types', 'content_type', ), 'get_feed': ('name', ), + 'list_assets': ('parent', 'read_time', 'asset_types', 'content_type', 'page_size', 'page_token', ), 'list_feeds': ('parent', ), - 'search_all_iam_policies': ('scope', 'query', 'page_size', 'page_token', ), + 'search_all_iam_policies': ('scope', 'query', 'page_size', 'page_token', 'asset_types', 'order_by', ), 'search_all_resources': ('scope', 'query', 'asset_types', 'page_size', 'page_token', 'order_by', ), 'update_feed': ('feed', 'update_mask', ), } diff --git a/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py b/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py index 84505a99d1..2d31593c3a 100644 --- a/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py @@ -528,6 +528,423 @@ async def test_export_assets_field_headers_async(): ) in kw['metadata'] +def test_list_assets(transport: str = 'grpc', request_type=asset_service.ListAssetsRequest): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.ListAssetsResponse( + next_page_token='next_page_token_value', + ) + response = client.list_assets(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.ListAssetsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAssetsPager) + assert response.next_page_token == 'next_page_token_value' + + +def test_list_assets_from_dict(): + test_list_assets(request_type=dict) + + +def test_list_assets_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 = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport='grpc', + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + client.list_assets() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.ListAssetsRequest() + + +@pytest.mark.asyncio +async def test_list_assets_async(transport: str = 'grpc_asyncio', request_type=asset_service.ListAssetsRequest): + client = AssetServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value =grpc_helpers_async.FakeUnaryUnaryCall(asset_service.ListAssetsResponse( + next_page_token='next_page_token_value', + )) + response = await client.list_assets(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == asset_service.ListAssetsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAssetsAsyncPager) + assert response.next_page_token == 'next_page_token_value' + + +@pytest.mark.asyncio +async def test_list_assets_async_from_dict(): + await test_list_assets_async(request_type=dict) + + +def test_list_assets_field_headers(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = asset_service.ListAssetsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + call.return_value = asset_service.ListAssetsResponse() + client.list_assets(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +@pytest.mark.asyncio +async def test_list_assets_field_headers_async(): + client = AssetServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = asset_service.ListAssetsRequest() + + request.parent = 'parent/value' + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(asset_service.ListAssetsResponse()) + await client.list_assets(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + 'x-goog-request-params', + 'parent=parent/value', + ) in kw['metadata'] + + +def test_list_assets_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.ListAssetsResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_assets( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +def test_list_assets_flattened_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_assets( + asset_service.ListAssetsRequest(), + parent='parent_value', + ) + + +@pytest.mark.asyncio +async def test_list_assets_flattened_async(): + client = AssetServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + # Designate an appropriate return value for the call. + call.return_value = asset_service.ListAssetsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(asset_service.ListAssetsResponse()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_assets( + parent='parent_value', + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0].parent == 'parent_value' + + +@pytest.mark.asyncio +async def test_list_assets_flattened_error_async(): + client = AssetServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_assets( + asset_service.ListAssetsRequest(), + parent='parent_value', + ) + + +def test_list_assets_pager(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + assets.Asset(), + ], + next_page_token='abc', + ), + asset_service.ListAssetsResponse( + assets=[], + next_page_token='def', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + ], + next_page_token='ghi', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata(( + ('parent', ''), + )), + ) + pager = client.list_assets(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, assets.Asset) + for i in results) + +def test_list_assets_pages(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__') as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + assets.Asset(), + ], + next_page_token='abc', + ), + asset_service.ListAssetsResponse( + assets=[], + next_page_token='def', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + ], + next_page_token='ghi', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + ], + ), + RuntimeError, + ) + pages = list(client.list_assets(request={}).pages) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + +@pytest.mark.asyncio +async def test_list_assets_async_pager(): + client = AssetServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + assets.Asset(), + ], + next_page_token='abc', + ), + asset_service.ListAssetsResponse( + assets=[], + next_page_token='def', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + ], + next_page_token='ghi', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_assets(request={},) + assert async_pager.next_page_token == 'abc' + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, assets.Asset) + for i in responses) + +@pytest.mark.asyncio +async def test_list_assets_async_pages(): + client = AssetServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_assets), + '__call__', new_callable=mock.AsyncMock) as call: + # Set the response to a series of pages. + call.side_effect = ( + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + assets.Asset(), + ], + next_page_token='abc', + ), + asset_service.ListAssetsResponse( + assets=[], + next_page_token='def', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + ], + next_page_token='ghi', + ), + asset_service.ListAssetsResponse( + assets=[ + assets.Asset(), + assets.Asset(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_assets(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ['abc','def','ghi', '']): + assert page_.raw_page.next_page_token == token + def test_batch_get_assets_history(transport: str = 'grpc', request_type=asset_service.BatchGetAssetsHistoryRequest): client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3102,6 +3519,7 @@ def test_asset_service_base_transport(): # raise NotImplementedError. methods = ( 'export_assets', + 'list_assets', 'batch_get_assets_history', 'create_feed', 'get_feed',