From c8cc3e18d2957d3b27290184a97607869a5f1b92 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 23 Jan 2023 16:09:48 +0000 Subject: [PATCH 1/9] chore(deps): update dependency google-cloud-pubsub to v2.14.0 (#538) Co-authored-by: Anthonios Partheniou --- samples/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index d49697a2..89d365bc 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,5 +1,5 @@ google-cloud-storage==2.7.0 google-cloud-asset==3.17.0 google-cloud-resource-manager==1.8.0 -google-cloud-pubsub==2.13.12 +google-cloud-pubsub==2.14.0 google-cloud-bigquery==3.4.2 From a6005621eae86a2a79097af0bbb375fb67d97f00 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 23 Jan 2023 16:36:49 +0000 Subject: [PATCH 2/9] chore(deps): update all dependencies (#540) --- samples/snippets/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 89d365bc..1d7b8245 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,5 +1,5 @@ google-cloud-storage==2.7.0 -google-cloud-asset==3.17.0 -google-cloud-resource-manager==1.8.0 +google-cloud-asset==3.17.1 +google-cloud-resource-manager==1.8.1 google-cloud-pubsub==2.14.0 google-cloud-bigquery==3.4.2 From 231f4e23205c9f8cb7cc33664df81d3621a50c9e Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 25 Jan 2023 11:04:42 -0500 Subject: [PATCH 3/9] chore: Update gapic-generator-python to v1.8.2 (#541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Update gapic-generator-python to v1.8.2 PiperOrigin-RevId: 504289125 Source-Link: https://github.com/googleapis/googleapis/commit/38a48a44a44279e9cf9f2f864b588958a2d87491 Source-Link: https://github.com/googleapis/googleapis-gen/commit/b2dc22663dbe47a972c8d8c2f8a4df013dafdcbc Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiYjJkYzIyNjYzZGJlNDdhOTcyYzhkOGMyZjhhNGRmMDEzZGFmZGNiYyJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * revert Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .coveragerc | 1 + .../snippet_metadata_google.cloud.asset.v1.json | 2 +- .../snippet_metadata_google.cloud.asset.v1p1beta1.json | 2 +- .../snippet_metadata_google.cloud.asset.v1p2beta1.json | 2 +- .../snippet_metadata_google.cloud.asset.v1p5beta1.json | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.coveragerc b/.coveragerc index f5ee43d5..801f6d8a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,6 +5,7 @@ branch = True show_missing = True omit = google/cloud/asset/__init__.py + google/cloud/asset/gapic_version.py exclude_lines = # Re-enable the standard pragma pragma: NO COVER diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json index 746f35c1..5a90dfa8 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.17.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json index 641a7dfc..dcbeb822 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.17.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json index 3191a859..38eaede8 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.17.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json index 909df7ae..13ffc229 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "3.17.1" + "version": "0.1.0" }, "snippets": [ { From e593f527008e30f0c1cccb05d029caeff5c68d68 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:52:37 +0000 Subject: [PATCH 4/9] chore: fix prerelease_deps nox session [autoapprove] (#542) Source-Link: https://togithub.com/googleapis/synthtool/commit/26c7505b2f76981ec1707b851e1595c8c06e90fc Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f946c75373c2b0040e8e318c5e85d0cf46bc6e61d0a01f3ef94d8de974ac6790 --- .github/.OwlBot.lock.yaml | 2 +- noxfile.py | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 889f77df..f0f3b24b 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:c43f1d918bcf817d337aa29ff833439494a158a0831508fda4ec75dc4c0d0320 + digest: sha256:f946c75373c2b0040e8e318c5e85d0cf46bc6e61d0a01f3ef94d8de974ac6790 diff --git a/noxfile.py b/noxfile.py index f322298c..91a45415 100644 --- a/noxfile.py +++ b/noxfile.py @@ -188,9 +188,9 @@ def unit(session): def install_systemtest_dependencies(session, *constraints): # Use pre-release gRPC for system tests. - # Exclude version 1.49.0rc1 which has a known issue. - # See https://github.com/grpc/grpc/pull/30642 - session.install("--pre", "grpcio!=1.49.0rc1") + # Exclude version 1.52.0rc1 which has a known issue. + # See https://github.com/grpc/grpc/issues/32163 + session.install("--pre", "grpcio!=1.52.0rc1") session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES, *constraints) @@ -345,9 +345,7 @@ def prerelease_deps(session): unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES session.install(*unit_deps_all) system_deps_all = ( - SYSTEM_TEST_STANDARD_DEPENDENCIES - + SYSTEM_TEST_EXTERNAL_DEPENDENCIES - + SYSTEM_TEST_EXTRAS + SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES ) session.install(*system_deps_all) @@ -377,8 +375,8 @@ def prerelease_deps(session): # dependency of grpc "six", "googleapis-common-protos", - # Exclude version 1.49.0rc1 which has a known issue. See https://github.com/grpc/grpc/pull/30642 - "grpcio!=1.49.0rc1", + # Exclude version 1.52.0rc1 which has a known issue. See https://github.com/grpc/grpc/issues/32163 + "grpcio!=1.52.0rc1", "grpcio-status", "google-api-core", "proto-plus", From 90b095c54a82ec1250b1e759ca2c7698db2430c5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 2 Feb 2023 10:44:19 +0000 Subject: [PATCH 5/9] chore(deps): update dependency google-cloud-bigquery to v3.5.0 (#544) --- samples/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 1d7b8245..e58324ce 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -2,4 +2,4 @@ google-cloud-storage==2.7.0 google-cloud-asset==3.17.1 google-cloud-resource-manager==1.8.1 google-cloud-pubsub==2.14.0 -google-cloud-bigquery==3.4.2 +google-cloud-bigquery==3.5.0 From c3507fdd5ad75e453ba3314e5a056c99c8203065 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:24:37 +0000 Subject: [PATCH 6/9] build(deps): bump cryptography from 38.0.3 to 39.0.1 in /synthtool/gcp/templates/python_library/.kokoro (#547) Source-Link: https://togithub.com/googleapis/synthtool/commit/bb171351c3946d3c3c32e60f5f18cee8c464ec51 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f62c53736eccb0c4934a3ea9316e0d57696bb49c1a7c86c726e9bb8a2f87dadf --- .github/.OwlBot.lock.yaml | 2 +- .kokoro/requirements.txt | 49 ++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index f0f3b24b..894fb6bc 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:f946c75373c2b0040e8e318c5e85d0cf46bc6e61d0a01f3ef94d8de974ac6790 + digest: sha256:f62c53736eccb0c4934a3ea9316e0d57696bb49c1a7c86c726e9bb8a2f87dadf diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 05dc4672..096e4800 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -113,33 +113,28 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==38.0.3 \ - --hash=sha256:068147f32fa662c81aebab95c74679b401b12b57494872886eb5c1139250ec5d \ - --hash=sha256:06fc3cc7b6f6cca87bd56ec80a580c88f1da5306f505876a71c8cfa7050257dd \ - --hash=sha256:25c1d1f19729fb09d42e06b4bf9895212292cb27bb50229f5aa64d039ab29146 \ - --hash=sha256:402852a0aea73833d982cabb6d0c3bb582c15483d29fb7085ef2c42bfa7e38d7 \ - --hash=sha256:4e269dcd9b102c5a3d72be3c45d8ce20377b8076a43cbed6f660a1afe365e436 \ - --hash=sha256:5419a127426084933076132d317911e3c6eb77568a1ce23c3ac1e12d111e61e0 \ - --hash=sha256:554bec92ee7d1e9d10ded2f7e92a5d70c1f74ba9524947c0ba0c850c7b011828 \ - --hash=sha256:5e89468fbd2fcd733b5899333bc54d0d06c80e04cd23d8c6f3e0542358c6060b \ - --hash=sha256:65535bc550b70bd6271984d9863a37741352b4aad6fb1b3344a54e6950249b55 \ - --hash=sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36 \ - --hash=sha256:6addc3b6d593cd980989261dc1cce38263c76954d758c3c94de51f1e010c9a50 \ - --hash=sha256:728f2694fa743a996d7784a6194da430f197d5c58e2f4e278612b359f455e4a2 \ - --hash=sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a \ - --hash=sha256:78cf5eefac2b52c10398a42765bfa981ce2372cbc0457e6bf9658f41ec3c41d8 \ - --hash=sha256:7f836217000342d448e1c9a342e9163149e45d5b5eca76a30e84503a5a96cab0 \ - --hash=sha256:8d41a46251bf0634e21fac50ffd643216ccecfaf3701a063257fe0b2be1b6548 \ - --hash=sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320 \ - --hash=sha256:9b24bcff7853ed18a63cfb0c2b008936a9554af24af2fb146e16d8e1aed75748 \ - --hash=sha256:b1b35d9d3a65542ed2e9d90115dfd16bbc027b3f07ee3304fc83580f26e43249 \ - --hash=sha256:b1b52c9e5f8aa2b802d48bd693190341fae201ea51c7a167d69fc48b60e8a959 \ - --hash=sha256:bbf203f1a814007ce24bd4d51362991d5cb90ba0c177a9c08825f2cc304d871f \ - --hash=sha256:be243c7e2bfcf6cc4cb350c0d5cdf15ca6383bbcb2a8ef51d3c9411a9d4386f0 \ - --hash=sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd \ - --hash=sha256:c46837ea467ed1efea562bbeb543994c2d1f6e800785bd5a2c98bc096f5cb220 \ - --hash=sha256:dfb4f4dd568de1b6af9f4cda334adf7d72cf5bc052516e1b2608b683375dd95c \ - --hash=sha256:ed7b00096790213e09eb11c97cc6e2b757f15f3d2f85833cd2d3ec3fe37c1722 +cryptography==39.0.1 \ + --hash=sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4 \ + --hash=sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f \ + --hash=sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502 \ + --hash=sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41 \ + --hash=sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965 \ + --hash=sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e \ + --hash=sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc \ + --hash=sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad \ + --hash=sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505 \ + --hash=sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388 \ + --hash=sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6 \ + --hash=sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2 \ + --hash=sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac \ + --hash=sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695 \ + --hash=sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6 \ + --hash=sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336 \ + --hash=sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0 \ + --hash=sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c \ + --hash=sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106 \ + --hash=sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a \ + --hash=sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8 # via # gcp-releasetool # secretstorage From 5189a57e92724f9bda63b198dd5cf68489cc5c66 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 16 Feb 2023 15:13:24 +0000 Subject: [PATCH 7/9] chore(deps): update dependency google-cloud-pubsub to v2.14.1 (#548) --- samples/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index e58324ce..2895d7be 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,5 +1,5 @@ google-cloud-storage==2.7.0 google-cloud-asset==3.17.1 google-cloud-resource-manager==1.8.1 -google-cloud-pubsub==2.14.0 +google-cloud-pubsub==2.14.1 google-cloud-bigquery==3.5.0 From e6bd01b917e1a42157e8a0d8ea05de79462b02c7 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Sun, 19 Feb 2023 05:35:36 -0500 Subject: [PATCH 8/9] feat: enable "rest" transport in Python for services supporting numeric enums (#549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: enable "rest" transport in Python for services supporting numeric enums PiperOrigin-RevId: 508143576 Source-Link: https://github.com/googleapis/googleapis/commit/7a702a989db3b413f39ff8994ca53fb38b6928c2 Source-Link: https://github.com/googleapis/googleapis-gen/commit/6ad1279c0e7aa787ac6b66c9fd4a210692edffcd Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNmFkMTI3OWMwZTdhYTc4N2FjNmI2NmM5ZmQ0YTIxMDY5MmVkZmZjZCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * revert * Update samples and tests to use REST transport * revert * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * fix typo * add pytest import * lint * fix tests * fix: Add service_yaml_parameters to py_gapic_library BUILD.bazel targets PiperOrigin-RevId: 510187992 Source-Link: https://github.com/googleapis/googleapis/commit/5edc23561778df80d5293f20132765f8757a6b2c Source-Link: https://github.com/googleapis/googleapis-gen/commit/b0bedb72e4765a3e0b674a28c50ea0f9a9b26a89 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiYjBiZWRiNzJlNDc2NWEzZTBiNjc0YTI4YzUwZWEwZjlhOWIyNmE4OSJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * revert * update tests to allow running both grpc and rest * remove transport for fixture * only test grpc for eventually_consistent_test * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * lint * fix tests * revert changes to test for rest transport * lint * fix test * testing * fix test --------- Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- google/cloud/asset_v1/gapic_metadata.json | 120 + .../services/asset_service/async_client.py | 55 + .../asset_v1/services/asset_service/client.py | 57 + .../asset_service/transports/__init__.py | 5 + .../services/asset_service/transports/base.py | 10 + .../services/asset_service/transports/grpc.py | 18 + .../asset_service/transports/grpc_asyncio.py | 18 + .../services/asset_service/transports/rest.py | 3332 ++++++++ .../cloud/asset_v1p1beta1/gapic_metadata.json | 15 + .../services/asset_service/async_client.py | 1 + .../services/asset_service/client.py | 3 + .../asset_service/transports/__init__.py | 5 + .../services/asset_service/transports/base.py | 1 + .../services/asset_service/transports/grpc.py | 1 + .../asset_service/transports/grpc_asyncio.py | 1 + .../services/asset_service/transports/rest.py | 441 + .../cloud/asset_v1p2beta1/gapic_metadata.json | 30 + .../services/asset_service/client.py | 2 + .../asset_service/transports/__init__.py | 5 + .../services/asset_service/transports/rest.py | 808 ++ .../cloud/asset_v1p5beta1/gapic_metadata.json | 10 + .../services/asset_service/async_client.py | 1 + .../services/asset_service/client.py | 3 + .../asset_service/transports/__init__.py | 5 + .../services/asset_service/transports/base.py | 1 + .../services/asset_service/transports/grpc.py | 1 + .../asset_service/transports/grpc_asyncio.py | 1 + .../services/asset_service/transports/rest.py | 306 + .../snippets/quickstart_analyzeiampolicy.py | 10 +- .../quickstart_analyzeiampolicy_test.py | 6 +- .../quickstart_analyzeiampolicylongrunning.py | 33 +- ...kstart_analyzeiampolicylongrunning_test.py | 12 +- .../quickstart_batchgetassetshistory.py | 16 +- .../quickstart_batchgetassetshistory_test.py | 4 +- .../quickstart_batchgeteffectiveiampolicy.py | 18 +- ...ckstart_batchgeteffectiveiampolicy_test.py | 8 +- .../snippets/quickstart_create_saved_query.py | 15 +- .../quickstart_create_saved_query_test.py | 11 +- samples/snippets/quickstart_createfeed.py | 24 +- .../snippets/quickstart_createfeed_test.py | 22 +- .../snippets/quickstart_delete_saved_query.py | 11 +- .../quickstart_delete_saved_query_test.py | 4 +- samples/snippets/quickstart_deletefeed.py | 11 +- .../snippets/quickstart_deletefeed_test.py | 3 +- samples/snippets/quickstart_exportassets.py | 34 +- .../snippets/quickstart_exportassets_test.py | 19 +- .../snippets/quickstart_get_saved_query.py | 5 +- .../quickstart_get_saved_query_test.py | 9 +- samples/snippets/quickstart_getfeed.py | 5 +- samples/snippets/quickstart_getfeed_test.py | 7 +- .../snippets/quickstart_list_saved_queries.py | 5 +- .../quickstart_list_saved_queries_test.py | 8 +- samples/snippets/quickstart_listassets.py | 7 +- .../snippets/quickstart_listassets_test.py | 6 +- samples/snippets/quickstart_listfeeds.py | 5 +- samples/snippets/quickstart_listfeeds_test.py | 6 +- .../quickstart_searchalliampolicies.py | 5 +- .../quickstart_searchalliampolicies_test.py | 8 +- .../snippets/quickstart_searchallresources.py | 13 +- .../quickstart_searchallresources_test.py | 4 +- .../snippets/quickstart_update_saved_query.py | 12 +- .../quickstart_update_saved_query_test.py | 9 +- samples/snippets/quickstart_updatefeed.py | 12 +- .../snippets/quickstart_updatefeed_test.py | 11 +- tests/system/test_vpcsc.py | 29 +- .../unit/gapic/asset_v1/test_asset_service.py | 7363 ++++++++++++++++- .../asset_v1p1beta1/test_asset_service.py | 778 +- .../asset_v1p2beta1/test_asset_service.py | 1722 +++- .../asset_v1p5beta1/test_asset_service.py | 421 +- 69 files changed, 15546 insertions(+), 421 deletions(-) create mode 100644 google/cloud/asset_v1/services/asset_service/transports/rest.py create mode 100644 google/cloud/asset_v1p1beta1/services/asset_service/transports/rest.py create mode 100644 google/cloud/asset_v1p2beta1/services/asset_service/transports/rest.py create mode 100644 google/cloud/asset_v1p5beta1/services/asset_service/transports/rest.py diff --git a/google/cloud/asset_v1/gapic_metadata.json b/google/cloud/asset_v1/gapic_metadata.json index 0563d863..e39e5043 100644 --- a/google/cloud/asset_v1/gapic_metadata.json +++ b/google/cloud/asset_v1/gapic_metadata.json @@ -246,6 +246,126 @@ ] } } + }, + "rest": { + "libraryClient": "AssetServiceClient", + "rpcs": { + "AnalyzeIamPolicy": { + "methods": [ + "analyze_iam_policy" + ] + }, + "AnalyzeIamPolicyLongrunning": { + "methods": [ + "analyze_iam_policy_longrunning" + ] + }, + "AnalyzeMove": { + "methods": [ + "analyze_move" + ] + }, + "AnalyzeOrgPolicies": { + "methods": [ + "analyze_org_policies" + ] + }, + "AnalyzeOrgPolicyGovernedAssets": { + "methods": [ + "analyze_org_policy_governed_assets" + ] + }, + "AnalyzeOrgPolicyGovernedContainers": { + "methods": [ + "analyze_org_policy_governed_containers" + ] + }, + "BatchGetAssetsHistory": { + "methods": [ + "batch_get_assets_history" + ] + }, + "BatchGetEffectiveIamPolicies": { + "methods": [ + "batch_get_effective_iam_policies" + ] + }, + "CreateFeed": { + "methods": [ + "create_feed" + ] + }, + "CreateSavedQuery": { + "methods": [ + "create_saved_query" + ] + }, + "DeleteFeed": { + "methods": [ + "delete_feed" + ] + }, + "DeleteSavedQuery": { + "methods": [ + "delete_saved_query" + ] + }, + "ExportAssets": { + "methods": [ + "export_assets" + ] + }, + "GetFeed": { + "methods": [ + "get_feed" + ] + }, + "GetSavedQuery": { + "methods": [ + "get_saved_query" + ] + }, + "ListAssets": { + "methods": [ + "list_assets" + ] + }, + "ListFeeds": { + "methods": [ + "list_feeds" + ] + }, + "ListSavedQueries": { + "methods": [ + "list_saved_queries" + ] + }, + "QueryAssets": { + "methods": [ + "query_assets" + ] + }, + "SearchAllIamPolicies": { + "methods": [ + "search_all_iam_policies" + ] + }, + "SearchAllResources": { + "methods": [ + "search_all_resources" + ] + }, + "UpdateFeed": { + "methods": [ + "update_feed" + ] + }, + "UpdateSavedQuery": { + "methods": [ + "update_saved_query" + ] + } + } } } } diff --git a/google/cloud/asset_v1/services/asset_service/async_client.py b/google/cloud/asset_v1/services/asset_service/async_client.py index 8ab5394c..3fd04b30 100644 --- a/google/cloud/asset_v1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1/services/asset_service/async_client.py @@ -47,6 +47,7 @@ from google.cloud.asset_v1.services.asset_service import pagers from google.cloud.asset_v1.types import asset_service from google.cloud.asset_v1.types import assets +from google.longrunning import operations_pb2 from google.protobuf import field_mask_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore @@ -3139,6 +3140,60 @@ async def sample_analyze_org_policy_governed_assets(): # Done; return the response. return response + async def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + 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: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # 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): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + 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((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + async def __aenter__(self): return self diff --git a/google/cloud/asset_v1/services/asset_service/client.py b/google/cloud/asset_v1/services/asset_service/client.py index caac68b4..002888ab 100644 --- a/google/cloud/asset_v1/services/asset_service/client.py +++ b/google/cloud/asset_v1/services/asset_service/client.py @@ -51,6 +51,7 @@ from google.cloud.asset_v1.services.asset_service import pagers from google.cloud.asset_v1.types import asset_service from google.cloud.asset_v1.types import assets +from google.longrunning import operations_pb2 from google.protobuf import field_mask_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore @@ -58,6 +59,7 @@ from .transports.base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AssetServiceGrpcTransport from .transports.grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .transports.rest import AssetServiceRestTransport class AssetServiceClientMeta(type): @@ -71,6 +73,7 @@ class AssetServiceClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport + _transport_registry["rest"] = AssetServiceRestTransport def get_transport_class( cls, @@ -3355,6 +3358,60 @@ def __exit__(self, type, value, traceback): """ self.transport.close() + def get_operation( + self, + request: Optional[operations_pb2.GetOperationRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message for + `GetOperation` method. + 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: + ~.operations_pb2.Operation: + An ``Operation`` object. + """ + # 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): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + 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((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/asset_v1/services/asset_service/transports/__init__.py b/google/cloud/asset_v1/services/asset_service/transports/__init__.py index c3ef619a..58f49f56 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/__init__.py +++ b/google/cloud/asset_v1/services/asset_service/transports/__init__.py @@ -19,15 +19,20 @@ from .base import AssetServiceTransport from .grpc import AssetServiceGrpcTransport from .grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .rest import AssetServiceRestTransport +from .rest import AssetServiceRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport +_transport_registry["rest"] = AssetServiceRestTransport __all__ = ( "AssetServiceTransport", "AssetServiceGrpcTransport", "AssetServiceGrpcAsyncIOTransport", + "AssetServiceRestTransport", + "AssetServiceRestInterceptor", ) diff --git a/google/cloud/asset_v1/services/asset_service/transports/base.py b/google/cloud/asset_v1/services/asset_service/transports/base.py index 8babe8ee..8e6f88fe 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1/services/asset_service/transports/base.py @@ -28,6 +28,7 @@ from google.oauth2 import service_account # type: ignore from google.cloud.asset_v1.types import asset_service +from google.longrunning import operations_pb2 from google.longrunning import operations_pb2 # type: ignore from google.protobuf import empty_pb2 # type: ignore @@ -627,6 +628,15 @@ def analyze_org_policy_governed_assets( ]: raise NotImplementedError() + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/asset_v1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1/services/asset_service/transports/grpc.py index a60456e5..a2f2a8c6 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc.py @@ -26,6 +26,7 @@ import grpc # type: ignore from google.cloud.asset_v1.types import asset_service +from google.longrunning import operations_pb2 from google.longrunning import operations_pb2 # type: ignore from google.protobuf import empty_pb2 # type: ignore from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO @@ -970,6 +971,23 @@ def analyze_org_policy_governed_assets( def close(self): self.grpc_channel.close() + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # 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 "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + @property def kind(self) -> str: return "grpc" diff --git a/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py index b856bb4a..00529bf1 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py @@ -26,6 +26,7 @@ from grpc.experimental import aio # type: ignore from google.cloud.asset_v1.types import asset_service +from google.longrunning import operations_pb2 from google.longrunning import operations_pb2 # type: ignore from google.protobuf import empty_pb2 # type: ignore from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO @@ -992,5 +993,22 @@ def analyze_org_policy_governed_assets( def close(self): return self.grpc_channel.close() + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # 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 "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + __all__ = ("AssetServiceGrpcAsyncIOTransport",) diff --git a/google/cloud/asset_v1/services/asset_service/transports/rest.py b/google/cloud/asset_v1/services/asset_service/transports/rest.py new file mode 100644 index 00000000..8f147404 --- /dev/null +++ b/google/cloud/asset_v1/services/asset_service/transports/rest.py @@ -0,0 +1,3332 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# + +from google.auth.transport.requests import AuthorizedSession # type: ignore +import json # type: ignore +import grpc # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.api_core import rest_helpers +from google.api_core import rest_streaming +from google.api_core import path_template +from google.api_core import gapic_v1 + +from google.protobuf import json_format +from google.api_core import operations_v1 +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.asset_v1.types import asset_service +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AssetServiceRestInterceptor: + """Interceptor for AssetService. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AssetServiceRestTransport. + + .. code-block:: python + class MyCustomAssetServiceInterceptor(AssetServiceRestInterceptor): + def pre_analyze_iam_policy(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_iam_policy(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_analyze_iam_policy_longrunning(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_iam_policy_longrunning(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_analyze_move(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_move(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_analyze_org_policies(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_org_policies(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_analyze_org_policy_governed_assets(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_org_policy_governed_assets(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_analyze_org_policy_governed_containers(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_org_policy_governed_containers(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_get_assets_history(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_get_assets_history(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_get_effective_iam_policies(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_get_effective_iam_policies(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_feed(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_saved_query(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_saved_query(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_delete_saved_query(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_assets(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_assets(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_feed(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_saved_query(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_saved_query(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_assets(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_assets(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_feeds(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_feeds(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_saved_queries(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_saved_queries(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_query_assets(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_query_assets(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_search_all_iam_policies(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_search_all_iam_policies(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_search_all_resources(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_search_all_resources(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_feed(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_saved_query(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_saved_query(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AssetServiceRestTransport(interceptor=MyCustomAssetServiceInterceptor()) + client = AssetServiceClient(transport=transport) + + + """ + + def pre_analyze_iam_policy( + self, + request: asset_service.AnalyzeIamPolicyRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.AnalyzeIamPolicyRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for analyze_iam_policy + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_analyze_iam_policy( + self, response: asset_service.AnalyzeIamPolicyResponse + ) -> asset_service.AnalyzeIamPolicyResponse: + """Post-rpc interceptor for analyze_iam_policy + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_analyze_iam_policy_longrunning( + self, + request: asset_service.AnalyzeIamPolicyLongrunningRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + asset_service.AnalyzeIamPolicyLongrunningRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for analyze_iam_policy_longrunning + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_analyze_iam_policy_longrunning( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for analyze_iam_policy_longrunning + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_analyze_move( + self, + request: asset_service.AnalyzeMoveRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.AnalyzeMoveRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for analyze_move + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_analyze_move( + self, response: asset_service.AnalyzeMoveResponse + ) -> asset_service.AnalyzeMoveResponse: + """Post-rpc interceptor for analyze_move + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_analyze_org_policies( + self, + request: asset_service.AnalyzeOrgPoliciesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.AnalyzeOrgPoliciesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for analyze_org_policies + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_analyze_org_policies( + self, response: asset_service.AnalyzeOrgPoliciesResponse + ) -> asset_service.AnalyzeOrgPoliciesResponse: + """Post-rpc interceptor for analyze_org_policies + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_analyze_org_policy_governed_assets( + self, + request: asset_service.AnalyzeOrgPolicyGovernedAssetsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + asset_service.AnalyzeOrgPolicyGovernedAssetsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for analyze_org_policy_governed_assets + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_analyze_org_policy_governed_assets( + self, response: asset_service.AnalyzeOrgPolicyGovernedAssetsResponse + ) -> asset_service.AnalyzeOrgPolicyGovernedAssetsResponse: + """Post-rpc interceptor for analyze_org_policy_governed_assets + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_analyze_org_policy_governed_containers( + self, + request: asset_service.AnalyzeOrgPolicyGovernedContainersRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + asset_service.AnalyzeOrgPolicyGovernedContainersRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for analyze_org_policy_governed_containers + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_analyze_org_policy_governed_containers( + self, response: asset_service.AnalyzeOrgPolicyGovernedContainersResponse + ) -> asset_service.AnalyzeOrgPolicyGovernedContainersResponse: + """Post-rpc interceptor for analyze_org_policy_governed_containers + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_batch_get_assets_history( + self, + request: asset_service.BatchGetAssetsHistoryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.BatchGetAssetsHistoryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_get_assets_history + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_batch_get_assets_history( + self, response: asset_service.BatchGetAssetsHistoryResponse + ) -> asset_service.BatchGetAssetsHistoryResponse: + """Post-rpc interceptor for batch_get_assets_history + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_batch_get_effective_iam_policies( + self, + request: asset_service.BatchGetEffectiveIamPoliciesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + asset_service.BatchGetEffectiveIamPoliciesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for batch_get_effective_iam_policies + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_batch_get_effective_iam_policies( + self, response: asset_service.BatchGetEffectiveIamPoliciesResponse + ) -> asset_service.BatchGetEffectiveIamPoliciesResponse: + """Post-rpc interceptor for batch_get_effective_iam_policies + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_create_feed( + self, + request: asset_service.CreateFeedRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.CreateFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_create_feed(self, response: asset_service.Feed) -> asset_service.Feed: + """Post-rpc interceptor for create_feed + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_create_saved_query( + self, + request: asset_service.CreateSavedQueryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.CreateSavedQueryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_saved_query + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_create_saved_query( + self, response: asset_service.SavedQuery + ) -> asset_service.SavedQuery: + """Post-rpc interceptor for create_saved_query + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_delete_feed( + self, + request: asset_service.DeleteFeedRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.DeleteFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def pre_delete_saved_query( + self, + request: asset_service.DeleteSavedQueryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.DeleteSavedQueryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_saved_query + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def pre_export_assets( + self, + request: asset_service.ExportAssetsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.ExportAssetsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_assets + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_export_assets( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_assets + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_get_feed( + self, request: asset_service.GetFeedRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[asset_service.GetFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_get_feed(self, response: asset_service.Feed) -> asset_service.Feed: + """Post-rpc interceptor for get_feed + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_get_saved_query( + self, + request: asset_service.GetSavedQueryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.GetSavedQueryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_saved_query + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_get_saved_query( + self, response: asset_service.SavedQuery + ) -> asset_service.SavedQuery: + """Post-rpc interceptor for get_saved_query + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_list_assets( + self, + request: asset_service.ListAssetsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.ListAssetsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_assets + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_list_assets( + self, response: asset_service.ListAssetsResponse + ) -> asset_service.ListAssetsResponse: + """Post-rpc interceptor for list_assets + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_list_feeds( + self, + request: asset_service.ListFeedsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.ListFeedsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_feeds + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_list_feeds( + self, response: asset_service.ListFeedsResponse + ) -> asset_service.ListFeedsResponse: + """Post-rpc interceptor for list_feeds + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_list_saved_queries( + self, + request: asset_service.ListSavedQueriesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.ListSavedQueriesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_saved_queries + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_list_saved_queries( + self, response: asset_service.ListSavedQueriesResponse + ) -> asset_service.ListSavedQueriesResponse: + """Post-rpc interceptor for list_saved_queries + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_query_assets( + self, + request: asset_service.QueryAssetsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.QueryAssetsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for query_assets + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_query_assets( + self, response: asset_service.QueryAssetsResponse + ) -> asset_service.QueryAssetsResponse: + """Post-rpc interceptor for query_assets + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_search_all_iam_policies( + self, + request: asset_service.SearchAllIamPoliciesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.SearchAllIamPoliciesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for search_all_iam_policies + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_search_all_iam_policies( + self, response: asset_service.SearchAllIamPoliciesResponse + ) -> asset_service.SearchAllIamPoliciesResponse: + """Post-rpc interceptor for search_all_iam_policies + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_search_all_resources( + self, + request: asset_service.SearchAllResourcesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.SearchAllResourcesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for search_all_resources + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_search_all_resources( + self, response: asset_service.SearchAllResourcesResponse + ) -> asset_service.SearchAllResourcesResponse: + """Post-rpc interceptor for search_all_resources + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_update_feed( + self, + request: asset_service.UpdateFeedRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.UpdateFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_update_feed(self, response: asset_service.Feed) -> asset_service.Feed: + """Post-rpc interceptor for update_feed + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_update_saved_query( + self, + request: asset_service.UpdateSavedQueryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.UpdateSavedQueryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_saved_query + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_update_saved_query( + self, response: asset_service.SavedQuery + ) -> asset_service.SavedQuery: + """Post-rpc interceptor for update_saved_query + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> operations_pb2.Operation: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.GetOperationRequest + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AssetServiceRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AssetServiceRestInterceptor + + +class AssetServiceRestTransport(AssetServiceTransport): + """REST backend transport for AssetService. + + Asset service definition. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "cloudasset.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AssetServiceRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AssetServiceRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v1/{name=*/*/operations/*/**}", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _AnalyzeIamPolicy(AssetServiceRestStub): + def __hash__(self): + return hash("AnalyzeIamPolicy") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "analysisQuery": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.AnalyzeIamPolicyRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeIamPolicyResponse: + r"""Call the analyze iam policy method over HTTP. + + Args: + request (~.asset_service.AnalyzeIamPolicyRequest): + The request object. A request message for + [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. + + 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: + ~.asset_service.AnalyzeIamPolicyResponse: + A response message for + [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{analysis_query.scope=*/*}:analyzeIamPolicy", + }, + ] + request, metadata = self._interceptor.pre_analyze_iam_policy( + request, metadata + ) + pb_request = asset_service.AnalyzeIamPolicyRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.AnalyzeIamPolicyResponse() + pb_resp = asset_service.AnalyzeIamPolicyResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_iam_policy(resp) + return resp + + class _AnalyzeIamPolicyLongrunning(AssetServiceRestStub): + def __hash__(self): + return hash("AnalyzeIamPolicyLongrunning") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.AnalyzeIamPolicyLongrunningRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the analyze iam policy + longrunning method over HTTP. + + Args: + request (~.asset_service.AnalyzeIamPolicyLongrunningRequest): + The request object. A request message for + [AssetService.AnalyzeIamPolicyLongrunning][google.cloud.asset.v1.AssetService.AnalyzeIamPolicyLongrunning]. + + 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: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1/{analysis_query.scope=*/*}:analyzeIamPolicyLongrunning", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_analyze_iam_policy_longrunning( + request, metadata + ) + pb_request = asset_service.AnalyzeIamPolicyLongrunningRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_iam_policy_longrunning(resp) + return resp + + class _AnalyzeMove(AssetServiceRestStub): + def __hash__(self): + return hash("AnalyzeMove") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "destinationParent": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.AnalyzeMoveRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeMoveResponse: + r"""Call the analyze move method over HTTP. + + Args: + request (~.asset_service.AnalyzeMoveRequest): + The request object. The request message for performing + resource move analysis. + + 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: + ~.asset_service.AnalyzeMoveResponse: + The response message for resource + move analysis. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{resource=*/*}:analyzeMove", + }, + ] + request, metadata = self._interceptor.pre_analyze_move(request, metadata) + pb_request = asset_service.AnalyzeMoveRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.AnalyzeMoveResponse() + pb_resp = asset_service.AnalyzeMoveResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_move(resp) + return resp + + class _AnalyzeOrgPolicies(AssetServiceRestStub): + def __hash__(self): + return hash("AnalyzeOrgPolicies") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "constraint": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.AnalyzeOrgPoliciesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeOrgPoliciesResponse: + r"""Call the analyze org policies method over HTTP. + + Args: + request (~.asset_service.AnalyzeOrgPoliciesRequest): + The request object. A request message for + [AssetService.AnalyzeOrgPolicies][google.cloud.asset.v1.AssetService.AnalyzeOrgPolicies]. + + 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: + ~.asset_service.AnalyzeOrgPoliciesResponse: + The response message for + [AssetService.AnalyzeOrgPolicies][google.cloud.asset.v1.AssetService.AnalyzeOrgPolicies]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{scope=*/*}:analyzeOrgPolicies", + }, + ] + request, metadata = self._interceptor.pre_analyze_org_policies( + request, metadata + ) + pb_request = asset_service.AnalyzeOrgPoliciesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.AnalyzeOrgPoliciesResponse() + pb_resp = asset_service.AnalyzeOrgPoliciesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_org_policies(resp) + return resp + + class _AnalyzeOrgPolicyGovernedAssets(AssetServiceRestStub): + def __hash__(self): + return hash("AnalyzeOrgPolicyGovernedAssets") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "constraint": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.AnalyzeOrgPolicyGovernedAssetsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeOrgPolicyGovernedAssetsResponse: + r"""Call the analyze org policy + governed assets method over HTTP. + + Args: + request (~.asset_service.AnalyzeOrgPolicyGovernedAssetsRequest): + The request object. A request message for + [AssetService.AnalyzeOrgPolicyGovernedAssets][google.cloud.asset.v1.AssetService.AnalyzeOrgPolicyGovernedAssets]. + + 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: + ~.asset_service.AnalyzeOrgPolicyGovernedAssetsResponse: + The response message for + [AssetService.AnalyzeOrgPolicyGovernedAssets][google.cloud.asset.v1.AssetService.AnalyzeOrgPolicyGovernedAssets]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{scope=*/*}:analyzeOrgPolicyGovernedAssets", + }, + ] + ( + request, + metadata, + ) = self._interceptor.pre_analyze_org_policy_governed_assets( + request, metadata + ) + pb_request = asset_service.AnalyzeOrgPolicyGovernedAssetsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse() + pb_resp = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_org_policy_governed_assets(resp) + return resp + + class _AnalyzeOrgPolicyGovernedContainers(AssetServiceRestStub): + def __hash__(self): + return hash("AnalyzeOrgPolicyGovernedContainers") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "constraint": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.AnalyzeOrgPolicyGovernedContainersRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.AnalyzeOrgPolicyGovernedContainersResponse: + r"""Call the analyze org policy + governed containers method over HTTP. + + Args: + request (~.asset_service.AnalyzeOrgPolicyGovernedContainersRequest): + The request object. A request message for + [AssetService.AnalyzeOrgPolicyGovernedContainers][google.cloud.asset.v1.AssetService.AnalyzeOrgPolicyGovernedContainers]. + + 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: + ~.asset_service.AnalyzeOrgPolicyGovernedContainersResponse: + The response message for + [AssetService.AnalyzeOrgPolicyGovernedContainers][google.cloud.asset.v1.AssetService.AnalyzeOrgPolicyGovernedContainers]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{scope=*/*}:analyzeOrgPolicyGovernedContainers", + }, + ] + ( + request, + metadata, + ) = self._interceptor.pre_analyze_org_policy_governed_containers( + request, metadata + ) + pb_request = asset_service.AnalyzeOrgPolicyGovernedContainersRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.AnalyzeOrgPolicyGovernedContainersResponse() + pb_resp = asset_service.AnalyzeOrgPolicyGovernedContainersResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_org_policy_governed_containers(resp) + return resp + + class _BatchGetAssetsHistory(AssetServiceRestStub): + def __hash__(self): + return hash("BatchGetAssetsHistory") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.BatchGetAssetsHistoryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.BatchGetAssetsHistoryResponse: + r"""Call the batch get assets history method over HTTP. + + Args: + request (~.asset_service.BatchGetAssetsHistoryRequest): + The request object. Batch get assets history request. + 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: + ~.asset_service.BatchGetAssetsHistoryResponse: + Batch get assets history response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{parent=*/*}:batchGetAssetsHistory", + }, + ] + request, metadata = self._interceptor.pre_batch_get_assets_history( + request, metadata + ) + pb_request = asset_service.BatchGetAssetsHistoryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.BatchGetAssetsHistoryResponse() + pb_resp = asset_service.BatchGetAssetsHistoryResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_get_assets_history(resp) + return resp + + class _BatchGetEffectiveIamPolicies(AssetServiceRestStub): + def __hash__(self): + return hash("BatchGetEffectiveIamPolicies") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "names": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.BatchGetEffectiveIamPoliciesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.BatchGetEffectiveIamPoliciesResponse: + r"""Call the batch get effective iam + policies method over HTTP. + + Args: + request (~.asset_service.BatchGetEffectiveIamPoliciesRequest): + The request object. A request message for + [AssetService.BatchGetEffectiveIamPolicies][google.cloud.asset.v1.AssetService.BatchGetEffectiveIamPolicies]. + + 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: + ~.asset_service.BatchGetEffectiveIamPoliciesResponse: + A response message for + [AssetService.BatchGetEffectiveIamPolicies][google.cloud.asset.v1.AssetService.BatchGetEffectiveIamPolicies]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{scope=*/*}/effectiveIamPolicies:batchGet", + }, + ] + request, metadata = self._interceptor.pre_batch_get_effective_iam_policies( + request, metadata + ) + pb_request = asset_service.BatchGetEffectiveIamPoliciesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.BatchGetEffectiveIamPoliciesResponse() + pb_resp = asset_service.BatchGetEffectiveIamPoliciesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_get_effective_iam_policies(resp) + return resp + + class _CreateFeed(AssetServiceRestStub): + def __hash__(self): + return hash("CreateFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.CreateFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.Feed: + r"""Call the create feed method over HTTP. + + Args: + request (~.asset_service.CreateFeedRequest): + The request object. Create asset feed request. + 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: + ~.asset_service.Feed: + An asset feed used to export asset + updates to a destinations. An asset feed + filter controls what updates are + exported. The asset feed must be created + within a project, organization, or + folder. Supported destinations are: + Pub/Sub topics. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1/{parent=*/*}/feeds", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_create_feed(request, metadata) + pb_request = asset_service.CreateFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.Feed() + pb_resp = asset_service.Feed.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_feed(resp) + return resp + + class _CreateSavedQuery(AssetServiceRestStub): + def __hash__(self): + return hash("CreateSavedQuery") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "savedQueryId": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.CreateSavedQueryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SavedQuery: + r"""Call the create saved query method over HTTP. + + Args: + request (~.asset_service.CreateSavedQueryRequest): + The request object. Request to create a saved query. + 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: + ~.asset_service.SavedQuery: + A saved query which can be shared + with others or used later. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1/{parent=*/*}/savedQueries", + "body": "saved_query", + }, + ] + request, metadata = self._interceptor.pre_create_saved_query( + request, metadata + ) + pb_request = asset_service.CreateSavedQueryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SavedQuery() + pb_resp = asset_service.SavedQuery.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_saved_query(resp) + return resp + + class _DeleteFeed(AssetServiceRestStub): + def __hash__(self): + return hash("DeleteFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.DeleteFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete feed method over HTTP. + + Args: + request (~.asset_service.DeleteFeedRequest): + The request object. + 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v1/{name=*/*/feeds/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_feed(request, metadata) + pb_request = asset_service.DeleteFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _DeleteSavedQuery(AssetServiceRestStub): + def __hash__(self): + return hash("DeleteSavedQuery") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.DeleteSavedQueryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete saved query method over HTTP. + + Args: + request (~.asset_service.DeleteSavedQueryRequest): + The request object. Request to delete a saved query. + 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v1/{name=*/*/savedQueries/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_saved_query( + request, metadata + ) + pb_request = asset_service.DeleteSavedQueryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _ExportAssets(AssetServiceRestStub): + def __hash__(self): + return hash("ExportAssets") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.ExportAssetsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export assets method over HTTP. + + Args: + request (~.asset_service.ExportAssetsRequest): + The request object. Export asset request. + 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: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1/{parent=*/*}:exportAssets", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_assets(request, metadata) + pb_request = asset_service.ExportAssetsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_export_assets(resp) + return resp + + class _GetFeed(AssetServiceRestStub): + def __hash__(self): + return hash("GetFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.GetFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.Feed: + r"""Call the get feed method over HTTP. + + Args: + request (~.asset_service.GetFeedRequest): + The request object. Get asset feed request. + 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: + ~.asset_service.Feed: + An asset feed used to export asset + updates to a destinations. An asset feed + filter controls what updates are + exported. The asset feed must be created + within a project, organization, or + folder. Supported destinations are: + Pub/Sub topics. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{name=*/*/feeds/*}", + }, + ] + request, metadata = self._interceptor.pre_get_feed(request, metadata) + pb_request = asset_service.GetFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.Feed() + pb_resp = asset_service.Feed.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_feed(resp) + return resp + + class _GetSavedQuery(AssetServiceRestStub): + def __hash__(self): + return hash("GetSavedQuery") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.GetSavedQueryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SavedQuery: + r"""Call the get saved query method over HTTP. + + Args: + request (~.asset_service.GetSavedQueryRequest): + The request object. Request to get a saved query. + 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: + ~.asset_service.SavedQuery: + A saved query which can be shared + with others or used later. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{name=*/*/savedQueries/*}", + }, + ] + request, metadata = self._interceptor.pre_get_saved_query(request, metadata) + pb_request = asset_service.GetSavedQueryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SavedQuery() + pb_resp = asset_service.SavedQuery.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_saved_query(resp) + return resp + + class _ListAssets(AssetServiceRestStub): + def __hash__(self): + return hash("ListAssets") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.ListAssetsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.ListAssetsResponse: + r"""Call the list assets method over HTTP. + + Args: + request (~.asset_service.ListAssetsRequest): + The request object. ListAssets request. + 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: + ~.asset_service.ListAssetsResponse: + ListAssets response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{parent=*/*}/assets", + }, + ] + request, metadata = self._interceptor.pre_list_assets(request, metadata) + pb_request = asset_service.ListAssetsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.ListAssetsResponse() + pb_resp = asset_service.ListAssetsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_assets(resp) + return resp + + class _ListFeeds(AssetServiceRestStub): + def __hash__(self): + return hash("ListFeeds") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.ListFeedsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.ListFeedsResponse: + r"""Call the list feeds method over HTTP. + + Args: + request (~.asset_service.ListFeedsRequest): + The request object. List asset feeds request. + 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: + ~.asset_service.ListFeedsResponse: + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{parent=*/*}/feeds", + }, + ] + request, metadata = self._interceptor.pre_list_feeds(request, metadata) + pb_request = asset_service.ListFeedsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.ListFeedsResponse() + pb_resp = asset_service.ListFeedsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_feeds(resp) + return resp + + class _ListSavedQueries(AssetServiceRestStub): + def __hash__(self): + return hash("ListSavedQueries") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.ListSavedQueriesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.ListSavedQueriesResponse: + r"""Call the list saved queries method over HTTP. + + Args: + request (~.asset_service.ListSavedQueriesRequest): + The request object. Request to list saved queries. + 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: + ~.asset_service.ListSavedQueriesResponse: + Response of listing saved queries. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{parent=*/*}/savedQueries", + }, + ] + request, metadata = self._interceptor.pre_list_saved_queries( + request, metadata + ) + pb_request = asset_service.ListSavedQueriesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.ListSavedQueriesResponse() + pb_resp = asset_service.ListSavedQueriesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_saved_queries(resp) + return resp + + class _QueryAssets(AssetServiceRestStub): + def __hash__(self): + return hash("QueryAssets") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.QueryAssetsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.QueryAssetsResponse: + r"""Call the query assets method over HTTP. + + Args: + request (~.asset_service.QueryAssetsRequest): + The request object. QueryAssets request. + 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: + ~.asset_service.QueryAssetsResponse: + QueryAssets response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1/{parent=*/*}:queryAssets", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_query_assets(request, metadata) + pb_request = asset_service.QueryAssetsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.QueryAssetsResponse() + pb_resp = asset_service.QueryAssetsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_query_assets(resp) + return resp + + class _SearchAllIamPolicies(AssetServiceRestStub): + def __hash__(self): + return hash("SearchAllIamPolicies") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.SearchAllIamPoliciesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SearchAllIamPoliciesResponse: + r"""Call the search all iam policies method over HTTP. + + Args: + request (~.asset_service.SearchAllIamPoliciesRequest): + The request object. Search all IAM policies request. + 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: + ~.asset_service.SearchAllIamPoliciesResponse: + Search all IAM policies response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{scope=*/*}:searchAllIamPolicies", + }, + ] + request, metadata = self._interceptor.pre_search_all_iam_policies( + request, metadata + ) + pb_request = asset_service.SearchAllIamPoliciesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SearchAllIamPoliciesResponse() + pb_resp = asset_service.SearchAllIamPoliciesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_search_all_iam_policies(resp) + return resp + + class _SearchAllResources(AssetServiceRestStub): + def __hash__(self): + return hash("SearchAllResources") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.SearchAllResourcesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SearchAllResourcesResponse: + r"""Call the search all resources method over HTTP. + + Args: + request (~.asset_service.SearchAllResourcesRequest): + The request object. Search all resources request. + 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: + ~.asset_service.SearchAllResourcesResponse: + Search all resources response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{scope=*/*}:searchAllResources", + }, + ] + request, metadata = self._interceptor.pre_search_all_resources( + request, metadata + ) + pb_request = asset_service.SearchAllResourcesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SearchAllResourcesResponse() + pb_resp = asset_service.SearchAllResourcesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_search_all_resources(resp) + return resp + + class _UpdateFeed(AssetServiceRestStub): + def __hash__(self): + return hash("UpdateFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.UpdateFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.Feed: + r"""Call the update feed method over HTTP. + + Args: + request (~.asset_service.UpdateFeedRequest): + The request object. Update asset feed request. + 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: + ~.asset_service.Feed: + An asset feed used to export asset + updates to a destinations. An asset feed + filter controls what updates are + exported. The asset feed must be created + within a project, organization, or + folder. Supported destinations are: + Pub/Sub topics. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v1/{feed.name=*/*/feeds/*}", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_update_feed(request, metadata) + pb_request = asset_service.UpdateFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.Feed() + pb_resp = asset_service.Feed.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_feed(resp) + return resp + + class _UpdateSavedQuery(AssetServiceRestStub): + def __hash__(self): + return hash("UpdateSavedQuery") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.UpdateSavedQueryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SavedQuery: + r"""Call the update saved query method over HTTP. + + Args: + request (~.asset_service.UpdateSavedQueryRequest): + The request object. Request to update a saved query. + 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: + ~.asset_service.SavedQuery: + A saved query which can be shared + with others or used later. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v1/{saved_query.name=*/*/savedQueries/*}", + "body": "saved_query", + }, + ] + request, metadata = self._interceptor.pre_update_saved_query( + request, metadata + ) + pb_request = asset_service.UpdateSavedQueryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SavedQuery() + pb_resp = asset_service.SavedQuery.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_saved_query(resp) + return resp + + @property + def analyze_iam_policy( + self, + ) -> Callable[ + [asset_service.AnalyzeIamPolicyRequest], asset_service.AnalyzeIamPolicyResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeIamPolicy(self._session, self._host, self._interceptor) # type: ignore + + @property + def analyze_iam_policy_longrunning( + self, + ) -> Callable[ + [asset_service.AnalyzeIamPolicyLongrunningRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeIamPolicyLongrunning(self._session, self._host, self._interceptor) # type: ignore + + @property + def analyze_move( + self, + ) -> Callable[ + [asset_service.AnalyzeMoveRequest], asset_service.AnalyzeMoveResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeMove(self._session, self._host, self._interceptor) # type: ignore + + @property + def analyze_org_policies( + self, + ) -> Callable[ + [asset_service.AnalyzeOrgPoliciesRequest], + asset_service.AnalyzeOrgPoliciesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeOrgPolicies(self._session, self._host, self._interceptor) # type: ignore + + @property + def analyze_org_policy_governed_assets( + self, + ) -> Callable[ + [asset_service.AnalyzeOrgPolicyGovernedAssetsRequest], + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeOrgPolicyGovernedAssets(self._session, self._host, self._interceptor) # type: ignore + + @property + def analyze_org_policy_governed_containers( + self, + ) -> Callable[ + [asset_service.AnalyzeOrgPolicyGovernedContainersRequest], + asset_service.AnalyzeOrgPolicyGovernedContainersResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeOrgPolicyGovernedContainers(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_get_assets_history( + self, + ) -> Callable[ + [asset_service.BatchGetAssetsHistoryRequest], + asset_service.BatchGetAssetsHistoryResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchGetAssetsHistory(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_get_effective_iam_policies( + self, + ) -> Callable[ + [asset_service.BatchGetEffectiveIamPoliciesRequest], + asset_service.BatchGetEffectiveIamPoliciesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchGetEffectiveIamPolicies(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_feed( + self, + ) -> Callable[[asset_service.CreateFeedRequest], asset_service.Feed]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_saved_query( + self, + ) -> Callable[[asset_service.CreateSavedQueryRequest], asset_service.SavedQuery]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateSavedQuery(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_feed( + self, + ) -> Callable[[asset_service.DeleteFeedRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_saved_query( + self, + ) -> Callable[[asset_service.DeleteSavedQueryRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteSavedQuery(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_assets( + self, + ) -> Callable[[asset_service.ExportAssetsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ExportAssets(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_feed(self) -> Callable[[asset_service.GetFeedRequest], asset_service.Feed]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_saved_query( + self, + ) -> Callable[[asset_service.GetSavedQueryRequest], asset_service.SavedQuery]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetSavedQuery(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_assets( + self, + ) -> Callable[[asset_service.ListAssetsRequest], asset_service.ListAssetsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListAssets(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_feeds( + self, + ) -> Callable[[asset_service.ListFeedsRequest], asset_service.ListFeedsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListFeeds(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_saved_queries( + self, + ) -> Callable[ + [asset_service.ListSavedQueriesRequest], asset_service.ListSavedQueriesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListSavedQueries(self._session, self._host, self._interceptor) # type: ignore + + @property + def query_assets( + self, + ) -> Callable[ + [asset_service.QueryAssetsRequest], asset_service.QueryAssetsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._QueryAssets(self._session, self._host, self._interceptor) # type: ignore + + @property + def search_all_iam_policies( + self, + ) -> Callable[ + [asset_service.SearchAllIamPoliciesRequest], + asset_service.SearchAllIamPoliciesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SearchAllIamPolicies(self._session, self._host, self._interceptor) # type: ignore + + @property + def search_all_resources( + self, + ) -> Callable[ + [asset_service.SearchAllResourcesRequest], + asset_service.SearchAllResourcesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SearchAllResources(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_feed( + self, + ) -> Callable[[asset_service.UpdateFeedRequest], asset_service.Feed]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_saved_query( + self, + ) -> Callable[[asset_service.UpdateSavedQueryRequest], asset_service.SavedQuery]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateSavedQuery(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AssetServiceRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + 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: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1/{name=*/*/operations/*/**}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AssetServiceRestTransport",) diff --git a/google/cloud/asset_v1p1beta1/gapic_metadata.json b/google/cloud/asset_v1p1beta1/gapic_metadata.json index 175cd294..c8f50c01 100644 --- a/google/cloud/asset_v1p1beta1/gapic_metadata.json +++ b/google/cloud/asset_v1p1beta1/gapic_metadata.json @@ -36,6 +36,21 @@ ] } } + }, + "rest": { + "libraryClient": "AssetServiceClient", + "rpcs": { + "SearchAllIamPolicies": { + "methods": [ + "search_all_iam_policies" + ] + }, + "SearchAllResources": { + "methods": [ + "search_all_resources" + ] + } + } } } } diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py b/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py index 0cd0771c..309c2dac 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py @@ -45,6 +45,7 @@ from google.cloud.asset_v1p1beta1.services.asset_service import pagers from google.cloud.asset_v1p1beta1.types import asset_service from google.cloud.asset_v1p1beta1.types import assets +from google.longrunning import operations_pb2 from .transports.base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import AssetServiceGrpcAsyncIOTransport from .client import AssetServiceClient diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/client.py b/google/cloud/asset_v1p1beta1/services/asset_service/client.py index 3a02fc99..44c73807 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/client.py @@ -49,9 +49,11 @@ from google.cloud.asset_v1p1beta1.services.asset_service import pagers from google.cloud.asset_v1p1beta1.types import asset_service from google.cloud.asset_v1p1beta1.types import assets +from google.longrunning import operations_pb2 from .transports.base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AssetServiceGrpcTransport from .transports.grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .transports.rest import AssetServiceRestTransport class AssetServiceClientMeta(type): @@ -65,6 +67,7 @@ class AssetServiceClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport + _transport_registry["rest"] = AssetServiceRestTransport def get_transport_class( cls, diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/__init__.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/__init__.py index c3ef619a..58f49f56 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/__init__.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/__init__.py @@ -19,15 +19,20 @@ from .base import AssetServiceTransport from .grpc import AssetServiceGrpcTransport from .grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .rest import AssetServiceRestTransport +from .rest import AssetServiceRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport +_transport_registry["rest"] = AssetServiceRestTransport __all__ = ( "AssetServiceTransport", "AssetServiceGrpcTransport", "AssetServiceGrpcAsyncIOTransport", + "AssetServiceRestTransport", + "AssetServiceRestInterceptor", ) diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py index a6e33d53..44d3df77 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py @@ -27,6 +27,7 @@ from google.oauth2 import service_account # type: ignore from google.cloud.asset_v1p1beta1.types import asset_service +from google.longrunning import operations_pb2 DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py index ccdf2540..1cf665f4 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py @@ -25,6 +25,7 @@ import grpc # type: ignore from google.cloud.asset_v1p1beta1.types import asset_service +from google.longrunning import operations_pb2 from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py index 1699d24b..af3f9abd 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py @@ -25,6 +25,7 @@ from grpc.experimental import aio # type: ignore from google.cloud.asset_v1p1beta1.types import asset_service +from google.longrunning import operations_pb2 from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .grpc import AssetServiceGrpcTransport diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/rest.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/rest.py new file mode 100644 index 00000000..2cece285 --- /dev/null +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/rest.py @@ -0,0 +1,441 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# + +from google.auth.transport.requests import AuthorizedSession # type: ignore +import json # type: ignore +import grpc # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.api_core import rest_helpers +from google.api_core import rest_streaming +from google.api_core import path_template +from google.api_core import gapic_v1 + +from google.protobuf import json_format +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.asset_v1p1beta1.types import asset_service + +from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AssetServiceRestInterceptor: + """Interceptor for AssetService. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AssetServiceRestTransport. + + .. code-block:: python + class MyCustomAssetServiceInterceptor(AssetServiceRestInterceptor): + def pre_search_all_iam_policies(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_search_all_iam_policies(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_search_all_resources(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_search_all_resources(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AssetServiceRestTransport(interceptor=MyCustomAssetServiceInterceptor()) + client = AssetServiceClient(transport=transport) + + + """ + + def pre_search_all_iam_policies( + self, + request: asset_service.SearchAllIamPoliciesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.SearchAllIamPoliciesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for search_all_iam_policies + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_search_all_iam_policies( + self, response: asset_service.SearchAllIamPoliciesResponse + ) -> asset_service.SearchAllIamPoliciesResponse: + """Post-rpc interceptor for search_all_iam_policies + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_search_all_resources( + self, + request: asset_service.SearchAllResourcesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.SearchAllResourcesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for search_all_resources + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_search_all_resources( + self, response: asset_service.SearchAllResourcesResponse + ) -> asset_service.SearchAllResourcesResponse: + """Post-rpc interceptor for search_all_resources + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AssetServiceRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AssetServiceRestInterceptor + + +class AssetServiceRestTransport(AssetServiceTransport): + """REST backend transport for AssetService. + + Asset service definition. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "cloudasset.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AssetServiceRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AssetServiceRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _SearchAllIamPolicies(AssetServiceRestStub): + def __hash__(self): + return hash("SearchAllIamPolicies") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.SearchAllIamPoliciesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SearchAllIamPoliciesResponse: + r"""Call the search all iam policies method over HTTP. + + Args: + request (~.asset_service.SearchAllIamPoliciesRequest): + The request object. Search all IAM policies request. + 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: + ~.asset_service.SearchAllIamPoliciesResponse: + Search all IAM policies response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1p1beta1/{scope=*/*}/iamPolicies:searchAll", + }, + ] + request, metadata = self._interceptor.pre_search_all_iam_policies( + request, metadata + ) + pb_request = asset_service.SearchAllIamPoliciesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SearchAllIamPoliciesResponse() + pb_resp = asset_service.SearchAllIamPoliciesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_search_all_iam_policies(resp) + return resp + + class _SearchAllResources(AssetServiceRestStub): + def __hash__(self): + return hash("SearchAllResources") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.SearchAllResourcesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.SearchAllResourcesResponse: + r"""Call the search all resources method over HTTP. + + Args: + request (~.asset_service.SearchAllResourcesRequest): + The request object. Search all resources request. + 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: + ~.asset_service.SearchAllResourcesResponse: + Search all resources response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1p1beta1/{scope=*/*}/resources:searchAll", + }, + ] + request, metadata = self._interceptor.pre_search_all_resources( + request, metadata + ) + pb_request = asset_service.SearchAllResourcesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.SearchAllResourcesResponse() + pb_resp = asset_service.SearchAllResourcesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_search_all_resources(resp) + return resp + + @property + def search_all_iam_policies( + self, + ) -> Callable[ + [asset_service.SearchAllIamPoliciesRequest], + asset_service.SearchAllIamPoliciesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SearchAllIamPolicies(self._session, self._host, self._interceptor) # type: ignore + + @property + def search_all_resources( + self, + ) -> Callable[ + [asset_service.SearchAllResourcesRequest], + asset_service.SearchAllResourcesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SearchAllResources(self._session, self._host, self._interceptor) # type: ignore + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AssetServiceRestTransport",) diff --git a/google/cloud/asset_v1p2beta1/gapic_metadata.json b/google/cloud/asset_v1p2beta1/gapic_metadata.json index 3c3674a8..792efcd7 100644 --- a/google/cloud/asset_v1p2beta1/gapic_metadata.json +++ b/google/cloud/asset_v1p2beta1/gapic_metadata.json @@ -66,6 +66,36 @@ ] } } + }, + "rest": { + "libraryClient": "AssetServiceClient", + "rpcs": { + "CreateFeed": { + "methods": [ + "create_feed" + ] + }, + "DeleteFeed": { + "methods": [ + "delete_feed" + ] + }, + "GetFeed": { + "methods": [ + "get_feed" + ] + }, + "ListFeeds": { + "methods": [ + "list_feeds" + ] + }, + "UpdateFeed": { + "methods": [ + "update_feed" + ] + } + } } } } diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/client.py b/google/cloud/asset_v1p2beta1/services/asset_service/client.py index addac356..e858ecd5 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/client.py @@ -50,6 +50,7 @@ from .transports.base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AssetServiceGrpcTransport from .transports.grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .transports.rest import AssetServiceRestTransport class AssetServiceClientMeta(type): @@ -63,6 +64,7 @@ class AssetServiceClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport + _transport_registry["rest"] = AssetServiceRestTransport def get_transport_class( cls, diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/transports/__init__.py b/google/cloud/asset_v1p2beta1/services/asset_service/transports/__init__.py index c3ef619a..58f49f56 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/transports/__init__.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/transports/__init__.py @@ -19,15 +19,20 @@ from .base import AssetServiceTransport from .grpc import AssetServiceGrpcTransport from .grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .rest import AssetServiceRestTransport +from .rest import AssetServiceRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport +_transport_registry["rest"] = AssetServiceRestTransport __all__ = ( "AssetServiceTransport", "AssetServiceGrpcTransport", "AssetServiceGrpcAsyncIOTransport", + "AssetServiceRestTransport", + "AssetServiceRestInterceptor", ) diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/transports/rest.py b/google/cloud/asset_v1p2beta1/services/asset_service/transports/rest.py new file mode 100644 index 00000000..bf7313b9 --- /dev/null +++ b/google/cloud/asset_v1p2beta1/services/asset_service/transports/rest.py @@ -0,0 +1,808 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# + +from google.auth.transport.requests import AuthorizedSession # type: ignore +import json # type: ignore +import grpc # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.api_core import rest_helpers +from google.api_core import rest_streaming +from google.api_core import path_template +from google.api_core import gapic_v1 + +from google.protobuf import json_format +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.asset_v1p2beta1.types import asset_service +from google.protobuf import empty_pb2 # type: ignore + +from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AssetServiceRestInterceptor: + """Interceptor for AssetService. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AssetServiceRestTransport. + + .. code-block:: python + class MyCustomAssetServiceInterceptor(AssetServiceRestInterceptor): + def pre_create_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_feed(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_feed(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_feeds(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_feeds(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_feed(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_feed(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AssetServiceRestTransport(interceptor=MyCustomAssetServiceInterceptor()) + client = AssetServiceClient(transport=transport) + + + """ + + def pre_create_feed( + self, + request: asset_service.CreateFeedRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.CreateFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_create_feed(self, response: asset_service.Feed) -> asset_service.Feed: + """Post-rpc interceptor for create_feed + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_delete_feed( + self, + request: asset_service.DeleteFeedRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.DeleteFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def pre_get_feed( + self, request: asset_service.GetFeedRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[asset_service.GetFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_get_feed(self, response: asset_service.Feed) -> asset_service.Feed: + """Post-rpc interceptor for get_feed + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_list_feeds( + self, + request: asset_service.ListFeedsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.ListFeedsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_feeds + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_list_feeds( + self, response: asset_service.ListFeedsResponse + ) -> asset_service.ListFeedsResponse: + """Post-rpc interceptor for list_feeds + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + def pre_update_feed( + self, + request: asset_service.UpdateFeedRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.UpdateFeedRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_feed + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_update_feed(self, response: asset_service.Feed) -> asset_service.Feed: + """Post-rpc interceptor for update_feed + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AssetServiceRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AssetServiceRestInterceptor + + +class AssetServiceRestTransport(AssetServiceTransport): + """REST backend transport for AssetService. + + Asset service definition. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "cloudasset.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AssetServiceRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AssetServiceRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateFeed(AssetServiceRestStub): + def __hash__(self): + return hash("CreateFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.CreateFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.Feed: + r"""Call the create feed method over HTTP. + + Args: + request (~.asset_service.CreateFeedRequest): + The request object. Create asset feed request. + 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: + ~.asset_service.Feed: + An asset feed used to export asset + updates to a destinations. An asset feed + filter controls what updates are + exported. The asset feed must be created + within a project, organization, or + folder. Supported destinations are: + Cloud Pub/Sub topics. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1p2beta1/{parent=*/*}/feeds", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_create_feed(request, metadata) + pb_request = asset_service.CreateFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.Feed() + pb_resp = asset_service.Feed.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_feed(resp) + return resp + + class _DeleteFeed(AssetServiceRestStub): + def __hash__(self): + return hash("DeleteFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.DeleteFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete feed method over HTTP. + + Args: + request (~.asset_service.DeleteFeedRequest): + The request object. + 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v1p2beta1/{name=*/*/feeds/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_feed(request, metadata) + pb_request = asset_service.DeleteFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetFeed(AssetServiceRestStub): + def __hash__(self): + return hash("GetFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.GetFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.Feed: + r"""Call the get feed method over HTTP. + + Args: + request (~.asset_service.GetFeedRequest): + The request object. Get asset feed request. + 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: + ~.asset_service.Feed: + An asset feed used to export asset + updates to a destinations. An asset feed + filter controls what updates are + exported. The asset feed must be created + within a project, organization, or + folder. Supported destinations are: + Cloud Pub/Sub topics. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1p2beta1/{name=*/*/feeds/*}", + }, + ] + request, metadata = self._interceptor.pre_get_feed(request, metadata) + pb_request = asset_service.GetFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.Feed() + pb_resp = asset_service.Feed.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_feed(resp) + return resp + + class _ListFeeds(AssetServiceRestStub): + def __hash__(self): + return hash("ListFeeds") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.ListFeedsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.ListFeedsResponse: + r"""Call the list feeds method over HTTP. + + Args: + request (~.asset_service.ListFeedsRequest): + The request object. List asset feeds request. + 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: + ~.asset_service.ListFeedsResponse: + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1p2beta1/{parent=*/*}/feeds", + }, + ] + request, metadata = self._interceptor.pre_list_feeds(request, metadata) + pb_request = asset_service.ListFeedsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.ListFeedsResponse() + pb_resp = asset_service.ListFeedsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_feeds(resp) + return resp + + class _UpdateFeed(AssetServiceRestStub): + def __hash__(self): + return hash("UpdateFeed") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.UpdateFeedRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.Feed: + r"""Call the update feed method over HTTP. + + Args: + request (~.asset_service.UpdateFeedRequest): + The request object. Update asset feed request. + 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: + ~.asset_service.Feed: + An asset feed used to export asset + updates to a destinations. An asset feed + filter controls what updates are + exported. The asset feed must be created + within a project, organization, or + folder. Supported destinations are: + Cloud Pub/Sub topics. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v1p2beta1/{feed.name=*/*/feeds/*}", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_update_feed(request, metadata) + pb_request = asset_service.UpdateFeedRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.Feed() + pb_resp = asset_service.Feed.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_feed(resp) + return resp + + @property + def create_feed( + self, + ) -> Callable[[asset_service.CreateFeedRequest], asset_service.Feed]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_feed( + self, + ) -> Callable[[asset_service.DeleteFeedRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_feed(self) -> Callable[[asset_service.GetFeedRequest], asset_service.Feed]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_feeds( + self, + ) -> Callable[[asset_service.ListFeedsRequest], asset_service.ListFeedsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListFeeds(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_feed( + self, + ) -> Callable[[asset_service.UpdateFeedRequest], asset_service.Feed]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateFeed(self._session, self._host, self._interceptor) # type: ignore + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AssetServiceRestTransport",) diff --git a/google/cloud/asset_v1p5beta1/gapic_metadata.json b/google/cloud/asset_v1p5beta1/gapic_metadata.json index 3d280aa7..2c3088cd 100644 --- a/google/cloud/asset_v1p5beta1/gapic_metadata.json +++ b/google/cloud/asset_v1p5beta1/gapic_metadata.json @@ -26,6 +26,16 @@ ] } } + }, + "rest": { + "libraryClient": "AssetServiceClient", + "rpcs": { + "ListAssets": { + "methods": [ + "list_assets" + ] + } + } } } } diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py b/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py index 34553f1d..8a56b6bc 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py @@ -45,6 +45,7 @@ from google.cloud.asset_v1p5beta1.services.asset_service import pagers from google.cloud.asset_v1p5beta1.types import asset_service from google.cloud.asset_v1p5beta1.types import assets +from google.longrunning import operations_pb2 from .transports.base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import AssetServiceGrpcAsyncIOTransport from .client import AssetServiceClient diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/client.py b/google/cloud/asset_v1p5beta1/services/asset_service/client.py index e5018998..d1670775 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/client.py @@ -49,9 +49,11 @@ from google.cloud.asset_v1p5beta1.services.asset_service import pagers from google.cloud.asset_v1p5beta1.types import asset_service from google.cloud.asset_v1p5beta1.types import assets +from google.longrunning import operations_pb2 from .transports.base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AssetServiceGrpcTransport from .transports.grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .transports.rest import AssetServiceRestTransport class AssetServiceClientMeta(type): @@ -65,6 +67,7 @@ class AssetServiceClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport + _transport_registry["rest"] = AssetServiceRestTransport def get_transport_class( cls, diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/__init__.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/__init__.py index c3ef619a..58f49f56 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/__init__.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/__init__.py @@ -19,15 +19,20 @@ from .base import AssetServiceTransport from .grpc import AssetServiceGrpcTransport from .grpc_asyncio import AssetServiceGrpcAsyncIOTransport +from .rest import AssetServiceRestTransport +from .rest import AssetServiceRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AssetServiceTransport]] _transport_registry["grpc"] = AssetServiceGrpcTransport _transport_registry["grpc_asyncio"] = AssetServiceGrpcAsyncIOTransport +_transport_registry["rest"] = AssetServiceRestTransport __all__ = ( "AssetServiceTransport", "AssetServiceGrpcTransport", "AssetServiceGrpcAsyncIOTransport", + "AssetServiceRestTransport", + "AssetServiceRestInterceptor", ) diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py index 49c0181e..e26f202f 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py @@ -27,6 +27,7 @@ from google.oauth2 import service_account # type: ignore from google.cloud.asset_v1p5beta1.types import asset_service +from google.longrunning import operations_pb2 DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=package_version.__version__ diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py index 22908e9d..2b98ffe7 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py @@ -25,6 +25,7 @@ import grpc # type: ignore from google.cloud.asset_v1p5beta1.types import asset_service +from google.longrunning import operations_pb2 from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py index d919107a..d5ed9fec 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py @@ -25,6 +25,7 @@ from grpc.experimental import aio # type: ignore from google.cloud.asset_v1p5beta1.types import asset_service +from google.longrunning import operations_pb2 from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO from .grpc import AssetServiceGrpcTransport diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/rest.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/rest.py new file mode 100644 index 00000000..cf5ac4d8 --- /dev/null +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/rest.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 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. +# + +from google.auth.transport.requests import AuthorizedSession # type: ignore +import json # type: ignore +import grpc # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.api_core import rest_helpers +from google.api_core import rest_streaming +from google.api_core import path_template +from google.api_core import gapic_v1 + +from google.protobuf import json_format +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.asset_v1p5beta1.types import asset_service + +from .base import AssetServiceTransport, DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AssetServiceRestInterceptor: + """Interceptor for AssetService. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AssetServiceRestTransport. + + .. code-block:: python + class MyCustomAssetServiceInterceptor(AssetServiceRestInterceptor): + def pre_list_assets(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_assets(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AssetServiceRestTransport(interceptor=MyCustomAssetServiceInterceptor()) + client = AssetServiceClient(transport=transport) + + + """ + + def pre_list_assets( + self, + request: asset_service.ListAssetsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[asset_service.ListAssetsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_assets + + Override in a subclass to manipulate the request or metadata + before they are sent to the AssetService server. + """ + return request, metadata + + def post_list_assets( + self, response: asset_service.ListAssetsResponse + ) -> asset_service.ListAssetsResponse: + """Post-rpc interceptor for list_assets + + Override in a subclass to manipulate the response + after it is returned by the AssetService server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AssetServiceRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AssetServiceRestInterceptor + + +class AssetServiceRestTransport(AssetServiceTransport): + """REST backend transport for AssetService. + + Asset service definition. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "cloudasset.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AssetServiceRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` 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): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AssetServiceRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _ListAssets(AssetServiceRestStub): + def __hash__(self): + return hash("ListAssets") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, str] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: asset_service.ListAssetsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> asset_service.ListAssetsResponse: + r"""Call the list assets method over HTTP. + + Args: + request (~.asset_service.ListAssetsRequest): + The request object. ListAssets request. + 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: + ~.asset_service.ListAssetsResponse: + ListAssets response. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v1p5beta1/{parent=*/*}/assets", + }, + ] + request, metadata = self._interceptor.pre_list_assets(request, metadata) + pb_request = asset_service.ListAssetsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = asset_service.ListAssetsResponse() + pb_resp = asset_service.ListAssetsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_assets(resp) + return resp + + @property + def list_assets( + self, + ) -> Callable[[asset_service.ListAssetsRequest], asset_service.ListAssetsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListAssets(self._session, self._host, self._interceptor) # type: ignore + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AssetServiceRestTransport",) diff --git a/samples/snippets/quickstart_analyzeiampolicy.py b/samples/snippets/quickstart_analyzeiampolicy.py index ee43cd9d..feb23926 100644 --- a/samples/snippets/quickstart_analyzeiampolicy.py +++ b/samples/snippets/quickstart_analyzeiampolicy.py @@ -18,13 +18,19 @@ import argparse -def analyze_iam_policy(project_id): +def analyze_iam_policy(project_id: str, transport: str = "None") -> None: + """ + Args: + project_id(str): The project id. + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_analyze_iam_policy] from google.cloud import asset_v1 # TODO project_id = 'Your Google Cloud Project ID' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) # Build analysis query diff --git a/samples/snippets/quickstart_analyzeiampolicy_test.py b/samples/snippets/quickstart_analyzeiampolicy_test.py index ec398389..e05cdfb5 100644 --- a/samples/snippets/quickstart_analyzeiampolicy_test.py +++ b/samples/snippets/quickstart_analyzeiampolicy_test.py @@ -15,13 +15,15 @@ # limitations under the License. import os +import pytest import quickstart_analyzeiampolicy PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] -def test_analyze_iam_policy(capsys): - quickstart_analyzeiampolicy.analyze_iam_policy(PROJECT) +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_analyze_iam_policy(transport, capsys): + quickstart_analyzeiampolicy.analyze_iam_policy(PROJECT, transport=transport) out, _ = capsys.readouterr() assert "fully_explored: true" in out diff --git a/samples/snippets/quickstart_analyzeiampolicylongrunning.py b/samples/snippets/quickstart_analyzeiampolicylongrunning.py index 29f59092..c26ad8dc 100644 --- a/samples/snippets/quickstart_analyzeiampolicylongrunning.py +++ b/samples/snippets/quickstart_analyzeiampolicylongrunning.py @@ -18,14 +18,26 @@ import argparse -def analyze_iam_policy_longrunning_gcs(project_id, dump_file_path): +def analyze_iam_policy_longrunning_gcs( + project_id: str, dump_file_path: str, transport: str = None +) -> None: + """ + Args: + + project_id(str): Your Google Cloud Project ID + dump_file_path(str): Your analysis dump file path + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ + # [START asset_quickstart_analyze_iam_policy_longrunning_gcs] from google.cloud import asset_v1 # TODO project_id = 'Your Google Cloud Project ID' # TODO dump_file_path = 'Your analysis dump file path' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) # Build analysis query @@ -48,15 +60,28 @@ def analyze_iam_policy_longrunning_gcs(project_id, dump_file_path): # [END asset_quickstart_analyze_iam_policy_longrunning_gcs] -def analyze_iam_policy_longrunning_bigquery(project_id, dataset, table): +def analyze_iam_policy_longrunning_bigquery( + project_id: str, dataset: str, table, transport: str = None +) -> None: + """ + Args: + + project_id(str): Your Google Cloud Project ID + dataset(str): 'Your BigQuery dataset path' + table(str): 'Your BigQuery table name' + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + + """ # [START asset_quickstart_analyze_iam_policy_longrunning_bigquery] from google.cloud import asset_v1 # TODO project_id = 'Your Google Cloud Project ID' # TODO dataset = 'Your BigQuery dataset path' # TODO table = 'Your BigQuery table name' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) # Build analysis query diff --git a/samples/snippets/quickstart_analyzeiampolicylongrunning_test.py b/samples/snippets/quickstart_analyzeiampolicylongrunning_test.py index 0cb22a3a..0da9e243 100644 --- a/samples/snippets/quickstart_analyzeiampolicylongrunning_test.py +++ b/samples/snippets/quickstart_analyzeiampolicylongrunning_test.py @@ -64,17 +64,23 @@ def dataset(bigquery_client): bigquery_client.delete_dataset(dataset_id, delete_contents=True, not_found_ok=False) -def test_analyze_iam_policy_longrunning(analysis_bucket, dataset, capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_analyze_iam_policy_longrunning(analysis_bucket, dataset, capsys, transport): dump_file_path = "gs://{}/analysis-dump.txt".format(analysis_bucket) quickstart_analyzeiampolicylongrunning.analyze_iam_policy_longrunning_gcs( - PROJECT, dump_file_path + project_id=PROJECT, + dump_file_path=dump_file_path, + transport=transport, ) out, _ = capsys.readouterr() assert "True" in out dataset_id = "projects/{}/datasets/{}".format(PROJECT, dataset) quickstart_analyzeiampolicylongrunning.analyze_iam_policy_longrunning_bigquery( - PROJECT, dataset_id, "analysis_" + project_id=PROJECT, + dataset=dataset_id, + table="analysis_", + transport=transport, ) out, _ = capsys.readouterr() assert "True" in out diff --git a/samples/snippets/quickstart_batchgetassetshistory.py b/samples/snippets/quickstart_batchgetassetshistory.py index 3ee70e30..d159d7ff 100644 --- a/samples/snippets/quickstart_batchgetassetshistory.py +++ b/samples/snippets/quickstart_batchgetassetshistory.py @@ -16,17 +16,29 @@ import argparse +from typing import List -def batch_get_assets_history(project_id, asset_names): +def batch_get_assets_history( + project_id: str, asset_names: List[str], transport: str = None +): + """ + Args: + project_id(str): Your Google Cloud Project ID + asset_names(List[str]): Your asset names list. + For example: ["//storage.googleapis.com/[BUCKET_NAME]",] + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_batch_get_assets_history] from google.cloud import asset_v1 # TODO project_id = 'Your Google Cloud Project ID' # TODO asset_names = 'Your asset names list, e.g.: # ["//storage.googleapis.com/[BUCKET_NAME]",]' + # TODO transport = 'The transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) content_type = asset_v1.ContentType.RESOURCE read_time_window = asset_v1.TimeWindow() diff --git a/samples/snippets/quickstart_batchgetassetshistory_test.py b/samples/snippets/quickstart_batchgetassetshistory_test.py index 1bb483eb..6ed604a1 100644 --- a/samples/snippets/quickstart_batchgetassetshistory_test.py +++ b/samples/snippets/quickstart_batchgetassetshistory_test.py @@ -54,7 +54,9 @@ def test_batch_get_assets_history(asset_bucket, capsys): @backoff.on_exception(backoff.expo, (AssertionError, InvalidArgument), max_time=60) def eventually_consistent_test(): - quickstart_batchgetassetshistory.batch_get_assets_history(PROJECT, asset_names) + quickstart_batchgetassetshistory.batch_get_assets_history( + project_id=PROJECT, asset_names=asset_names, transport="grpc" + ) out, _ = capsys.readouterr() assert bucket_asset_name in out diff --git a/samples/snippets/quickstart_batchgeteffectiveiampolicy.py b/samples/snippets/quickstart_batchgeteffectiveiampolicy.py index 4e7f2e3c..0b98f5c7 100644 --- a/samples/snippets/quickstart_batchgeteffectiveiampolicy.py +++ b/samples/snippets/quickstart_batchgeteffectiveiampolicy.py @@ -16,16 +16,28 @@ import argparse +from typing import List -def batch_get_effective_iam_policies(resource_names, scope): +def batch_get_effective_iam_policies( + resource_names: List[str], scope: str, transport: str = None +): + """ + Args: + resource_names(List[str]): List of resource names + scope(str): project ID/number, folder number or org number + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ + # [START asset_quickstart_batch_get_effective_iam_policies] from google.cloud import asset_v1 - # TODO scope = 'project ID/number, folder number or org number' # TODO resource_names = 'List of resource names' + # TODO scope = 'project ID/number, folder number or org number' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.batch_get_effective_iam_policies( request={"scope": scope, "names": resource_names} diff --git a/samples/snippets/quickstart_batchgeteffectiveiampolicy_test.py b/samples/snippets/quickstart_batchgeteffectiveiampolicy_test.py index e04628b1..e15d5715 100644 --- a/samples/snippets/quickstart_batchgeteffectiveiampolicy_test.py +++ b/samples/snippets/quickstart_batchgeteffectiveiampolicy_test.py @@ -15,19 +15,23 @@ # limitations under the License. import os +import pytest import quickstart_batchgeteffectiveiampolicy PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] -def test_batch_get_effective_iam_policies(capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_batch_get_effective_iam_policies(transport, capsys): scope = "projects/{}".format(PROJECT) resource_names = [ "//cloudresourcemanager.googleapis.com/projects/{}".format(PROJECT) ] quickstart_batchgeteffectiveiampolicy.batch_get_effective_iam_policies( - resource_names, scope + resource_names=resource_names, + scope=scope, + transport=transport, ) out, _ = capsys.readouterr() assert resource_names[0] in out diff --git a/samples/snippets/quickstart_create_saved_query.py b/samples/snippets/quickstart_create_saved_query.py index 3b75e72e..904f2a23 100644 --- a/samples/snippets/quickstart_create_saved_query.py +++ b/samples/snippets/quickstart_create_saved_query.py @@ -18,13 +18,24 @@ import argparse -def create_saved_query(project_id, saved_query_id, description): +def create_saved_query( + project_id: str, saved_query_id: str, description: str, transport: str = None +): + """ + Args: + project_id(str): Your Google Cloud Project ID + saved_query_id(str): SavedQuery ID you want to create + description(str): The description for the query. + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_create_saved_query] from google.cloud import asset_v1 # TODO project_id = 'Your Google Cloud Project ID' # TODO saved_query_id = 'SavedQuery ID you want to create' - client = asset_v1.AssetServiceClient() + + client = asset_v1.AssetServiceClient(transport=transport) parent = f"projects/{project_id}" saved_query = asset_v1.SavedQuery() saved_query.description = description diff --git a/samples/snippets/quickstart_create_saved_query_test.py b/samples/snippets/quickstart_create_saved_query_test.py index cefb731a..30a7785d 100644 --- a/samples/snippets/quickstart_create_saved_query_test.py +++ b/samples/snippets/quickstart_create_saved_query_test.py @@ -15,6 +15,7 @@ # limitations under the License. import os +import pytest import uuid import quickstart_create_saved_query @@ -24,10 +25,14 @@ SAVED_QUERY_ID = f"saved-query-{uuid.uuid4().hex}" -def test_create_saved_query(capsys, saved_query_deleter): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_create_saved_query(transport, capsys, saved_query_deleter): saved_query = quickstart_create_saved_query.create_saved_query( - PROJECT, SAVED_QUERY_ID, "saved query foo" + project_id=PROJECT, + saved_query_id=f"{SAVED_QUERY_ID}-{transport}", + description="saved query foo", + transport=transport, ) saved_query_deleter.append(saved_query.name) - expected_resource_name_suffix = f"savedQueries/{SAVED_QUERY_ID}" + expected_resource_name_suffix = f"savedQueries/{SAVED_QUERY_ID}-{transport}" assert saved_query.name.endswith(expected_resource_name_suffix) diff --git a/samples/snippets/quickstart_createfeed.py b/samples/snippets/quickstart_createfeed.py index 9e19433f..3f70b5f5 100644 --- a/samples/snippets/quickstart_createfeed.py +++ b/samples/snippets/quickstart_createfeed.py @@ -16,9 +16,28 @@ import argparse +from typing import List +from google.cloud.asset_v1 import ContentType -def create_feed(project_id, feed_id, asset_names, topic, content_type): +def create_feed( + project_id: str, + feed_id: str, + asset_names: List[str], + topic: str, + content_type: ContentType, + transport: str = None, +): + """ + Args: + project_id(str): The project id. + feed_id(str): Feed ID you want to create + asset_names(List[str]): List of asset names the feed listen to + topic(str): Topic name of the feed. + content_type[google.cloud.asset_v1.ContentType]: Content type of the feed. + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_create_feed] from google.cloud import asset_v1 @@ -27,8 +46,9 @@ def create_feed(project_id, feed_id, asset_names, topic, content_type): # TODO asset_names = 'List of asset names the feed listen to' # TODO topic = "Topic name of the feed" # TODO content_type ="Content type of the feed" + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) feed = asset_v1.Feed() feed.asset_names.extend(asset_names) diff --git a/samples/snippets/quickstart_createfeed_test.py b/samples/snippets/quickstart_createfeed_test.py index c464c11a..8d7eb559 100644 --- a/samples/snippets/quickstart_createfeed_test.py +++ b/samples/snippets/quickstart_createfeed_test.py @@ -15,6 +15,7 @@ # limitations under the License. import os +import pytest import uuid import quickstart_createfeed @@ -26,22 +27,29 @@ FEED_ID_R = "feed-{}".format(uuid.uuid4().hex) -def test_create_feed(capsys, test_topic, deleter): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_create_feed(transport, capsys, test_topic, deleter): from google.cloud import asset_v1 feed = quickstart_createfeed.create_feed( - PROJECT, FEED_ID, [ASSET_NAME], test_topic.name, asset_v1.ContentType.RESOURCE + project_id=PROJECT, + feed_id=f"{FEED_ID}-{transport}", + asset_names=[f"{ASSET_NAME}"], + topic=test_topic.name, + content_type=asset_v1.ContentType.RESOURCE, + transport=transport, ) deleter.append(feed.name) out, _ = capsys.readouterr() assert "feed" in out feed_r = quickstart_createfeed.create_feed( - PROJECT, - FEED_ID_R, - [ASSET_NAME], - test_topic.name, - asset_v1.ContentType.RELATIONSHIP, + project_id=PROJECT, + feed_id=f"{FEED_ID_R}-{transport}", + asset_names=[f"{ASSET_NAME}"], + topic=test_topic.name, + content_type=asset_v1.ContentType.RELATIONSHIP, + transport=transport, ) deleter.append(feed_r.name) out_r, _ = capsys.readouterr() diff --git a/samples/snippets/quickstart_delete_saved_query.py b/samples/snippets/quickstart_delete_saved_query.py index 593156b4..219df620 100644 --- a/samples/snippets/quickstart_delete_saved_query.py +++ b/samples/snippets/quickstart_delete_saved_query.py @@ -18,13 +18,20 @@ import argparse -def delete_saved_query(saved_query_name): +def delete_saved_query(saved_query_name: str, transport: str = None): + """ + Args: + saved_query_name(str): SavedQuery name you want to delete + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_delete_saved_query] from google.cloud import asset_v1 # TODO saved_query_name = 'SavedQuery name you want to delete' + # TODO tranport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) client.delete_saved_query(request={"name": saved_query_name}) print("deleted_saved_query") # [END asset_quickstart_delete_saved_query] diff --git a/samples/snippets/quickstart_delete_saved_query_test.py b/samples/snippets/quickstart_delete_saved_query_test.py index 1fe5e1a1..e8b03d1b 100644 --- a/samples/snippets/quickstart_delete_saved_query_test.py +++ b/samples/snippets/quickstart_delete_saved_query_test.py @@ -24,7 +24,9 @@ def test_delete_saved_query(capsys, test_saved_query): - quickstart_delete_saved_query.delete_saved_query(test_saved_query.name) + quickstart_delete_saved_query.delete_saved_query( + saved_query_name=test_saved_query.name, transport="grpc" + ) out, _ = capsys.readouterr() assert "deleted_saved_query" in out diff --git a/samples/snippets/quickstart_deletefeed.py b/samples/snippets/quickstart_deletefeed.py index 9aab5429..c85759a8 100644 --- a/samples/snippets/quickstart_deletefeed.py +++ b/samples/snippets/quickstart_deletefeed.py @@ -18,13 +18,20 @@ import argparse -def delete_feed(feed_name): +def delete_feed(feed_name: str, transport: str = None): + """ + Args: + feed_name(str): Feed name you want to delete. + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_delete_feed] from google.cloud import asset_v1 # TODO feed_name = 'Feed name you want to delete' + # TODO transport = 'Transport that you want to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) client.delete_feed(request={"name": feed_name}) print("deleted_feed") # [END asset_quickstart_delete_feed] diff --git a/samples/snippets/quickstart_deletefeed_test.py b/samples/snippets/quickstart_deletefeed_test.py index 3c5a113a..137bde0b 100644 --- a/samples/snippets/quickstart_deletefeed_test.py +++ b/samples/snippets/quickstart_deletefeed_test.py @@ -23,8 +23,7 @@ def test_delete_feed(capsys, test_feed): - - quickstart_deletefeed.delete_feed(test_feed.name) + quickstart_deletefeed.delete_feed(feed_name=test_feed.name, transport="grpc") out, _ = capsys.readouterr() assert "deleted_feed" in out diff --git a/samples/snippets/quickstart_exportassets.py b/samples/snippets/quickstart_exportassets.py index d61b0d86..71a04771 100644 --- a/samples/snippets/quickstart_exportassets.py +++ b/samples/snippets/quickstart_exportassets.py @@ -16,16 +16,26 @@ import argparse +from google.cloud.asset_v1 import ContentType -def export_assets(project_id, dump_file_path): +def export_assets(project_id: str, dump_file_path: str, transport: str = None): + """ + Args: + + project_id(str): Your Google Cloud Project ID + dump_file_path(str): Your analysis dump file path + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_export_assets] from google.cloud import asset_v1 # TODO project_id = 'Your Google Cloud Project ID' # TODO dump_file_path = 'Your asset dump file path' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) output_config = asset_v1.OutputConfig() output_config.gcs_destination.uri = dump_file_path @@ -36,7 +46,22 @@ def export_assets(project_id, dump_file_path): # [END asset_quickstart_export_assets] -def export_assets_bigquery(project_id, dataset, table, content_type): +def export_assets_bigquery( + project_id: str, + dataset: str, + table: str, + content_type: ContentType, + transport: str = None, +): + """ + Args: + project_id(str): The project id. + dataset(str): Your BigQuery dataset path. + table(str): Your BigQuery table name. + content_type[google.cloud.asset_v1.ContentType]: Content type of the feed. + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_export_assets_bigquery] from google.cloud import asset_v1 @@ -44,8 +69,9 @@ def export_assets_bigquery(project_id, dataset, table, content_type): # TODO dataset = 'Your BigQuery dataset path' # TODO table = 'Your BigQuery table name' # TODO content_type ="Content type to export" + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) parent = "projects/{}".format(project_id) output_config = asset_v1.OutputConfig() output_config.bigquery_destination.dataset = dataset diff --git a/samples/snippets/quickstart_exportassets_test.py b/samples/snippets/quickstart_exportassets_test.py index 274bbb67..b0494c95 100644 --- a/samples/snippets/quickstart_exportassets_test.py +++ b/samples/snippets/quickstart_exportassets_test.py @@ -64,23 +64,34 @@ def dataset(bigquery_client): bigquery_client.delete_dataset(dataset_id, delete_contents=True, not_found_ok=False) -def test_export_assets(asset_bucket, dataset, capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_export_assets(transport, asset_bucket, dataset, capsys): dump_file_path = "gs://{}/assets-dump.txt".format(asset_bucket) - quickstart_exportassets.export_assets(PROJECT, dump_file_path) + quickstart_exportassets.export_assets( + project_id=PROJECT, dump_file_path=dump_file_path, transport=transport + ) out, _ = capsys.readouterr() assert dump_file_path in out content_type = asset_v1.ContentType.RESOURCE dataset_id = "projects/{}/datasets/{}".format(PROJECT, dataset) quickstart_exportassets.export_assets_bigquery( - PROJECT, dataset_id, "assettable", content_type + project_id=PROJECT, + dataset=dataset_id, + table="assettable", + content_type=content_type, + transport=transport, ) out, _ = capsys.readouterr() assert dataset_id in out content_type_r = asset_v1.ContentType.RELATIONSHIP quickstart_exportassets.export_assets_bigquery( - PROJECT, dataset_id, "assettable", content_type_r + project_id=PROJECT, + dataset=dataset_id, + table="assettable", + content_type=content_type_r, + transport=transport, ) out_r, _ = capsys.readouterr() assert dataset_id in out_r diff --git a/samples/snippets/quickstart_get_saved_query.py b/samples/snippets/quickstart_get_saved_query.py index 0acd8132..54bcb24d 100644 --- a/samples/snippets/quickstart_get_saved_query.py +++ b/samples/snippets/quickstart_get_saved_query.py @@ -18,13 +18,14 @@ import argparse -def get_saved_query(saved_query_name): +def get_saved_query(saved_query_name, transport: str = None): # [START asset_quickstart_get_saved_query] from google.cloud import asset_v1 # TODO saved_query_name = 'SavedQuery Name you want to get' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.get_saved_query(request={"name": saved_query_name}) print(f"gotten_saved_query: {response}") # [END asset_quickstart_get_saved_query] diff --git a/samples/snippets/quickstart_get_saved_query_test.py b/samples/snippets/quickstart_get_saved_query_test.py index bb7b4147..45868531 100644 --- a/samples/snippets/quickstart_get_saved_query_test.py +++ b/samples/snippets/quickstart_get_saved_query_test.py @@ -14,11 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + import quickstart_get_saved_query -def test_get_saved_query(capsys, test_saved_query): - quickstart_get_saved_query.get_saved_query(test_saved_query.name) +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_get_saved_query(transport, capsys, test_saved_query): + quickstart_get_saved_query.get_saved_query( + test_saved_query.name, transport=transport + ) out, _ = capsys.readouterr() assert "gotten_saved_query" in out diff --git a/samples/snippets/quickstart_getfeed.py b/samples/snippets/quickstart_getfeed.py index aebe7621..a43874eb 100644 --- a/samples/snippets/quickstart_getfeed.py +++ b/samples/snippets/quickstart_getfeed.py @@ -18,13 +18,14 @@ import argparse -def get_feed(feed_name): +def get_feed(feed_name, transport: str = None): # [START asset_quickstart_get_feed] from google.cloud import asset_v1 # TODO feed_name = 'Feed Name you want to get' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.get_feed(request={"name": feed_name}) print("gotten_feed: {}".format(response)) # [START asset_quickstart_get_feed] diff --git a/samples/snippets/quickstart_getfeed_test.py b/samples/snippets/quickstart_getfeed_test.py index dd2a92bd..76b3502e 100644 --- a/samples/snippets/quickstart_getfeed_test.py +++ b/samples/snippets/quickstart_getfeed_test.py @@ -14,11 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + import quickstart_getfeed -def test_get_feed(capsys, test_feed): - quickstart_getfeed.get_feed(test_feed.name) +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_get_feed(transport, capsys, test_feed): + quickstart_getfeed.get_feed(test_feed.name, transport=transport) out, _ = capsys.readouterr() assert "gotten_feed" in out diff --git a/samples/snippets/quickstart_list_saved_queries.py b/samples/snippets/quickstart_list_saved_queries.py index 9f066e2d..f4402d67 100644 --- a/samples/snippets/quickstart_list_saved_queries.py +++ b/samples/snippets/quickstart_list_saved_queries.py @@ -18,13 +18,14 @@ import argparse -def list_saved_queries(parent_resource): +def list_saved_queries(parent_resource, transport: str = None): # [START asset_quickstart_list_saved_queries] from google.cloud import asset_v1 # TODO parent_resource = 'Parent resource you want to list all saved_queries' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.list_saved_queries(request={"parent": parent_resource}) print(f"saved_queries: {response.saved_queries}") # [END asset_quickstart_list_saved_queries] diff --git a/samples/snippets/quickstart_list_saved_queries_test.py b/samples/snippets/quickstart_list_saved_queries_test.py index d09c2c0c..63d81c49 100644 --- a/samples/snippets/quickstart_list_saved_queries_test.py +++ b/samples/snippets/quickstart_list_saved_queries_test.py @@ -15,14 +15,18 @@ # limitations under the License. import os +import pytest import quickstart_list_saved_queries PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] -def test_list_saved_queries(capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_list_saved_queries(transport, capsys): parent_resource = f"projects/{PROJECT}" - quickstart_list_saved_queries.list_saved_queries(parent_resource) + quickstart_list_saved_queries.list_saved_queries( + parent_resource, transport=transport + ) out, _ = capsys.readouterr() assert "saved_queries" in out diff --git a/samples/snippets/quickstart_listassets.py b/samples/snippets/quickstart_listassets.py index da1e71b5..074bd7e8 100644 --- a/samples/snippets/quickstart_listassets.py +++ b/samples/snippets/quickstart_listassets.py @@ -18,7 +18,9 @@ import argparse -def list_assets(project_id, asset_types, page_size, content_type): +def list_assets( + project_id, asset_types, page_size, content_type, transport: str = None +): # [START asset_quickstart_list_assets] from google.cloud import asset_v1 @@ -28,9 +30,10 @@ def list_assets(project_id, asset_types, page_size, content_type): # TODO page_size = 'Num of assets in one page, which must be between 1 and # 1000 (both inclusively)' # TODO content_type ="Content type to list" + # TODO transport = 'Transport to use. Either "grpc" or "rest"' project_resource = "projects/{}".format(project_id) - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) # Call ListAssets v1 to list assets. response = client.list_assets( diff --git a/samples/snippets/quickstart_listassets_test.py b/samples/snippets/quickstart_listassets_test.py index 8060921c..1d41e509 100644 --- a/samples/snippets/quickstart_listassets_test.py +++ b/samples/snippets/quickstart_listassets_test.py @@ -15,13 +15,15 @@ # limitations under the License. import os +import pytest import quickstart_listassets PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] -def test_list_assets(capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_list_assets(transport, capsys): from google.cloud import asset_v1 quickstart_listassets.list_assets( @@ -29,6 +31,7 @@ def test_list_assets(capsys): asset_types=["iam.googleapis.com/Role"], page_size=10, content_type=asset_v1.ContentType.RESOURCE, + transport=transport, ) out, _ = capsys.readouterr() assert "asset" in out @@ -38,6 +41,7 @@ def test_list_assets(capsys): asset_types=[], page_size=10, content_type=asset_v1.ContentType.RELATIONSHIP, + transport=transport, ) out_r, _ = capsys.readouterr() assert "asset" in out_r diff --git a/samples/snippets/quickstart_listfeeds.py b/samples/snippets/quickstart_listfeeds.py index c432d358..d1dd8a20 100644 --- a/samples/snippets/quickstart_listfeeds.py +++ b/samples/snippets/quickstart_listfeeds.py @@ -18,13 +18,14 @@ import argparse -def list_feeds(parent_resource): +def list_feeds(parent_resource, transport: str = None): # [START asset_quickstart_list_feeds] from google.cloud import asset_v1 # TODO parent_resource = 'Parent resource you want to list all feeds' + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.list_feeds(request={"parent": parent_resource}) print("feeds: {}".format(response.feeds)) # [END asset_quickstart_list_feeds] diff --git a/samples/snippets/quickstart_listfeeds_test.py b/samples/snippets/quickstart_listfeeds_test.py index 19c44297..c50743f2 100644 --- a/samples/snippets/quickstart_listfeeds_test.py +++ b/samples/snippets/quickstart_listfeeds_test.py @@ -15,14 +15,16 @@ # limitations under the License. import os +import pytest import quickstart_listfeeds PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] -def test_list_feeds(capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_list_feeds(transport, capsys): parent_resource = "projects/{}".format(PROJECT) - quickstart_listfeeds.list_feeds(parent_resource) + quickstart_listfeeds.list_feeds(parent_resource, transport=transport) out, _ = capsys.readouterr() assert "feeds" in out diff --git a/samples/snippets/quickstart_searchalliampolicies.py b/samples/snippets/quickstart_searchalliampolicies.py index 3782ebb6..ee5d2ee3 100644 --- a/samples/snippets/quickstart_searchalliampolicies.py +++ b/samples/snippets/quickstart_searchalliampolicies.py @@ -18,15 +18,16 @@ import argparse -def search_all_iam_policies(scope, query=None, page_size=None): +def search_all_iam_policies(scope, query=None, page_size=None, transport: str = None): # [START asset_quickstart_search_all_iam_policies] from google.cloud import asset_v1 # TODO scope = 'Scope of the search' # TODO query = 'Query statement' # TODO page_size = Size of each result page + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.search_all_iam_policies( request={"scope": scope, "query": query, "page_size": page_size} ) diff --git a/samples/snippets/quickstart_searchalliampolicies_test.py b/samples/snippets/quickstart_searchalliampolicies_test.py index c9d313ea..c33b120e 100644 --- a/samples/snippets/quickstart_searchalliampolicies_test.py +++ b/samples/snippets/quickstart_searchalliampolicies_test.py @@ -15,15 +15,19 @@ # limitations under the License. import os +import pytest import quickstart_searchalliampolicies PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] -def test_search_all_iam_policies(capsys): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_search_all_iam_policies(transport, capsys): scope = "projects/{}".format(PROJECT) query = "policy:roles/owner" - quickstart_searchalliampolicies.search_all_iam_policies(scope, query=query) + quickstart_searchalliampolicies.search_all_iam_policies( + scope=scope, query=query, transport=transport + ) out, _ = capsys.readouterr() assert "roles/owner" in out diff --git a/samples/snippets/quickstart_searchallresources.py b/samples/snippets/quickstart_searchallresources.py index afecca7b..c595ea08 100644 --- a/samples/snippets/quickstart_searchallresources.py +++ b/samples/snippets/quickstart_searchallresources.py @@ -16,10 +16,18 @@ import argparse +from typing import List + +from google.cloud.asset_v1 import ContentType def search_all_resources( - scope, query=None, asset_types=None, page_size=None, order_by=None + scope: str, + query: str = None, + asset_types: List[ContentType] = None, + page_size: int = None, + order_by: List[str] = None, + transport: str = None, ): # [START asset_quickstart_search_all_resources] from google.cloud import asset_v1 @@ -29,8 +37,9 @@ def search_all_resources( # TODO asset_types = 'List of asset types to search for' # TODO page_size = Size of each result page # TODO order_by = 'Fields to sort the results' + # TODO transport= 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) response = client.search_all_resources( request={ "scope": scope, diff --git a/samples/snippets/quickstart_searchallresources_test.py b/samples/snippets/quickstart_searchallresources_test.py index da019752..02098c30 100644 --- a/samples/snippets/quickstart_searchallresources_test.py +++ b/samples/snippets/quickstart_searchallresources_test.py @@ -55,7 +55,9 @@ def test_search_all_resources(asset_dataset, capsys): # immediately searchable. Need some time before the snippet will pass. @backoff.on_exception(backoff.expo, (AssertionError), max_time=240) def eventually_consistent_test(): - quickstart_searchallresources.search_all_resources(scope, query=query) + quickstart_searchallresources.search_all_resources( + scope=scope, query=query, transport="grpc" + ) out, _ = capsys.readouterr() assert DATASET in out diff --git a/samples/snippets/quickstart_update_saved_query.py b/samples/snippets/quickstart_update_saved_query.py index a27d051c..028a6b70 100644 --- a/samples/snippets/quickstart_update_saved_query.py +++ b/samples/snippets/quickstart_update_saved_query.py @@ -18,15 +18,23 @@ import argparse -def update_saved_query(saved_query_name, description): +def update_saved_query(saved_query_name: str, description: str, transport: str = None): + """ + Args: + saved_query_name(str): SavedQuery Name you want to update + description(str): New description + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_update_saved_query] from google.cloud import asset_v1 from google.protobuf import field_mask_pb2 # TODO saved_query_name = 'SavedQuery Name you want to update' # TODO description = "New description' + # TODO transport = 'The transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) saved_query = asset_v1.SavedQuery() saved_query.name = saved_query_name saved_query.description = description diff --git a/samples/snippets/quickstart_update_saved_query_test.py b/samples/snippets/quickstart_update_saved_query_test.py index 734b3219..360a4cc5 100644 --- a/samples/snippets/quickstart_update_saved_query_test.py +++ b/samples/snippets/quickstart_update_saved_query_test.py @@ -14,11 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + import quickstart_update_saved_query -def test_update_saved_query(capsys, test_saved_query): - quickstart_update_saved_query.update_saved_query(test_saved_query.name, "bar") +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_update_saved_query(transport, capsys, test_saved_query): + quickstart_update_saved_query.update_saved_query( + saved_query_name=test_saved_query.name, description="bar", transport=transport + ) out, _ = capsys.readouterr() assert "updated_saved_query" in out diff --git a/samples/snippets/quickstart_updatefeed.py b/samples/snippets/quickstart_updatefeed.py index 3ad638ec..c20496fc 100644 --- a/samples/snippets/quickstart_updatefeed.py +++ b/samples/snippets/quickstart_updatefeed.py @@ -18,15 +18,23 @@ import argparse -def update_feed(feed_name, topic): +def update_feed(feed_name: str, topic: str, transport: str = None): + """ + Args: + feed_name(str): Feed Name you want to update + topic(str): Topic name you want to update with + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ # [START asset_quickstart_update_feed] from google.cloud import asset_v1 from google.protobuf import field_mask_pb2 # TODO feed_name = 'Feed Name you want to update' # TODO topic = "Topic name you want to update with" + # TODO transport = 'Transport to use. Either "grpc" or "rest"' - client = asset_v1.AssetServiceClient() + client = asset_v1.AssetServiceClient(transport=transport) feed = asset_v1.Feed() feed.name = feed_name feed.feed_output_config.pubsub_destination.topic = topic diff --git a/samples/snippets/quickstart_updatefeed_test.py b/samples/snippets/quickstart_updatefeed_test.py index e09cb191..d910c329 100644 --- a/samples/snippets/quickstart_updatefeed_test.py +++ b/samples/snippets/quickstart_updatefeed_test.py @@ -14,11 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + import quickstart_updatefeed -def test_update_feed(capsys, test_feed, another_topic): - quickstart_updatefeed.update_feed(test_feed.name, another_topic.name) +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_update_feed(transport, capsys, test_feed, another_topic): + quickstart_updatefeed.update_feed( + feed_name=test_feed.name, + topic=another_topic.name, + transport=transport, + ) out, _ = capsys.readouterr() assert "updated_feed" in out diff --git a/tests/system/test_vpcsc.py b/tests/system/test_vpcsc.py index fc85bd7a..d55e08d1 100644 --- a/tests/system/test_vpcsc.py +++ b/tests/system/test_vpcsc.py @@ -27,8 +27,13 @@ @pytest.fixture -def client(): - return asset_v1.AssetServiceClient() +def client(transport: str = None): + """ + Args: + transport(str): The transport to use. For example, "grpc" + or "rest". If set to None, a transport is chosen automatically. + """ + return asset_v1.AssetServiceClient(transport=transport) @pytest.fixture @@ -48,17 +53,19 @@ def parent_outside(): @vpcsc_config.skip_unless_inside_vpcsc -def test_export_assets_inside(client, output_config, parent_inside): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_export_assets_inside(client, output_config, parent_inside, transport): with pytest.raises(exceptions.InvalidArgument): - client.export_assets( + client(transport=transport).export_assets( request={"parent": parent_inside, "output_config": output_config} ) @vpcsc_config.skip_unless_inside_vpcsc -def test_export_assets_outside(client, output_config, parent_outside): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_export_assets_outside(client, output_config, parent_outside, transport): with pytest.raises(exceptions.PermissionDenied) as exc: - client.export_assets( + client(transport=transport).export_assets( request={"parent": parent_outside, "output_config": output_config} ) @@ -66,9 +73,10 @@ def test_export_assets_outside(client, output_config, parent_outside): @vpcsc_config.skip_unless_inside_vpcsc -def test_batch_get_assets_history_inside(client, parent_inside): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_batch_get_assets_history_inside(client, parent_inside, transport): read_time_window = {} - client.batch_get_assets_history( + client(transport=transport).batch_get_assets_history( request={ "parent": parent_inside, "read_time_window": {}, @@ -78,11 +86,12 @@ def test_batch_get_assets_history_inside(client, parent_inside): @vpcsc_config.skip_unless_inside_vpcsc -def test_batch_get_assets_history_outside(client, parent_outside): +@pytest.mark.parametrize("transport", ["grpc", "rest"]) +def test_batch_get_assets_history_outside(client, parent_outside, transport): content_type = asset_v1.ContentType.CONTENT_TYPE_UNSPECIFIED read_time_window = {} with pytest.raises(exceptions.PermissionDenied) as exc: - client.batch_get_assets_history( + client(transport=transport).batch_get_assets_history( request={ "parent": parent_outside, "read_time_window": {}, diff --git a/tests/unit/gapic/asset_v1/test_asset_service.py b/tests/unit/gapic/asset_v1/test_asset_service.py index a6f7fa22..a13ce647 100644 --- a/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1/test_asset_service.py @@ -24,10 +24,17 @@ import grpc from grpc.experimental import aio +from collections.abc import Iterable +from google.protobuf import json_format +import json import math import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule from proto.marshal.rules import wrappers +from requests import Response +from requests import Request, PreparedRequest +from requests.sessions import Session +from google.protobuf import json_format from google.api_core import client_options from google.api_core import exceptions as core_exceptions @@ -103,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_info(client_class, transport_name): @@ -116,7 +124,11 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -124,6 +136,7 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ [ (transports.AssetServiceGrpcTransport, "grpc"), (transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_service_account_always_use_jwt( @@ -149,6 +162,7 @@ def test_asset_service_client_service_account_always_use_jwt( [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_file(client_class, transport_name): @@ -169,13 +183,18 @@ def test_asset_service_client_from_service_account_file(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() available_transports = [ transports.AssetServiceGrpcTransport, + transports.AssetServiceRestTransport, ] assert transport in available_transports @@ -192,6 +211,7 @@ def test_asset_service_client_get_transport_class(): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) @mock.patch.object( @@ -335,6 +355,8 @@ def test_asset_service_client_client_options( "grpc_asyncio", "false", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "true"), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -528,6 +550,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_client_options_scopes( @@ -568,6 +591,7 @@ def test_asset_service_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", None), ], ) def test_asset_service_client_client_options_credentials_file( @@ -7143,218 +7167,6893 @@ async def test_analyze_org_policy_governed_assets_async_pages(): assert page_.raw_page.next_page_token == token -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.AssetServiceGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + asset_service.ExportAssetsRequest, + dict, + ], +) +def test_export_assets_rest(request_type): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = AssetServiceClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.AssetServiceGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.AssetServiceGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options=options, - transport=transport, - ) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.export_assets(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_assets_rest_required_fields( + request_type=asset_service.ExportAssetsRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.AssetServiceGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.export_assets(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_assets_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_assets._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "outputConfig", + ) ) + ) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.AssetServiceGrpcTransport( +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_assets_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), ) client = AssetServiceClient(transport=transport) - assert client.transport is transport + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AssetServiceRestInterceptor, "post_export_assets" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_export_assets" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.ExportAssetsRequest.pb( + asset_service.ExportAssetsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = asset_service.ExportAssetsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_assets( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.AssetServiceGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - channel = transport.grpc_channel - assert channel - transport = transports.AssetServiceGrpcAsyncIOTransport( +def test_export_assets_rest_bad_request( + transport: str = "rest", request_type=asset_service.ExportAssetsRequest +): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AssetServiceGrpcTransport, - transports.AssetServiceGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.export_assets(request) + + +def test_export_assets_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + asset_service.ListAssetsRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = AssetServiceClient.get_transport_class(transport_name)( +def test_list_assets_rest(request_type): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListAssetsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_assets(request) + + # 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_rest_required_fields(request_type=asset_service.ListAssetsRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_assets._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "asset_types", + "content_type", + "page_size", + "page_token", + "read_time", + "relationship_types", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.AssetServiceGrpcTransport, + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.ListAssetsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.ListAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_assets(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_assets_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_assets._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "assetTypes", + "contentType", + "pageSize", + "pageToken", + "readTime", + "relationshipTypes", + ) + ) + & set(("parent",)) ) -def test_asset_service_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.AssetServiceTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_assets_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_list_assets" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_list_assets" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.ListAssetsRequest.pb( + asset_service.ListAssetsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.ListAssetsResponse.to_json( + asset_service.ListAssetsResponse() ) + request = asset_service.ListAssetsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.ListAssetsResponse() -def test_asset_service_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.asset_v1.services.asset_service.transports.AssetServiceTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.AssetServiceTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_assets( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "export_assets", - "list_assets", - "batch_get_assets_history", - "create_feed", - "get_feed", - "list_feeds", - "update_feed", - "delete_feed", - "search_all_resources", - "search_all_iam_policies", - "analyze_iam_policy", - "analyze_iam_policy_longrunning", - "analyze_move", - "query_assets", - "create_saved_query", - "get_saved_query", - "list_saved_queries", - "update_saved_query", - "delete_saved_query", - "batch_get_effective_iam_policies", - "analyze_org_policies", - "analyze_org_policy_governed_containers", - "analyze_org_policy_governed_assets", + pre.assert_called_once() + post.assert_called_once() + + +def test_list_assets_rest_bad_request( + transport: str = "rest", request_type=asset_service.ListAssetsRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_assets(request) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_assets_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) -def test_asset_service_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.asset_v1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AssetServiceTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=("https://www.googleapis.com/auth/cloud-platform",), - quota_project_id="octopus", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListAssetsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) + mock_args.update(sample_request) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -def test_asset_service_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.asset_v1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AssetServiceTransport() - adc.assert_called_once() + client.list_assets(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{parent=*/*}/assets" % client.transport._host, args[1] + ) + + +def test_list_assets_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # 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", + ) + + +def test_list_assets_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + 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(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(asset_service.ListAssetsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "sample1/sample2"} + + pager = client.list_assets(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, assets.Asset) for i in results) + + pages = list(client.list_assets(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.BatchGetAssetsHistoryRequest, + dict, + ], +) +def test_batch_get_assets_history_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.BatchGetAssetsHistoryResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.BatchGetAssetsHistoryResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_get_assets_history(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.BatchGetAssetsHistoryResponse) + + +def test_batch_get_assets_history_rest_required_fields( + request_type=asset_service.BatchGetAssetsHistoryRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_get_assets_history._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_get_assets_history._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "asset_names", + "content_type", + "read_time_window", + "relationship_types", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.BatchGetAssetsHistoryResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.BatchGetAssetsHistoryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_get_assets_history(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_get_assets_history_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_get_assets_history._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "assetNames", + "contentType", + "readTimeWindow", + "relationshipTypes", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_get_assets_history_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_batch_get_assets_history" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_batch_get_assets_history" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.BatchGetAssetsHistoryRequest.pb( + asset_service.BatchGetAssetsHistoryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.BatchGetAssetsHistoryResponse.to_json( + asset_service.BatchGetAssetsHistoryResponse() + ) + + request = asset_service.BatchGetAssetsHistoryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.BatchGetAssetsHistoryResponse() + + client.batch_get_assets_history( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_get_assets_history_rest_bad_request( + transport: str = "rest", request_type=asset_service.BatchGetAssetsHistoryRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_get_assets_history(request) + + +def test_batch_get_assets_history_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.CreateFeedRequest, + dict, + ], +) +def test_create_feed_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed( + name="name_value", + asset_names=["asset_names_value"], + asset_types=["asset_types_value"], + content_type=asset_service.ContentType.RESOURCE, + relationship_types=["relationship_types_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_feed(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.Feed) + assert response.name == "name_value" + assert response.asset_names == ["asset_names_value"] + assert response.asset_types == ["asset_types_value"] + assert response.content_type == asset_service.ContentType.RESOURCE + assert response.relationship_types == ["relationship_types_value"] + + +def test_create_feed_rest_required_fields(request_type=asset_service.CreateFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["feed_id"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["feedId"] = "feed_id_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "feedId" in jsonified_request + assert jsonified_request["feedId"] == "feed_id_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_feed._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "feedId", + "feed", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_create_feed" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_create_feed" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.CreateFeedRequest.pb( + asset_service.CreateFeedRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.Feed.to_json(asset_service.Feed()) + + request = asset_service.CreateFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.Feed() + + client.create_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.CreateFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_feed(request) + + +def test_create_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{parent=*/*}/feeds" % client.transport._host, args[1] + ) + + +def test_create_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_feed( + asset_service.CreateFeedRequest(), + parent="parent_value", + ) + + +def test_create_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.GetFeedRequest, + dict, + ], +) +def test_get_feed_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed( + name="name_value", + asset_names=["asset_names_value"], + asset_types=["asset_types_value"], + content_type=asset_service.ContentType.RESOURCE, + relationship_types=["relationship_types_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_feed(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.Feed) + assert response.name == "name_value" + assert response.asset_names == ["asset_names_value"] + assert response.asset_types == ["asset_types_value"] + assert response.content_type == asset_service.ContentType.RESOURCE + assert response.relationship_types == ["relationship_types_value"] + + +def test_get_feed_rest_required_fields(request_type=asset_service.GetFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_feed._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_get_feed" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_get_feed" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.GetFeedRequest.pb(asset_service.GetFeedRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.Feed.to_json(asset_service.Feed()) + + request = asset_service.GetFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.Feed() + + client.get_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.GetFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_feed(request) + + +def test_get_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "sample1/sample2/feeds/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{name=*/*/feeds/*}" % client.transport._host, args[1] + ) + + +def test_get_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_feed( + asset_service.GetFeedRequest(), + name="name_value", + ) + + +def test_get_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.ListFeedsRequest, + dict, + ], +) +def test_list_feeds_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListFeedsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListFeedsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_feeds(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.ListFeedsResponse) + + +def test_list_feeds_rest_required_fields(request_type=asset_service.ListFeedsRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_feeds._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_feeds._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.ListFeedsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.ListFeedsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_feeds(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_feeds_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_feeds._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_feeds_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_list_feeds" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_list_feeds" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.ListFeedsRequest.pb(asset_service.ListFeedsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.ListFeedsResponse.to_json( + asset_service.ListFeedsResponse() + ) + + request = asset_service.ListFeedsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.ListFeedsResponse() + + client.list_feeds( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_feeds_rest_bad_request( + transport: str = "rest", request_type=asset_service.ListFeedsRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_feeds(request) + + +def test_list_feeds_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListFeedsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListFeedsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_feeds(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{parent=*/*}/feeds" % client.transport._host, args[1] + ) + + +def test_list_feeds_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_feeds( + asset_service.ListFeedsRequest(), + parent="parent_value", + ) + + +def test_list_feeds_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.UpdateFeedRequest, + dict, + ], +) +def test_update_feed_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"feed": {"name": "sample1/sample2/feeds/sample3"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed( + name="name_value", + asset_names=["asset_names_value"], + asset_types=["asset_types_value"], + content_type=asset_service.ContentType.RESOURCE, + relationship_types=["relationship_types_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_feed(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.Feed) + assert response.name == "name_value" + assert response.asset_names == ["asset_names_value"] + assert response.asset_types == ["asset_types_value"] + assert response.content_type == asset_service.ContentType.RESOURCE + assert response.relationship_types == ["relationship_types_value"] + + +def test_update_feed_rest_required_fields(request_type=asset_service.UpdateFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_feed._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "feed", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_update_feed" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_update_feed" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.UpdateFeedRequest.pb( + asset_service.UpdateFeedRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.Feed.to_json(asset_service.Feed()) + + request = asset_service.UpdateFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.Feed() + + client.update_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.UpdateFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"feed": {"name": "sample1/sample2/feeds/sample3"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_feed(request) + + +def test_update_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + + # get arguments that satisfy an http rule for this method + sample_request = {"feed": {"name": "sample1/sample2/feeds/sample3"}} + + # get truthy value for each flattened field + mock_args = dict( + feed=asset_service.Feed(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{feed.name=*/*/feeds/*}" % client.transport._host, args[1] + ) + + +def test_update_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_feed( + asset_service.UpdateFeedRequest(), + feed=asset_service.Feed(name="name_value"), + ) + + +def test_update_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.DeleteFeedRequest, + dict, + ], +) +def test_delete_feed_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_feed(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_feed_rest_required_fields(request_type=asset_service.DeleteFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_feed._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_delete_feed" + ) as pre: + pre.assert_not_called() + pb_message = asset_service.DeleteFeedRequest.pb( + asset_service.DeleteFeedRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = asset_service.DeleteFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.DeleteFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_feed(request) + + +def test_delete_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "sample1/sample2/feeds/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{name=*/*/feeds/*}" % client.transport._host, args[1] + ) + + +def test_delete_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_feed( + asset_service.DeleteFeedRequest(), + name="name_value", + ) + + +def test_delete_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.SearchAllResourcesRequest, + dict, + ], +) +def test_search_all_resources_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllResourcesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllResourcesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.search_all_resources(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.SearchAllResourcesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_search_all_resources_rest_required_fields( + request_type=asset_service.SearchAllResourcesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_resources._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["scope"] = "scope_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_resources._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "asset_types", + "order_by", + "page_size", + "page_token", + "query", + "read_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllResourcesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SearchAllResourcesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.search_all_resources(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_search_all_resources_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.search_all_resources._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "assetTypes", + "orderBy", + "pageSize", + "pageToken", + "query", + "readMask", + ) + ) + & set(("scope",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_search_all_resources_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_search_all_resources" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_search_all_resources" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.SearchAllResourcesRequest.pb( + asset_service.SearchAllResourcesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SearchAllResourcesResponse.to_json( + asset_service.SearchAllResourcesResponse() + ) + + request = asset_service.SearchAllResourcesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SearchAllResourcesResponse() + + client.search_all_resources( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_search_all_resources_rest_bad_request( + transport: str = "rest", request_type=asset_service.SearchAllResourcesRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.search_all_resources(request) + + +def test_search_all_resources_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllResourcesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + query="query_value", + asset_types=["asset_types_value"], + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllResourcesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.search_all_resources(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{scope=*/*}:searchAllResources" % client.transport._host, args[1] + ) + + +def test_search_all_resources_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.search_all_resources( + asset_service.SearchAllResourcesRequest(), + scope="scope_value", + query="query_value", + asset_types=["asset_types_value"], + ) + + +def test_search_all_resources_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.SearchAllResourcesResponse( + results=[ + assets.ResourceSearchResult(), + assets.ResourceSearchResult(), + assets.ResourceSearchResult(), + ], + next_page_token="abc", + ), + asset_service.SearchAllResourcesResponse( + results=[], + next_page_token="def", + ), + asset_service.SearchAllResourcesResponse( + results=[ + assets.ResourceSearchResult(), + ], + next_page_token="ghi", + ), + asset_service.SearchAllResourcesResponse( + results=[ + assets.ResourceSearchResult(), + assets.ResourceSearchResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.SearchAllResourcesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.search_all_resources(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, assets.ResourceSearchResult) for i in results) + + pages = list(client.search_all_resources(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.SearchAllIamPoliciesRequest, + dict, + ], +) +def test_search_all_iam_policies_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllIamPoliciesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllIamPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.search_all_iam_policies(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.SearchAllIamPoliciesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_search_all_iam_policies_rest_required_fields( + request_type=asset_service.SearchAllIamPoliciesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_iam_policies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["scope"] = "scope_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_iam_policies._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "asset_types", + "order_by", + "page_size", + "page_token", + "query", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllIamPoliciesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SearchAllIamPoliciesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.search_all_iam_policies(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_search_all_iam_policies_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.search_all_iam_policies._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "assetTypes", + "orderBy", + "pageSize", + "pageToken", + "query", + ) + ) + & set(("scope",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_search_all_iam_policies_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_search_all_iam_policies" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_search_all_iam_policies" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.SearchAllIamPoliciesRequest.pb( + asset_service.SearchAllIamPoliciesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SearchAllIamPoliciesResponse.to_json( + asset_service.SearchAllIamPoliciesResponse() + ) + + request = asset_service.SearchAllIamPoliciesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SearchAllIamPoliciesResponse() + + client.search_all_iam_policies( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_search_all_iam_policies_rest_bad_request( + transport: str = "rest", request_type=asset_service.SearchAllIamPoliciesRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.search_all_iam_policies(request) + + +def test_search_all_iam_policies_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllIamPoliciesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + query="query_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllIamPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.search_all_iam_policies(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{scope=*/*}:searchAllIamPolicies" % client.transport._host, args[1] + ) + + +def test_search_all_iam_policies_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.search_all_iam_policies( + asset_service.SearchAllIamPoliciesRequest(), + scope="scope_value", + query="query_value", + ) + + +def test_search_all_iam_policies_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.SearchAllIamPoliciesResponse( + results=[ + assets.IamPolicySearchResult(), + assets.IamPolicySearchResult(), + assets.IamPolicySearchResult(), + ], + next_page_token="abc", + ), + asset_service.SearchAllIamPoliciesResponse( + results=[], + next_page_token="def", + ), + asset_service.SearchAllIamPoliciesResponse( + results=[ + assets.IamPolicySearchResult(), + ], + next_page_token="ghi", + ), + asset_service.SearchAllIamPoliciesResponse( + results=[ + assets.IamPolicySearchResult(), + assets.IamPolicySearchResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.SearchAllIamPoliciesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.search_all_iam_policies(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, assets.IamPolicySearchResult) for i in results) + + pages = list(client.search_all_iam_policies(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.AnalyzeIamPolicyRequest, + dict, + ], +) +def test_analyze_iam_policy_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"analysis_query": {"scope": "sample1/sample2"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeIamPolicyResponse( + fully_explored=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeIamPolicyResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_iam_policy(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.AnalyzeIamPolicyResponse) + assert response.fully_explored is True + + +def test_analyze_iam_policy_rest_required_fields( + request_type=asset_service.AnalyzeIamPolicyRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_iam_policy._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_iam_policy._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "analysis_query", + "execution_timeout", + "saved_analysis_query", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeIamPolicyResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.AnalyzeIamPolicyResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_iam_policy(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_iam_policy_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.analyze_iam_policy._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "analysisQuery", + "executionTimeout", + "savedAnalysisQuery", + ) + ) + & set(("analysisQuery",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_iam_policy_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_analyze_iam_policy" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_analyze_iam_policy" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.AnalyzeIamPolicyRequest.pb( + asset_service.AnalyzeIamPolicyRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.AnalyzeIamPolicyResponse.to_json( + asset_service.AnalyzeIamPolicyResponse() + ) + + request = asset_service.AnalyzeIamPolicyRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.AnalyzeIamPolicyResponse() + + client.analyze_iam_policy( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_iam_policy_rest_bad_request( + transport: str = "rest", request_type=asset_service.AnalyzeIamPolicyRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"analysis_query": {"scope": "sample1/sample2"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_iam_policy(request) + + +def test_analyze_iam_policy_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.AnalyzeIamPolicyLongrunningRequest, + dict, + ], +) +def test_analyze_iam_policy_longrunning_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"analysis_query": {"scope": "sample1/sample2"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_iam_policy_longrunning(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_analyze_iam_policy_longrunning_rest_required_fields( + request_type=asset_service.AnalyzeIamPolicyLongrunningRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_iam_policy_longrunning._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_iam_policy_longrunning._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_iam_policy_longrunning(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_iam_policy_longrunning_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.analyze_iam_policy_longrunning._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(()) + & set( + ( + "analysisQuery", + "outputConfig", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_iam_policy_longrunning_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AssetServiceRestInterceptor, "post_analyze_iam_policy_longrunning" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_analyze_iam_policy_longrunning" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.AnalyzeIamPolicyLongrunningRequest.pb( + asset_service.AnalyzeIamPolicyLongrunningRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = asset_service.AnalyzeIamPolicyLongrunningRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.analyze_iam_policy_longrunning( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_iam_policy_longrunning_rest_bad_request( + transport: str = "rest", + request_type=asset_service.AnalyzeIamPolicyLongrunningRequest, +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"analysis_query": {"scope": "sample1/sample2"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_iam_policy_longrunning(request) + + +def test_analyze_iam_policy_longrunning_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.AnalyzeMoveRequest, + dict, + ], +) +def test_analyze_move_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeMoveResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeMoveResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_move(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.AnalyzeMoveResponse) + + +def test_analyze_move_rest_required_fields( + request_type=asset_service.AnalyzeMoveRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["resource"] = "" + request_init["destination_parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "destinationParent" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_move._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "destinationParent" in jsonified_request + assert jsonified_request["destinationParent"] == request_init["destination_parent"] + + jsonified_request["resource"] = "resource_value" + jsonified_request["destinationParent"] = "destination_parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_move._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "destination_parent", + "view", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "resource" in jsonified_request + assert jsonified_request["resource"] == "resource_value" + assert "destinationParent" in jsonified_request + assert jsonified_request["destinationParent"] == "destination_parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeMoveResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.AnalyzeMoveResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_move(request) + + expected_params = [ + ( + "destinationParent", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_move_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.analyze_move._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "destinationParent", + "view", + ) + ) + & set( + ( + "resource", + "destinationParent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_move_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_analyze_move" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_analyze_move" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.AnalyzeMoveRequest.pb( + asset_service.AnalyzeMoveRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.AnalyzeMoveResponse.to_json( + asset_service.AnalyzeMoveResponse() + ) + + request = asset_service.AnalyzeMoveRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.AnalyzeMoveResponse() + + client.analyze_move( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_move_rest_bad_request( + transport: str = "rest", request_type=asset_service.AnalyzeMoveRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"resource": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_move(request) + + +def test_analyze_move_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.QueryAssetsRequest, + dict, + ], +) +def test_query_assets_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.QueryAssetsResponse( + job_reference="job_reference_value", + done=True, + error=status_pb2.Status(code=411), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.QueryAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.query_assets(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.QueryAssetsResponse) + assert response.job_reference == "job_reference_value" + assert response.done is True + + +def test_query_assets_rest_required_fields( + request_type=asset_service.QueryAssetsRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).query_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).query_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.QueryAssetsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.QueryAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.query_assets(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_query_assets_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.query_assets._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_query_assets_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_query_assets" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_query_assets" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.QueryAssetsRequest.pb( + asset_service.QueryAssetsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.QueryAssetsResponse.to_json( + asset_service.QueryAssetsResponse() + ) + + request = asset_service.QueryAssetsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.QueryAssetsResponse() + + client.query_assets( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_query_assets_rest_bad_request( + transport: str = "rest", request_type=asset_service.QueryAssetsRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.query_assets(request) + + +def test_query_assets_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.CreateSavedQueryRequest, + dict, + ], +) +def test_create_saved_query_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request_init["saved_query"] = { + "name": "name_value", + "description": "description_value", + "create_time": {"seconds": 751, "nanos": 543}, + "creator": "creator_value", + "last_update_time": {}, + "last_updater": "last_updater_value", + "labels": {}, + "content": { + "iam_policy_analysis_query": { + "scope": "scope_value", + "resource_selector": {"full_resource_name": "full_resource_name_value"}, + "identity_selector": {"identity": "identity_value"}, + "access_selector": { + "roles": ["roles_value1", "roles_value2"], + "permissions": ["permissions_value1", "permissions_value2"], + }, + "options": { + "expand_groups": True, + "expand_roles": True, + "expand_resources": True, + "output_resource_edges": True, + "output_group_edges": True, + "analyze_service_account_impersonation": True, + }, + "condition_context": {"access_time": {}}, + } + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery( + name="name_value", + description="description_value", + creator="creator_value", + last_updater="last_updater_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_saved_query(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.SavedQuery) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.creator == "creator_value" + assert response.last_updater == "last_updater_value" + + +def test_create_saved_query_rest_required_fields( + request_type=asset_service.CreateSavedQueryRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["saved_query_id"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "savedQueryId" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_saved_query._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "savedQueryId" in jsonified_request + assert jsonified_request["savedQueryId"] == request_init["saved_query_id"] + + jsonified_request["parent"] = "parent_value" + jsonified_request["savedQueryId"] = "saved_query_id_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_saved_query._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("saved_query_id",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "savedQueryId" in jsonified_request + assert jsonified_request["savedQueryId"] == "saved_query_id_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_saved_query(request) + + expected_params = [ + ( + "savedQueryId", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_saved_query_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_saved_query._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("savedQueryId",)) + & set( + ( + "parent", + "savedQuery", + "savedQueryId", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_saved_query_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_create_saved_query" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_create_saved_query" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.CreateSavedQueryRequest.pb( + asset_service.CreateSavedQueryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SavedQuery.to_json( + asset_service.SavedQuery() + ) + + request = asset_service.CreateSavedQueryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SavedQuery() + + client.create_saved_query( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_saved_query_rest_bad_request( + transport: str = "rest", request_type=asset_service.CreateSavedQueryRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request_init["saved_query"] = { + "name": "name_value", + "description": "description_value", + "create_time": {"seconds": 751, "nanos": 543}, + "creator": "creator_value", + "last_update_time": {}, + "last_updater": "last_updater_value", + "labels": {}, + "content": { + "iam_policy_analysis_query": { + "scope": "scope_value", + "resource_selector": {"full_resource_name": "full_resource_name_value"}, + "identity_selector": {"identity": "identity_value"}, + "access_selector": { + "roles": ["roles_value1", "roles_value2"], + "permissions": ["permissions_value1", "permissions_value2"], + }, + "options": { + "expand_groups": True, + "expand_roles": True, + "expand_resources": True, + "output_resource_edges": True, + "output_group_edges": True, + "analyze_service_account_impersonation": True, + }, + "condition_context": {"access_time": {}}, + } + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_saved_query(request) + + +def test_create_saved_query_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + saved_query=asset_service.SavedQuery(name="name_value"), + saved_query_id="saved_query_id_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_saved_query(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{parent=*/*}/savedQueries" % client.transport._host, args[1] + ) + + +def test_create_saved_query_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_saved_query( + asset_service.CreateSavedQueryRequest(), + parent="parent_value", + saved_query=asset_service.SavedQuery(name="name_value"), + saved_query_id="saved_query_id_value", + ) + + +def test_create_saved_query_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.GetSavedQueryRequest, + dict, + ], +) +def test_get_saved_query_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/savedQueries/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery( + name="name_value", + description="description_value", + creator="creator_value", + last_updater="last_updater_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_saved_query(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.SavedQuery) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.creator == "creator_value" + assert response.last_updater == "last_updater_value" + + +def test_get_saved_query_rest_required_fields( + request_type=asset_service.GetSavedQueryRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_saved_query._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_saved_query._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_saved_query(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_saved_query_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_saved_query._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_saved_query_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_get_saved_query" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_get_saved_query" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.GetSavedQueryRequest.pb( + asset_service.GetSavedQueryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SavedQuery.to_json( + asset_service.SavedQuery() + ) + + request = asset_service.GetSavedQueryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SavedQuery() + + client.get_saved_query( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_saved_query_rest_bad_request( + transport: str = "rest", request_type=asset_service.GetSavedQueryRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/savedQueries/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_saved_query(request) + + +def test_get_saved_query_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "sample1/sample2/savedQueries/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_saved_query(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{name=*/*/savedQueries/*}" % client.transport._host, args[1] + ) + + +def test_get_saved_query_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_saved_query( + asset_service.GetSavedQueryRequest(), + name="name_value", + ) + + +def test_get_saved_query_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.ListSavedQueriesRequest, + dict, + ], +) +def test_list_saved_queries_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListSavedQueriesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListSavedQueriesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_saved_queries(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSavedQueriesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_saved_queries_rest_required_fields( + request_type=asset_service.ListSavedQueriesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_saved_queries._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_saved_queries._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.ListSavedQueriesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.ListSavedQueriesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_saved_queries(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_saved_queries_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_saved_queries._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_saved_queries_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_list_saved_queries" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_list_saved_queries" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.ListSavedQueriesRequest.pb( + asset_service.ListSavedQueriesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.ListSavedQueriesResponse.to_json( + asset_service.ListSavedQueriesResponse() + ) + + request = asset_service.ListSavedQueriesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.ListSavedQueriesResponse() + + client.list_saved_queries( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_saved_queries_rest_bad_request( + transport: str = "rest", request_type=asset_service.ListSavedQueriesRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_saved_queries(request) + + +def test_list_saved_queries_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListSavedQueriesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListSavedQueriesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_saved_queries(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{parent=*/*}/savedQueries" % client.transport._host, args[1] + ) + + +def test_list_saved_queries_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_saved_queries( + asset_service.ListSavedQueriesRequest(), + parent="parent_value", + ) + + +def test_list_saved_queries_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.ListSavedQueriesResponse( + saved_queries=[ + asset_service.SavedQuery(), + asset_service.SavedQuery(), + asset_service.SavedQuery(), + ], + next_page_token="abc", + ), + asset_service.ListSavedQueriesResponse( + saved_queries=[], + next_page_token="def", + ), + asset_service.ListSavedQueriesResponse( + saved_queries=[ + asset_service.SavedQuery(), + ], + next_page_token="ghi", + ), + asset_service.ListSavedQueriesResponse( + saved_queries=[ + asset_service.SavedQuery(), + asset_service.SavedQuery(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.ListSavedQueriesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "sample1/sample2"} + + pager = client.list_saved_queries(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, asset_service.SavedQuery) for i in results) + + pages = list(client.list_saved_queries(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.UpdateSavedQueryRequest, + dict, + ], +) +def test_update_saved_query_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"saved_query": {"name": "sample1/sample2/savedQueries/sample3"}} + request_init["saved_query"] = { + "name": "sample1/sample2/savedQueries/sample3", + "description": "description_value", + "create_time": {"seconds": 751, "nanos": 543}, + "creator": "creator_value", + "last_update_time": {}, + "last_updater": "last_updater_value", + "labels": {}, + "content": { + "iam_policy_analysis_query": { + "scope": "scope_value", + "resource_selector": {"full_resource_name": "full_resource_name_value"}, + "identity_selector": {"identity": "identity_value"}, + "access_selector": { + "roles": ["roles_value1", "roles_value2"], + "permissions": ["permissions_value1", "permissions_value2"], + }, + "options": { + "expand_groups": True, + "expand_roles": True, + "expand_resources": True, + "output_resource_edges": True, + "output_group_edges": True, + "analyze_service_account_impersonation": True, + }, + "condition_context": {"access_time": {}}, + } + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery( + name="name_value", + description="description_value", + creator="creator_value", + last_updater="last_updater_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_saved_query(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.SavedQuery) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.creator == "creator_value" + assert response.last_updater == "last_updater_value" + + +def test_update_saved_query_rest_required_fields( + request_type=asset_service.UpdateSavedQueryRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_saved_query._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_saved_query._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_saved_query(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_saved_query_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_saved_query._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "savedQuery", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_saved_query_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_update_saved_query" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_update_saved_query" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.UpdateSavedQueryRequest.pb( + asset_service.UpdateSavedQueryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SavedQuery.to_json( + asset_service.SavedQuery() + ) + + request = asset_service.UpdateSavedQueryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SavedQuery() + + client.update_saved_query( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_saved_query_rest_bad_request( + transport: str = "rest", request_type=asset_service.UpdateSavedQueryRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"saved_query": {"name": "sample1/sample2/savedQueries/sample3"}} + request_init["saved_query"] = { + "name": "sample1/sample2/savedQueries/sample3", + "description": "description_value", + "create_time": {"seconds": 751, "nanos": 543}, + "creator": "creator_value", + "last_update_time": {}, + "last_updater": "last_updater_value", + "labels": {}, + "content": { + "iam_policy_analysis_query": { + "scope": "scope_value", + "resource_selector": {"full_resource_name": "full_resource_name_value"}, + "identity_selector": {"identity": "identity_value"}, + "access_selector": { + "roles": ["roles_value1", "roles_value2"], + "permissions": ["permissions_value1", "permissions_value2"], + }, + "options": { + "expand_groups": True, + "expand_roles": True, + "expand_resources": True, + "output_resource_edges": True, + "output_group_edges": True, + "analyze_service_account_impersonation": True, + }, + "condition_context": {"access_time": {}}, + } + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_saved_query(request) + + +def test_update_saved_query_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SavedQuery() + + # get arguments that satisfy an http rule for this method + sample_request = { + "saved_query": {"name": "sample1/sample2/savedQueries/sample3"} + } + + # get truthy value for each flattened field + mock_args = dict( + saved_query=asset_service.SavedQuery(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SavedQuery.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_saved_query(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{saved_query.name=*/*/savedQueries/*}" % client.transport._host, + args[1], + ) + + +def test_update_saved_query_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_saved_query( + asset_service.UpdateSavedQueryRequest(), + saved_query=asset_service.SavedQuery(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_saved_query_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.DeleteSavedQueryRequest, + dict, + ], +) +def test_delete_saved_query_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/savedQueries/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_saved_query(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_saved_query_rest_required_fields( + request_type=asset_service.DeleteSavedQueryRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_saved_query._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_saved_query._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_saved_query(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_saved_query_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_saved_query._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_saved_query_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_delete_saved_query" + ) as pre: + pre.assert_not_called() + pb_message = asset_service.DeleteSavedQueryRequest.pb( + asset_service.DeleteSavedQueryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = asset_service.DeleteSavedQueryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_saved_query( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_saved_query_rest_bad_request( + transport: str = "rest", request_type=asset_service.DeleteSavedQueryRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/savedQueries/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_saved_query(request) + + +def test_delete_saved_query_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "sample1/sample2/savedQueries/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_saved_query(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{name=*/*/savedQueries/*}" % client.transport._host, args[1] + ) + + +def test_delete_saved_query_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_saved_query( + asset_service.DeleteSavedQueryRequest(), + name="name_value", + ) + + +def test_delete_saved_query_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.BatchGetEffectiveIamPoliciesRequest, + dict, + ], +) +def test_batch_get_effective_iam_policies_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.BatchGetEffectiveIamPoliciesResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.BatchGetEffectiveIamPoliciesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_get_effective_iam_policies(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.BatchGetEffectiveIamPoliciesResponse) + + +def test_batch_get_effective_iam_policies_rest_required_fields( + request_type=asset_service.BatchGetEffectiveIamPoliciesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request_init["names"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "names" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_get_effective_iam_policies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "names" in jsonified_request + assert jsonified_request["names"] == request_init["names"] + + jsonified_request["scope"] = "scope_value" + jsonified_request["names"] = "names_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_get_effective_iam_policies._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("names",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + assert "names" in jsonified_request + assert jsonified_request["names"] == "names_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.BatchGetEffectiveIamPoliciesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.BatchGetEffectiveIamPoliciesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_get_effective_iam_policies(request) + + expected_params = [ + ( + "names", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_get_effective_iam_policies_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = ( + transport.batch_get_effective_iam_policies._get_unset_required_fields({}) + ) + assert set(unset_fields) == ( + set(("names",)) + & set( + ( + "scope", + "names", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_get_effective_iam_policies_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_batch_get_effective_iam_policies" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_batch_get_effective_iam_policies" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.BatchGetEffectiveIamPoliciesRequest.pb( + asset_service.BatchGetEffectiveIamPoliciesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + asset_service.BatchGetEffectiveIamPoliciesResponse.to_json( + asset_service.BatchGetEffectiveIamPoliciesResponse() + ) + ) + + request = asset_service.BatchGetEffectiveIamPoliciesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.BatchGetEffectiveIamPoliciesResponse() + + client.batch_get_effective_iam_policies( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_get_effective_iam_policies_rest_bad_request( + transport: str = "rest", + request_type=asset_service.BatchGetEffectiveIamPoliciesRequest, +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_get_effective_iam_policies(request) + + +def test_batch_get_effective_iam_policies_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.AnalyzeOrgPoliciesRequest, + dict, + ], +) +def test_analyze_org_policies_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPoliciesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeOrgPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_org_policies(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.AnalyzeOrgPoliciesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_analyze_org_policies_rest_required_fields( + request_type=asset_service.AnalyzeOrgPoliciesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request_init["constraint"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "constraint" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_org_policies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "constraint" in jsonified_request + assert jsonified_request["constraint"] == request_init["constraint"] + + jsonified_request["scope"] = "scope_value" + jsonified_request["constraint"] = "constraint_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_org_policies._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "constraint", + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + assert "constraint" in jsonified_request + assert jsonified_request["constraint"] == "constraint_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPoliciesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.AnalyzeOrgPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_org_policies(request) + + expected_params = [ + ( + "constraint", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_org_policies_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.analyze_org_policies._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "constraint", + "filter", + "pageSize", + "pageToken", + ) + ) + & set( + ( + "scope", + "constraint", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_org_policies_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_analyze_org_policies" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_analyze_org_policies" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.AnalyzeOrgPoliciesRequest.pb( + asset_service.AnalyzeOrgPoliciesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.AnalyzeOrgPoliciesResponse.to_json( + asset_service.AnalyzeOrgPoliciesResponse() + ) + + request = asset_service.AnalyzeOrgPoliciesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.AnalyzeOrgPoliciesResponse() + + client.analyze_org_policies( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_org_policies_rest_bad_request( + transport: str = "rest", request_type=asset_service.AnalyzeOrgPoliciesRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_org_policies(request) + + +def test_analyze_org_policies_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPoliciesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + constraint="constraint_value", + filter="filter_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeOrgPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.analyze_org_policies(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{scope=*/*}:analyzeOrgPolicies" % client.transport._host, args[1] + ) + + +def test_analyze_org_policies_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.analyze_org_policies( + asset_service.AnalyzeOrgPoliciesRequest(), + scope="scope_value", + constraint="constraint_value", + filter="filter_value", + ) + + +def test_analyze_org_policies_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.AnalyzeOrgPoliciesResponse( + org_policy_results=[ + asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult(), + asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult(), + asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult(), + ], + next_page_token="abc", + ), + asset_service.AnalyzeOrgPoliciesResponse( + org_policy_results=[], + next_page_token="def", + ), + asset_service.AnalyzeOrgPoliciesResponse( + org_policy_results=[ + asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult(), + ], + next_page_token="ghi", + ), + asset_service.AnalyzeOrgPoliciesResponse( + org_policy_results=[ + asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult(), + asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.AnalyzeOrgPoliciesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.analyze_org_policies(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, asset_service.AnalyzeOrgPoliciesResponse.OrgPolicyResult) + for i in results + ) + + pages = list(client.analyze_org_policies(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.AnalyzeOrgPolicyGovernedContainersRequest, + dict, + ], +) +def test_analyze_org_policy_governed_containers_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPolicyGovernedContainersResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeOrgPolicyGovernedContainersResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_org_policy_governed_containers(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.AnalyzeOrgPolicyGovernedContainersPager) + assert response.next_page_token == "next_page_token_value" + + +def test_analyze_org_policy_governed_containers_rest_required_fields( + request_type=asset_service.AnalyzeOrgPolicyGovernedContainersRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request_init["constraint"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "constraint" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_org_policy_governed_containers._get_unset_required_fields( + jsonified_request + ) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "constraint" in jsonified_request + assert jsonified_request["constraint"] == request_init["constraint"] + + jsonified_request["scope"] = "scope_value" + jsonified_request["constraint"] = "constraint_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_org_policy_governed_containers._get_unset_required_fields( + jsonified_request + ) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "constraint", + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + assert "constraint" in jsonified_request + assert jsonified_request["constraint"] == "constraint_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPolicyGovernedContainersResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = ( + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.pb( + return_value + ) + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_org_policy_governed_containers(request) + + expected_params = [ + ( + "constraint", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_org_policy_governed_containers_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = ( + transport.analyze_org_policy_governed_containers._get_unset_required_fields({}) + ) + assert set(unset_fields) == ( + set( + ( + "constraint", + "filter", + "pageSize", + "pageToken", + ) + ) + & set( + ( + "scope", + "constraint", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_org_policy_governed_containers_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, + "post_analyze_org_policy_governed_containers", + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, + "pre_analyze_org_policy_governed_containers", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.AnalyzeOrgPolicyGovernedContainersRequest.pb( + asset_service.AnalyzeOrgPolicyGovernedContainersRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.to_json( + asset_service.AnalyzeOrgPolicyGovernedContainersResponse() + ) + ) + + request = asset_service.AnalyzeOrgPolicyGovernedContainersRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.AnalyzeOrgPolicyGovernedContainersResponse() + + client.analyze_org_policy_governed_containers( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_org_policy_governed_containers_rest_bad_request( + transport: str = "rest", + request_type=asset_service.AnalyzeOrgPolicyGovernedContainersRequest, +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_org_policy_governed_containers(request) + + +def test_analyze_org_policy_governed_containers_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPolicyGovernedContainersResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + constraint="constraint_value", + filter="filter_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeOrgPolicyGovernedContainersResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.analyze_org_policy_governed_containers(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{scope=*/*}:analyzeOrgPolicyGovernedContainers" + % client.transport._host, + args[1], + ) + + +def test_analyze_org_policy_governed_containers_rest_flattened_error( + transport: str = "rest", +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.analyze_org_policy_governed_containers( + asset_service.AnalyzeOrgPolicyGovernedContainersRequest(), + scope="scope_value", + constraint="constraint_value", + filter="filter_value", + ) + + +def test_analyze_org_policy_governed_containers_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.AnalyzeOrgPolicyGovernedContainersResponse( + governed_containers=[ + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer(), + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer(), + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer(), + ], + next_page_token="abc", + ), + asset_service.AnalyzeOrgPolicyGovernedContainersResponse( + governed_containers=[], + next_page_token="def", + ), + asset_service.AnalyzeOrgPolicyGovernedContainersResponse( + governed_containers=[ + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer(), + ], + next_page_token="ghi", + ), + asset_service.AnalyzeOrgPolicyGovernedContainersResponse( + governed_containers=[ + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer(), + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.analyze_org_policy_governed_containers(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance( + i, + asset_service.AnalyzeOrgPolicyGovernedContainersResponse.GovernedContainer, + ) + for i in results + ) + + pages = list( + client.analyze_org_policy_governed_containers(request=sample_request).pages + ) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.AnalyzeOrgPolicyGovernedAssetsRequest, + dict, + ], +) +def test_analyze_org_policy_governed_assets_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_org_policy_governed_assets(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.AnalyzeOrgPolicyGovernedAssetsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_analyze_org_policy_governed_assets_rest_required_fields( + request_type=asset_service.AnalyzeOrgPolicyGovernedAssetsRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request_init["constraint"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "constraint" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_org_policy_governed_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "constraint" in jsonified_request + assert jsonified_request["constraint"] == request_init["constraint"] + + jsonified_request["scope"] = "scope_value" + jsonified_request["constraint"] = "constraint_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_org_policy_governed_assets._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "constraint", + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + assert "constraint" in jsonified_request + assert jsonified_request["constraint"] == "constraint_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_org_policy_governed_assets(request) + + expected_params = [ + ( + "constraint", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_org_policy_governed_assets_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = ( + transport.analyze_org_policy_governed_assets._get_unset_required_fields({}) + ) + assert set(unset_fields) == ( + set( + ( + "constraint", + "filter", + "pageSize", + "pageToken", + ) + ) + & set( + ( + "scope", + "constraint", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_org_policy_governed_assets_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, + "post_analyze_org_policy_governed_assets", + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_analyze_org_policy_governed_assets" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.AnalyzeOrgPolicyGovernedAssetsRequest.pb( + asset_service.AnalyzeOrgPolicyGovernedAssetsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.to_json( + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse() + ) + ) + + request = asset_service.AnalyzeOrgPolicyGovernedAssetsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse() + + client.analyze_org_policy_governed_assets( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_org_policy_governed_assets_rest_bad_request( + transport: str = "rest", + request_type=asset_service.AnalyzeOrgPolicyGovernedAssetsRequest, +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_org_policy_governed_assets(request) + + +def test_analyze_org_policy_governed_assets_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + constraint="constraint_value", + filter="filter_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.analyze_org_policy_governed_assets(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{scope=*/*}:analyzeOrgPolicyGovernedAssets" % client.transport._host, + args[1], + ) + + +def test_analyze_org_policy_governed_assets_rest_flattened_error( + transport: str = "rest", +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.analyze_org_policy_governed_assets( + asset_service.AnalyzeOrgPolicyGovernedAssetsRequest(), + scope="scope_value", + constraint="constraint_value", + filter="filter_value", + ) + + +def test_analyze_org_policy_governed_assets_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse( + governed_assets=[ + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset(), + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset(), + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset(), + ], + next_page_token="abc", + ), + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse( + governed_assets=[], + next_page_token="def", + ), + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse( + governed_assets=[ + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset(), + ], + next_page_token="ghi", + ), + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse( + governed_assets=[ + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset(), + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.analyze_org_policy_governed_assets(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance( + i, asset_service.AnalyzeOrgPolicyGovernedAssetsResponse.GovernedAsset + ) + for i in results + ) + + pages = list( + client.analyze_org_policy_governed_assets(request=sample_request).pages + ) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AssetServiceClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AssetServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = AssetServiceClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AssetServiceGrpcTransport, + ) + + +def test_asset_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AssetServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_asset_service_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.asset_v1.services.asset_service.transports.AssetServiceTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.AssetServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "export_assets", + "list_assets", + "batch_get_assets_history", + "create_feed", + "get_feed", + "list_feeds", + "update_feed", + "delete_feed", + "search_all_resources", + "search_all_iam_policies", + "analyze_iam_policy", + "analyze_iam_policy_longrunning", + "analyze_move", + "query_assets", + "create_saved_query", + "get_saved_query", + "list_saved_queries", + "update_saved_query", + "delete_saved_query", + "batch_get_effective_iam_policies", + "analyze_org_policies", + "analyze_org_policy_governed_containers", + "analyze_org_policy_governed_assets", + "get_operation", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_asset_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.asset_v1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AssetServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +def test_asset_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.asset_v1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AssetServiceTransport() + adc.assert_called_once() def test_asset_service_auth_adc(): @@ -7394,6 +14093,7 @@ def test_asset_service_transport_auth_adc(transport_class): [ transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, ], ) def test_asset_service_transport_auth_gdch_credentials(transport_class): @@ -7488,11 +14188,40 @@ def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_clas ) +def test_asset_service_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AssetServiceRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_asset_service_rest_lro_client(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_no_port(transport_name): @@ -7503,7 +14232,11 @@ def test_asset_service_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -7511,6 +14244,7 @@ def test_asset_service_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_with_port(transport_name): @@ -7521,7 +14255,99 @@ def test_asset_service_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:8000") + assert client.transport._host == ( + "cloudasset.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_asset_service_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AssetServiceClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AssetServiceClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.export_assets._session + session2 = client2.transport.export_assets._session + assert session1 != session2 + session1 = client1.transport.list_assets._session + session2 = client2.transport.list_assets._session + assert session1 != session2 + session1 = client1.transport.batch_get_assets_history._session + session2 = client2.transport.batch_get_assets_history._session + assert session1 != session2 + session1 = client1.transport.create_feed._session + session2 = client2.transport.create_feed._session + assert session1 != session2 + session1 = client1.transport.get_feed._session + session2 = client2.transport.get_feed._session + assert session1 != session2 + session1 = client1.transport.list_feeds._session + session2 = client2.transport.list_feeds._session + assert session1 != session2 + session1 = client1.transport.update_feed._session + session2 = client2.transport.update_feed._session + assert session1 != session2 + session1 = client1.transport.delete_feed._session + session2 = client2.transport.delete_feed._session + assert session1 != session2 + session1 = client1.transport.search_all_resources._session + session2 = client2.transport.search_all_resources._session + assert session1 != session2 + session1 = client1.transport.search_all_iam_policies._session + session2 = client2.transport.search_all_iam_policies._session + assert session1 != session2 + session1 = client1.transport.analyze_iam_policy._session + session2 = client2.transport.analyze_iam_policy._session + assert session1 != session2 + session1 = client1.transport.analyze_iam_policy_longrunning._session + session2 = client2.transport.analyze_iam_policy_longrunning._session + assert session1 != session2 + session1 = client1.transport.analyze_move._session + session2 = client2.transport.analyze_move._session + assert session1 != session2 + session1 = client1.transport.query_assets._session + session2 = client2.transport.query_assets._session + assert session1 != session2 + session1 = client1.transport.create_saved_query._session + session2 = client2.transport.create_saved_query._session + assert session1 != session2 + session1 = client1.transport.get_saved_query._session + session2 = client2.transport.get_saved_query._session + assert session1 != session2 + session1 = client1.transport.list_saved_queries._session + session2 = client2.transport.list_saved_queries._session + assert session1 != session2 + session1 = client1.transport.update_saved_query._session + session2 = client2.transport.update_saved_query._session + assert session1 != session2 + session1 = client1.transport.delete_saved_query._session + session2 = client2.transport.delete_saved_query._session + assert session1 != session2 + session1 = client1.transport.batch_get_effective_iam_policies._session + session2 = client2.transport.batch_get_effective_iam_policies._session + assert session1 != session2 + session1 = client1.transport.analyze_org_policies._session + session2 = client2.transport.analyze_org_policies._session + assert session1 != session2 + session1 = client1.transport.analyze_org_policy_governed_containers._session + session2 = client2.transport.analyze_org_policy_governed_containers._session + assert session1 != session2 + session1 = client1.transport.analyze_org_policy_governed_assets._session + session2 = client2.transport.analyze_org_policy_governed_assets._session + assert session1 != session2 def test_asset_service_grpc_transport_channel(): @@ -7964,8 +14790,212 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "sample1/sample2/operations/sample3/sample4"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "sample1/sample2/operations/sample3/sample4"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation(transport: str = "grpc"): + 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 = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(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 response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + 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 = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(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 response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_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 = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(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", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_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 = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(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", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + 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.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_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.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -7983,6 +15013,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py index 7c2e9a08..76943e24 100644 --- a/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py @@ -24,10 +24,17 @@ import grpc from grpc.experimental import aio +from collections.abc import Iterable +from google.protobuf import json_format +import json import math import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule from proto.marshal.rules import wrappers +from requests import Response +from requests import Request, PreparedRequest +from requests.sessions import Session +from google.protobuf import json_format from google.api_core import client_options from google.api_core import exceptions as core_exceptions @@ -43,6 +50,7 @@ from google.cloud.asset_v1p1beta1.services.asset_service import transports from google.cloud.asset_v1p1beta1.types import asset_service from google.cloud.asset_v1p1beta1.types import assets +from google.longrunning import operations_pb2 from google.oauth2 import service_account import google.auth @@ -93,6 +101,7 @@ def test__get_default_mtls_endpoint(): [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_info(client_class, transport_name): @@ -106,7 +115,11 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -114,6 +127,7 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ [ (transports.AssetServiceGrpcTransport, "grpc"), (transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_service_account_always_use_jwt( @@ -139,6 +153,7 @@ def test_asset_service_client_service_account_always_use_jwt( [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_file(client_class, transport_name): @@ -159,13 +174,18 @@ def test_asset_service_client_from_service_account_file(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() available_transports = [ transports.AssetServiceGrpcTransport, + transports.AssetServiceRestTransport, ] assert transport in available_transports @@ -182,6 +202,7 @@ def test_asset_service_client_get_transport_class(): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) @mock.patch.object( @@ -325,6 +346,8 @@ def test_asset_service_client_client_options( "grpc_asyncio", "false", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "true"), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -518,6 +541,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_client_options_scopes( @@ -558,6 +582,7 @@ def test_asset_service_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", None), ], ) def test_asset_service_client_client_options_credentials_file( @@ -1584,6 +1609,700 @@ async def test_search_all_iam_policies_async_pages(): assert page_.raw_page.next_page_token == token +@pytest.mark.parametrize( + "request_type", + [ + asset_service.SearchAllResourcesRequest, + dict, + ], +) +def test_search_all_resources_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllResourcesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllResourcesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.search_all_resources(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.SearchAllResourcesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_search_all_resources_rest_required_fields( + request_type=asset_service.SearchAllResourcesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_resources._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["scope"] = "scope_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_resources._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "asset_types", + "order_by", + "page_size", + "page_token", + "query", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllResourcesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SearchAllResourcesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.search_all_resources(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_search_all_resources_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.search_all_resources._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "assetTypes", + "orderBy", + "pageSize", + "pageToken", + "query", + ) + ) + & set(("scope",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_search_all_resources_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_search_all_resources" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_search_all_resources" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.SearchAllResourcesRequest.pb( + asset_service.SearchAllResourcesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SearchAllResourcesResponse.to_json( + asset_service.SearchAllResourcesResponse() + ) + + request = asset_service.SearchAllResourcesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SearchAllResourcesResponse() + + client.search_all_resources( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_search_all_resources_rest_bad_request( + transport: str = "rest", request_type=asset_service.SearchAllResourcesRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.search_all_resources(request) + + +def test_search_all_resources_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllResourcesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + query="query_value", + asset_types=["asset_types_value"], + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllResourcesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.search_all_resources(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p1beta1/{scope=*/*}/resources:searchAll" % client.transport._host, + args[1], + ) + + +def test_search_all_resources_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.search_all_resources( + asset_service.SearchAllResourcesRequest(), + scope="scope_value", + query="query_value", + asset_types=["asset_types_value"], + ) + + +def test_search_all_resources_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.SearchAllResourcesResponse( + results=[ + assets.StandardResourceMetadata(), + assets.StandardResourceMetadata(), + assets.StandardResourceMetadata(), + ], + next_page_token="abc", + ), + asset_service.SearchAllResourcesResponse( + results=[], + next_page_token="def", + ), + asset_service.SearchAllResourcesResponse( + results=[ + assets.StandardResourceMetadata(), + ], + next_page_token="ghi", + ), + asset_service.SearchAllResourcesResponse( + results=[ + assets.StandardResourceMetadata(), + assets.StandardResourceMetadata(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.SearchAllResourcesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.search_all_resources(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, assets.StandardResourceMetadata) for i in results) + + pages = list(client.search_all_resources(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.SearchAllIamPoliciesRequest, + dict, + ], +) +def test_search_all_iam_policies_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllIamPoliciesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllIamPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.search_all_iam_policies(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.SearchAllIamPoliciesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_search_all_iam_policies_rest_required_fields( + request_type=asset_service.SearchAllIamPoliciesRequest, +): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["scope"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_iam_policies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["scope"] = "scope_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_all_iam_policies._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + "query", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "scope" in jsonified_request + assert jsonified_request["scope"] == "scope_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllIamPoliciesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.SearchAllIamPoliciesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.search_all_iam_policies(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_search_all_iam_policies_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.search_all_iam_policies._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + "query", + ) + ) + & set(("scope",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_search_all_iam_policies_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_search_all_iam_policies" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_search_all_iam_policies" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.SearchAllIamPoliciesRequest.pb( + asset_service.SearchAllIamPoliciesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.SearchAllIamPoliciesResponse.to_json( + asset_service.SearchAllIamPoliciesResponse() + ) + + request = asset_service.SearchAllIamPoliciesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.SearchAllIamPoliciesResponse() + + client.search_all_iam_policies( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_search_all_iam_policies_rest_bad_request( + transport: str = "rest", request_type=asset_service.SearchAllIamPoliciesRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"scope": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.search_all_iam_policies(request) + + +def test_search_all_iam_policies_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.SearchAllIamPoliciesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"scope": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + scope="scope_value", + query="query_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.SearchAllIamPoliciesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.search_all_iam_policies(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p1beta1/{scope=*/*}/iamPolicies:searchAll" % client.transport._host, + args[1], + ) + + +def test_search_all_iam_policies_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.search_all_iam_policies( + asset_service.SearchAllIamPoliciesRequest(), + scope="scope_value", + query="query_value", + ) + + +def test_search_all_iam_policies_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + asset_service.SearchAllIamPoliciesResponse( + results=[ + assets.IamPolicySearchResult(), + assets.IamPolicySearchResult(), + assets.IamPolicySearchResult(), + ], + next_page_token="abc", + ), + asset_service.SearchAllIamPoliciesResponse( + results=[], + next_page_token="def", + ), + asset_service.SearchAllIamPoliciesResponse( + results=[ + assets.IamPolicySearchResult(), + ], + next_page_token="ghi", + ), + asset_service.SearchAllIamPoliciesResponse( + results=[ + assets.IamPolicySearchResult(), + assets.IamPolicySearchResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + asset_service.SearchAllIamPoliciesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"scope": "sample1/sample2"} + + pager = client.search_all_iam_policies(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, assets.IamPolicySearchResult) for i in results) + + pages = list(client.search_all_iam_policies(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AssetServiceGrpcTransport( @@ -1665,6 +2384,7 @@ def test_transport_get_channel(): [ transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, ], ) def test_transport_adc(transport_class): @@ -1679,6 +2399,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1809,6 +2530,7 @@ def test_asset_service_transport_auth_adc(transport_class): [ transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, ], ) def test_asset_service_transport_auth_gdch_credentials(transport_class): @@ -1903,11 +2625,23 @@ def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_clas ) +def test_asset_service_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AssetServiceRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_no_port(transport_name): @@ -1918,7 +2652,11 @@ def test_asset_service_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -1926,6 +2664,7 @@ def test_asset_service_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_with_port(transport_name): @@ -1936,7 +2675,36 @@ def test_asset_service_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:8000") + assert client.transport._host == ( + "cloudasset.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_asset_service_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AssetServiceClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AssetServiceClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.search_all_resources._session + session2 = client2.transport.search_all_resources._session + assert session1 != session2 + session1 = client1.transport.search_all_iam_policies._session + session2 = client2.transport.search_all_iam_policies._session + assert session1 != session2 def test_asset_service_grpc_transport_channel(): @@ -2199,6 +2967,7 @@ async def test_transport_close_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2216,6 +2985,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py index 9d48c2b7..c30bb75a 100644 --- a/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py @@ -24,10 +24,17 @@ import grpc from grpc.experimental import aio +from collections.abc import Iterable +from google.protobuf import json_format +import json import math import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule from proto.marshal.rules import wrappers +from requests import Response +from requests import Request, PreparedRequest +from requests.sessions import Session +from google.protobuf import json_format from google.api_core import client_options from google.api_core import exceptions as core_exceptions @@ -92,6 +99,7 @@ def test__get_default_mtls_endpoint(): [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_info(client_class, transport_name): @@ -105,7 +113,11 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -113,6 +125,7 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ [ (transports.AssetServiceGrpcTransport, "grpc"), (transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_service_account_always_use_jwt( @@ -138,6 +151,7 @@ def test_asset_service_client_service_account_always_use_jwt( [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_file(client_class, transport_name): @@ -158,13 +172,18 @@ def test_asset_service_client_from_service_account_file(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() available_transports = [ transports.AssetServiceGrpcTransport, + transports.AssetServiceRestTransport, ] assert transport in available_transports @@ -181,6 +200,7 @@ def test_asset_service_client_get_transport_class(): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) @mock.patch.object( @@ -324,6 +344,8 @@ def test_asset_service_client_client_options( "grpc_asyncio", "false", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "true"), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -517,6 +539,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_client_options_scopes( @@ -557,6 +580,7 @@ def test_asset_service_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", None), ], ) def test_asset_service_client_client_options_credentials_file( @@ -1833,210 +1857,1540 @@ async def test_delete_feed_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.AssetServiceGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + asset_service.CreateFeedRequest, + dict, + ], +) +def test_create_feed_rest(request_type): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = AssetServiceClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed( + name="name_value", + asset_names=["asset_names_value"], + asset_types=["asset_types_value"], + content_type=asset_service.ContentType.RESOURCE, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.AssetServiceGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_feed(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.Feed) + assert response.name == "name_value" + assert response.asset_names == ["asset_names_value"] + assert response.asset_types == ["asset_types_value"] + assert response.content_type == asset_service.ContentType.RESOURCE + + +def test_create_feed_rest_required_fields(request_type=asset_service.CreateFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["feed_id"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.AssetServiceGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["feedId"] = "feed_id_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "feedId" in jsonified_request + assert jsonified_request["feedId"] == "feed_id_value" + + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options=options, - transport=transport, + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_feed._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "feedId", + "feed", + ) ) + ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) - # It is an error to provide scopes and a transport instance. - transport = transports.AssetServiceGrpcTransport( +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), ) - with pytest.raises(ValueError): - client = AssetServiceClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_create_feed" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_create_feed" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.CreateFeedRequest.pb( + asset_service.CreateFeedRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.Feed.to_json(asset_service.Feed()) + + request = asset_service.CreateFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.Feed() + + client.create_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) + pre.assert_called_once() + post.assert_called_once() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.AssetServiceGrpcTransport( + +def test_create_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.CreateFeedRequest +): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = AssetServiceClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.AssetServiceGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_feed(request) + + +def test_create_feed_rest_flattened(): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.AssetServiceGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p2beta1/{parent=*/*}/feeds" % client.transport._host, args[1] + ) + + +def test_create_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_feed( + asset_service.CreateFeedRequest(), + parent="parent_value", + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AssetServiceGrpcTransport, - transports.AssetServiceGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + +def test_create_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + asset_service.GetFeedRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = AssetServiceClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_feed_rest(request_type): client = AssetServiceClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.AssetServiceGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) -def test_asset_service_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.AssetServiceTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed( + name="name_value", + asset_names=["asset_names_value"], + asset_types=["asset_types_value"], + content_type=asset_service.ContentType.RESOURCE, ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_asset_service_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.asset_v1p2beta1.services.asset_service.transports.AssetServiceTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.AssetServiceTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_feed(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.Feed) + assert response.name == "name_value" + assert response.asset_names == ["asset_names_value"] + assert response.asset_types == ["asset_types_value"] + assert response.content_type == asset_service.ContentType.RESOURCE + + +def test_get_feed_rest_required_fields(request_type=asset_service.GetFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_feed", - "get_feed", - "list_feeds", - "update_feed", - "delete_feed", + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + request = request_type(**request_init) - with pytest.raises(NotImplementedError): - transport.close() + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_asset_service_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.asset_v1p2beta1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AssetServiceTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=("https://www.googleapis.com/auth/cloud-platform",), - quota_project_id="octopus", - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_feed(request) -def test_asset_service_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.asset_v1p2beta1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AssetServiceTransport() - adc.assert_called_once() + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params -def test_asset_service_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - AssetServiceClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=("https://www.googleapis.com/auth/cloud-platform",), - quota_project_id=None, - ) +def test_get_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + unset_fields = transport.get_feed._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -@pytest.mark.parametrize( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_get_feed" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_get_feed" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.GetFeedRequest.pb(asset_service.GetFeedRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.Feed.to_json(asset_service.Feed()) + + request = asset_service.GetFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.Feed() + + client.get_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.GetFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_feed(request) + + +def test_get_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "sample1/sample2/feeds/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p2beta1/{name=*/*/feeds/*}" % client.transport._host, args[1] + ) + + +def test_get_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_feed( + asset_service.GetFeedRequest(), + name="name_value", + ) + + +def test_get_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.ListFeedsRequest, + dict, + ], +) +def test_list_feeds_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListFeedsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListFeedsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_feeds(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.ListFeedsResponse) + + +def test_list_feeds_rest_required_fields(request_type=asset_service.ListFeedsRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_feeds._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_feeds._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.ListFeedsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.ListFeedsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_feeds(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_feeds_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_feeds._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_feeds_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_list_feeds" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_list_feeds" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.ListFeedsRequest.pb(asset_service.ListFeedsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.ListFeedsResponse.to_json( + asset_service.ListFeedsResponse() + ) + + request = asset_service.ListFeedsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.ListFeedsResponse() + + client.list_feeds( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_feeds_rest_bad_request( + transport: str = "rest", request_type=asset_service.ListFeedsRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_feeds(request) + + +def test_list_feeds_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListFeedsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListFeedsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_feeds(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p2beta1/{parent=*/*}/feeds" % client.transport._host, args[1] + ) + + +def test_list_feeds_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_feeds( + asset_service.ListFeedsRequest(), + parent="parent_value", + ) + + +def test_list_feeds_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.UpdateFeedRequest, + dict, + ], +) +def test_update_feed_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"feed": {"name": "sample1/sample2/feeds/sample3"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed( + name="name_value", + asset_names=["asset_names_value"], + asset_types=["asset_types_value"], + content_type=asset_service.ContentType.RESOURCE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_feed(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, asset_service.Feed) + assert response.name == "name_value" + assert response.asset_names == ["asset_names_value"] + assert response.asset_types == ["asset_types_value"] + assert response.content_type == asset_service.ContentType.RESOURCE + + +def test_update_feed_rest_required_fields(request_type=asset_service.UpdateFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_feed._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "feed", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_update_feed" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_update_feed" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.UpdateFeedRequest.pb( + asset_service.UpdateFeedRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.Feed.to_json(asset_service.Feed()) + + request = asset_service.UpdateFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.Feed() + + client.update_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.UpdateFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"feed": {"name": "sample1/sample2/feeds/sample3"}} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_feed(request) + + +def test_update_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.Feed() + + # get arguments that satisfy an http rule for this method + sample_request = {"feed": {"name": "sample1/sample2/feeds/sample3"}} + + # get truthy value for each flattened field + mock_args = dict( + feed=asset_service.Feed(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.Feed.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p2beta1/{feed.name=*/*/feeds/*}" % client.transport._host, args[1] + ) + + +def test_update_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_feed( + asset_service.UpdateFeedRequest(), + feed=asset_service.Feed(name="name_value"), + ) + + +def test_update_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + asset_service.DeleteFeedRequest, + dict, + ], +) +def test_delete_feed_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_feed(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_feed_rest_required_fields(request_type=asset_service.DeleteFeedRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_feed._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_feed(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_feed_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_feed._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_feed_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_delete_feed" + ) as pre: + pre.assert_not_called() + pb_message = asset_service.DeleteFeedRequest.pb( + asset_service.DeleteFeedRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = asset_service.DeleteFeedRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_feed( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_feed_rest_bad_request( + transport: str = "rest", request_type=asset_service.DeleteFeedRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "sample1/sample2/feeds/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_feed(request) + + +def test_delete_feed_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "sample1/sample2/feeds/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_feed(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p2beta1/{name=*/*/feeds/*}" % client.transport._host, args[1] + ) + + +def test_delete_feed_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_feed( + asset_service.DeleteFeedRequest(), + name="name_value", + ) + + +def test_delete_feed_rest_error(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AssetServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AssetServiceClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AssetServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AssetServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = AssetServiceClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AssetServiceGrpcTransport, + ) + + +def test_asset_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AssetServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_asset_service_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.asset_v1p2beta1.services.asset_service.transports.AssetServiceTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.AssetServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_feed", + "get_feed", + "list_feeds", + "update_feed", + "delete_feed", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_asset_service_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.asset_v1p2beta1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AssetServiceTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +def test_asset_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.asset_v1p2beta1.services.asset_service.transports.AssetServiceTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AssetServiceTransport() + adc.assert_called_once() + + +def test_asset_service_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + AssetServiceClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( "transport_class", [ transports.AssetServiceGrpcTransport, @@ -2061,6 +3415,7 @@ def test_asset_service_transport_auth_adc(transport_class): [ transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, ], ) def test_asset_service_transport_auth_gdch_credentials(transport_class): @@ -2155,11 +3510,23 @@ def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_clas ) +def test_asset_service_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AssetServiceRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_no_port(transport_name): @@ -2170,7 +3537,11 @@ def test_asset_service_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -2178,6 +3549,7 @@ def test_asset_service_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_with_port(transport_name): @@ -2188,7 +3560,45 @@ def test_asset_service_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:8000") + assert client.transport._host == ( + "cloudasset.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_asset_service_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AssetServiceClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AssetServiceClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_feed._session + session2 = client2.transport.create_feed._session + assert session1 != session2 + session1 = client1.transport.get_feed._session + session2 = client2.transport.get_feed._session + assert session1 != session2 + session1 = client1.transport.list_feeds._session + session2 = client2.transport.list_feeds._session + assert session1 != session2 + session1 = client1.transport.update_feed._session + session2 = client2.transport.update_feed._session + assert session1 != session2 + session1 = client1.transport.delete_feed._session + session2 = client2.transport.delete_feed._session + assert session1 != session2 def test_asset_service_grpc_transport_channel(): @@ -2474,6 +3884,7 @@ async def test_transport_close_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2491,6 +3902,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py index 2100a35f..ff1cdc7f 100644 --- a/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py @@ -24,10 +24,17 @@ import grpc from grpc.experimental import aio +from collections.abc import Iterable +from google.protobuf import json_format +import json import math import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule from proto.marshal.rules import wrappers +from requests import Response +from requests import Request, PreparedRequest +from requests.sessions import Session +from google.protobuf import json_format from google.api_core import client_options from google.api_core import exceptions as core_exceptions @@ -43,6 +50,7 @@ from google.cloud.asset_v1p5beta1.services.asset_service import transports from google.cloud.asset_v1p5beta1.types import asset_service from google.cloud.asset_v1p5beta1.types import assets +from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import timestamp_pb2 # type: ignore import google.auth @@ -94,6 +102,7 @@ def test__get_default_mtls_endpoint(): [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_info(client_class, transport_name): @@ -107,7 +116,11 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -115,6 +128,7 @@ def test_asset_service_client_from_service_account_info(client_class, transport_ [ (transports.AssetServiceGrpcTransport, "grpc"), (transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_service_account_always_use_jwt( @@ -140,6 +154,7 @@ def test_asset_service_client_service_account_always_use_jwt( [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), + (AssetServiceClient, "rest"), ], ) def test_asset_service_client_from_service_account_file(client_class, transport_name): @@ -160,13 +175,18 @@ def test_asset_service_client_from_service_account_file(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() available_transports = [ transports.AssetServiceGrpcTransport, + transports.AssetServiceRestTransport, ] assert transport in available_transports @@ -183,6 +203,7 @@ def test_asset_service_client_get_transport_class(): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) @mock.patch.object( @@ -326,6 +347,8 @@ def test_asset_service_client_client_options( "grpc_asyncio", "false", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "true"), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -519,6 +542,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): transports.AssetServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest"), ], ) def test_asset_service_client_client_options_scopes( @@ -559,6 +583,7 @@ def test_asset_service_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AssetServiceClient, transports.AssetServiceRestTransport, "rest", None), ], ) def test_asset_service_client_client_options_credentials_file( @@ -1089,6 +1114,346 @@ async def test_list_assets_async_pages(): assert page_.raw_page.next_page_token == token +@pytest.mark.parametrize( + "request_type", + [ + asset_service.ListAssetsRequest, + dict, + ], +) +def test_list_assets_rest(request_type): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListAssetsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_assets(request) + + # 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_rest_required_fields(request_type=asset_service.ListAssetsRequest): + transport_class = transports.AssetServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_assets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_assets._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "asset_types", + "content_type", + "page_size", + "page_token", + "read_time", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = asset_service.ListAssetsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = asset_service.ListAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_assets(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_assets_rest_unset_required_fields(): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_assets._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "assetTypes", + "contentType", + "pageSize", + "pageToken", + "readTime", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_assets_rest_interceptors(null_interceptor): + transport = transports.AssetServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AssetServiceRestInterceptor(), + ) + client = AssetServiceClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AssetServiceRestInterceptor, "post_list_assets" + ) as post, mock.patch.object( + transports.AssetServiceRestInterceptor, "pre_list_assets" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = asset_service.ListAssetsRequest.pb( + asset_service.ListAssetsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = asset_service.ListAssetsResponse.to_json( + asset_service.ListAssetsResponse() + ) + + request = asset_service.ListAssetsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = asset_service.ListAssetsResponse() + + client.list_assets( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_assets_rest_bad_request( + transport: str = "rest", request_type=asset_service.ListAssetsRequest +): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "sample1/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_assets(request) + + +def test_list_assets_rest_flattened(): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = asset_service.ListAssetsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "sample1/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = asset_service.ListAssetsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_assets(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1p5beta1/{parent=*/*}/assets" % client.transport._host, args[1] + ) + + +def test_list_assets_rest_flattened_error(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # 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", + ) + + +def test_list_assets_rest_pager(transport: str = "rest"): + client = AssetServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + 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(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(asset_service.ListAssetsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "sample1/sample2"} + + pager = client.list_assets(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, assets.Asset) for i in results) + + pages = list(client.list_assets(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AssetServiceGrpcTransport( @@ -1170,6 +1535,7 @@ def test_transport_get_channel(): [ transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, ], ) def test_transport_adc(transport_class): @@ -1184,6 +1550,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1311,6 +1678,7 @@ def test_asset_service_transport_auth_adc(transport_class): [ transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport, + transports.AssetServiceRestTransport, ], ) def test_asset_service_transport_auth_gdch_credentials(transport_class): @@ -1405,11 +1773,23 @@ def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_clas ) +def test_asset_service_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AssetServiceRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_no_port(transport_name): @@ -1420,7 +1800,11 @@ def test_asset_service_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:443") + assert client.transport._host == ( + "cloudasset.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com" + ) @pytest.mark.parametrize( @@ -1428,6 +1812,7 @@ def test_asset_service_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_asset_service_host_with_port(transport_name): @@ -1438,7 +1823,33 @@ def test_asset_service_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("cloudasset.googleapis.com:8000") + assert client.transport._host == ( + "cloudasset.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://cloudasset.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_asset_service_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AssetServiceClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AssetServiceClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_assets._session + session2 = client2.transport.list_assets._session + assert session1 != session2 def test_asset_service_grpc_transport_channel(): @@ -1775,6 +2186,7 @@ async def test_transport_close_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -1792,6 +2204,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: From 92ddde9ad982f0ee39974cd752a22d0a5aeeb129 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 16:19:24 -0800 Subject: [PATCH 9/9] chore(main): release 3.18.0 (#550) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ google/cloud/asset/gapic_version.py | 2 +- google/cloud/asset_v1/gapic_version.py | 2 +- google/cloud/asset_v1p1beta1/gapic_version.py | 2 +- google/cloud/asset_v1p2beta1/gapic_version.py | 2 +- google/cloud/asset_v1p4beta1/gapic_version.py | 2 +- google/cloud/asset_v1p5beta1/gapic_version.py | 2 +- .../snippet_metadata_google.cloud.asset.v1.json | 2 +- .../snippet_metadata_google.cloud.asset.v1p1beta1.json | 2 +- .../snippet_metadata_google.cloud.asset.v1p2beta1.json | 2 +- .../snippet_metadata_google.cloud.asset.v1p5beta1.json | 2 +- 12 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a3d1f01f..da0b97f9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.17.1" + ".": "3.18.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 897f0ab7..2645634e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-asset/#history +## [3.18.0](https://github.com/googleapis/python-asset/compare/v3.17.1...v3.18.0) (2023-02-19) + + +### Features + +* Enable "rest" transport in Python for services supporting numeric enums ([#549](https://github.com/googleapis/python-asset/issues/549)) ([e6bd01b](https://github.com/googleapis/python-asset/commit/e6bd01b917e1a42157e8a0d8ea05de79462b02c7)) + ## [3.17.1](https://github.com/googleapis/python-asset/compare/v3.17.0...v3.17.1) (2023-01-20) diff --git a/google/cloud/asset/gapic_version.py b/google/cloud/asset/gapic_version.py index 404743e2..16b29293 100644 --- a/google/cloud/asset/gapic_version.py +++ b/google/cloud/asset/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.17.1" # {x-release-please-version} +__version__ = "3.18.0" # {x-release-please-version} diff --git a/google/cloud/asset_v1/gapic_version.py b/google/cloud/asset_v1/gapic_version.py index 404743e2..16b29293 100644 --- a/google/cloud/asset_v1/gapic_version.py +++ b/google/cloud/asset_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.17.1" # {x-release-please-version} +__version__ = "3.18.0" # {x-release-please-version} diff --git a/google/cloud/asset_v1p1beta1/gapic_version.py b/google/cloud/asset_v1p1beta1/gapic_version.py index 404743e2..16b29293 100644 --- a/google/cloud/asset_v1p1beta1/gapic_version.py +++ b/google/cloud/asset_v1p1beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.17.1" # {x-release-please-version} +__version__ = "3.18.0" # {x-release-please-version} diff --git a/google/cloud/asset_v1p2beta1/gapic_version.py b/google/cloud/asset_v1p2beta1/gapic_version.py index 404743e2..16b29293 100644 --- a/google/cloud/asset_v1p2beta1/gapic_version.py +++ b/google/cloud/asset_v1p2beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.17.1" # {x-release-please-version} +__version__ = "3.18.0" # {x-release-please-version} diff --git a/google/cloud/asset_v1p4beta1/gapic_version.py b/google/cloud/asset_v1p4beta1/gapic_version.py index 404743e2..16b29293 100644 --- a/google/cloud/asset_v1p4beta1/gapic_version.py +++ b/google/cloud/asset_v1p4beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.17.1" # {x-release-please-version} +__version__ = "3.18.0" # {x-release-please-version} diff --git a/google/cloud/asset_v1p5beta1/gapic_version.py b/google/cloud/asset_v1p5beta1/gapic_version.py index 404743e2..16b29293 100644 --- a/google/cloud/asset_v1p5beta1/gapic_version.py +++ b/google/cloud/asset_v1p5beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "3.17.1" # {x-release-please-version} +__version__ = "3.18.0" # {x-release-please-version} diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json index 5a90dfa8..84da7a0b 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.18.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json index dcbeb822..dcc203e4 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p1beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.18.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json index 38eaede8..631446c3 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p2beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.18.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json index 13ffc229..906d3338 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.asset.v1p5beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-asset", - "version": "0.1.0" + "version": "3.18.0" }, "snippets": [ {