diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index f0f3b24b..5fc5daa3 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:8555f0e37e6261408f792bfd6635102d2da5ad73f8f09bcb24f25e6afb5fac97 diff --git a/.kokoro/requirements.in b/.kokoro/requirements.in index cbd7e77f..882178ce 100644 --- a/.kokoro/requirements.in +++ b/.kokoro/requirements.in @@ -1,5 +1,5 @@ gcp-docuploader -gcp-releasetool +gcp-releasetool>=1.10.5 # required for compatibility with cryptography>=39.x importlib-metadata typing-extensions twine diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 05dc4672..fa99c129 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 @@ -159,9 +154,9 @@ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf # via -r requirements.in -gcp-releasetool==1.10.0 \ - --hash=sha256:72a38ca91b59c24f7e699e9227c90cbe4dd71b789383cb0164b088abae294c83 \ - --hash=sha256:8c7c99320208383d4bb2b808c6880eb7a81424afe7cdba3c8d84b25f4f0e097d +gcp-releasetool==1.10.5 \ + --hash=sha256:174b7b102d704b254f2a26a3eda2c684fd3543320ec239baf771542a2e58e109 \ + --hash=sha256:e29d29927fe2ca493105a82958c6873bb2b90d503acac56be2c229e74de0eec9 # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 18e9f06a..d0d087a3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.18.0" + ".": "1.19.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 10fc63df..36b1deb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [1.19.0](https://github.com/googleapis/python-dialogflow-cx/compare/v1.18.0...v1.19.0) (2023-02-28) + + +### Features + +* Added gcs.proto. added support for GcsDestination and TextToSpeechSettings ([acfd1a1](https://github.com/googleapis/python-dialogflow-cx/commit/acfd1a11aca9c9cba7fb351f1781fa73c1e1d985)) +* Added persist_parameter_changes field from query_params to MatchIntentRequest ([acfd1a1](https://github.com/googleapis/python-dialogflow-cx/commit/acfd1a11aca9c9cba7fb351f1781fa73c1e1d985)) +* Enable "rest" transport in Python for services supporting numeric enums ([acfd1a1](https://github.com/googleapis/python-dialogflow-cx/commit/acfd1a11aca9c9cba7fb351f1781fa73c1e1d985)) +* Remove [REQUIRED] for VersionConfig ([acfd1a1](https://github.com/googleapis/python-dialogflow-cx/commit/acfd1a11aca9c9cba7fb351f1781fa73c1e1d985)) + + +### Documentation + +* Add more meaningful comments ([acfd1a1](https://github.com/googleapis/python-dialogflow-cx/commit/acfd1a11aca9c9cba7fb351f1781fa73c1e1d985)) + ## [1.18.0](https://github.com/googleapis/python-dialogflow-cx/compare/v1.17.1...v1.18.0) (2023-01-30) diff --git a/dialogflow-cx-v3-py.tar.gz b/dialogflow-cx-v3-py.tar.gz index 7eef5dbd..843316ab 100644 Binary files a/dialogflow-cx-v3-py.tar.gz and b/dialogflow-cx-v3-py.tar.gz differ diff --git a/dialogflow-cx-v3beta1-py.tar.gz b/dialogflow-cx-v3beta1-py.tar.gz index a108ba04..1086ecd4 100644 Binary files a/dialogflow-cx-v3beta1-py.tar.gz and b/dialogflow-cx-v3beta1-py.tar.gz differ diff --git a/google/cloud/dialogflowcx/__init__.py b/google/cloud/dialogflowcx/__init__.py index 656c9978..54a45abc 100644 --- a/google/cloud/dialogflowcx/__init__.py +++ b/google/cloud/dialogflowcx/__init__.py @@ -102,6 +102,7 @@ from google.cloud.dialogflowcx_v3.types.audio_config import OutputAudioConfig from google.cloud.dialogflowcx_v3.types.audio_config import SpeechWordInfo from google.cloud.dialogflowcx_v3.types.audio_config import SynthesizeSpeechConfig +from google.cloud.dialogflowcx_v3.types.audio_config import TextToSpeechSettings from google.cloud.dialogflowcx_v3.types.audio_config import VoiceSelectionParams from google.cloud.dialogflowcx_v3.types.audio_config import AudioEncoding from google.cloud.dialogflowcx_v3.types.audio_config import OutputAudioEncoding @@ -178,6 +179,7 @@ from google.cloud.dialogflowcx_v3.types.flow import UpdateFlowRequest from google.cloud.dialogflowcx_v3.types.flow import ValidateFlowRequest from google.cloud.dialogflowcx_v3.types.fulfillment import Fulfillment +from google.cloud.dialogflowcx_v3.types.gcs import GcsDestination from google.cloud.dialogflowcx_v3.types.intent import CreateIntentRequest from google.cloud.dialogflowcx_v3.types.intent import DeleteIntentRequest from google.cloud.dialogflowcx_v3.types.intent import GetIntentRequest @@ -386,6 +388,7 @@ "OutputAudioConfig", "SpeechWordInfo", "SynthesizeSpeechConfig", + "TextToSpeechSettings", "VoiceSelectionParams", "AudioEncoding", "OutputAudioEncoding", @@ -454,6 +457,7 @@ "UpdateFlowRequest", "ValidateFlowRequest", "Fulfillment", + "GcsDestination", "CreateIntentRequest", "DeleteIntentRequest", "GetIntentRequest", diff --git a/google/cloud/dialogflowcx/gapic_version.py b/google/cloud/dialogflowcx/gapic_version.py index 0028cb17..86f8ab82 100644 --- a/google/cloud/dialogflowcx/gapic_version.py +++ b/google/cloud/dialogflowcx/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "1.19.0" # {x-release-please-version} diff --git a/google/cloud/dialogflowcx_v3/__init__.py b/google/cloud/dialogflowcx_v3/__init__.py index a1f42c2f..ab1eb164 100644 --- a/google/cloud/dialogflowcx_v3/__init__.py +++ b/google/cloud/dialogflowcx_v3/__init__.py @@ -70,6 +70,7 @@ from .types.audio_config import OutputAudioConfig from .types.audio_config import SpeechWordInfo from .types.audio_config import SynthesizeSpeechConfig +from .types.audio_config import TextToSpeechSettings from .types.audio_config import VoiceSelectionParams from .types.audio_config import AudioEncoding from .types.audio_config import OutputAudioEncoding @@ -138,6 +139,7 @@ from .types.flow import UpdateFlowRequest from .types.flow import ValidateFlowRequest from .types.fulfillment import Fulfillment +from .types.gcs import GcsDestination from .types.intent import CreateIntentRequest from .types.intent import DeleteIntentRequest from .types.intent import GetIntentRequest @@ -347,6 +349,7 @@ "FulfillIntentRequest", "FulfillIntentResponse", "Fulfillment", + "GcsDestination", "GetAgentRequest", "GetAgentValidationResultRequest", "GetChangelogRequest", @@ -462,6 +465,7 @@ "TestResult", "TestRunDifference", "TextInput", + "TextToSpeechSettings", "TrainFlowRequest", "TransitionCoverage", "TransitionRoute", diff --git a/google/cloud/dialogflowcx_v3/gapic_metadata.json b/google/cloud/dialogflowcx_v3/gapic_metadata.json index 7053ca4a..e89078c3 100644 --- a/google/cloud/dialogflowcx_v3/gapic_metadata.json +++ b/google/cloud/dialogflowcx_v3/gapic_metadata.json @@ -106,6 +106,56 @@ ] } } + }, + "rest": { + "libraryClient": "AgentsClient", + "rpcs": { + "CreateAgent": { + "methods": [ + "create_agent" + ] + }, + "DeleteAgent": { + "methods": [ + "delete_agent" + ] + }, + "ExportAgent": { + "methods": [ + "export_agent" + ] + }, + "GetAgent": { + "methods": [ + "get_agent" + ] + }, + "GetAgentValidationResult": { + "methods": [ + "get_agent_validation_result" + ] + }, + "ListAgents": { + "methods": [ + "list_agents" + ] + }, + "RestoreAgent": { + "methods": [ + "restore_agent" + ] + }, + "UpdateAgent": { + "methods": [ + "update_agent" + ] + }, + "ValidateAgent": { + "methods": [ + "validate_agent" + ] + } + } } } }, @@ -140,6 +190,21 @@ ] } } + }, + "rest": { + "libraryClient": "ChangelogsClient", + "rpcs": { + "GetChangelog": { + "methods": [ + "get_changelog" + ] + }, + "ListChangelogs": { + "methods": [ + "list_changelogs" + ] + } + } } } }, @@ -174,6 +239,21 @@ ] } } + }, + "rest": { + "libraryClient": "DeploymentsClient", + "rpcs": { + "GetDeployment": { + "methods": [ + "get_deployment" + ] + }, + "ListDeployments": { + "methods": [ + "list_deployments" + ] + } + } } } }, @@ -238,6 +318,36 @@ ] } } + }, + "rest": { + "libraryClient": "EntityTypesClient", + "rpcs": { + "CreateEntityType": { + "methods": [ + "create_entity_type" + ] + }, + "DeleteEntityType": { + "methods": [ + "delete_entity_type" + ] + }, + "GetEntityType": { + "methods": [ + "get_entity_type" + ] + }, + "ListEntityTypes": { + "methods": [ + "list_entity_types" + ] + }, + "UpdateEntityType": { + "methods": [ + "update_entity_type" + ] + } + } } } }, @@ -342,6 +452,56 @@ ] } } + }, + "rest": { + "libraryClient": "EnvironmentsClient", + "rpcs": { + "CreateEnvironment": { + "methods": [ + "create_environment" + ] + }, + "DeleteEnvironment": { + "methods": [ + "delete_environment" + ] + }, + "DeployFlow": { + "methods": [ + "deploy_flow" + ] + }, + "GetEnvironment": { + "methods": [ + "get_environment" + ] + }, + "ListContinuousTestResults": { + "methods": [ + "list_continuous_test_results" + ] + }, + "ListEnvironments": { + "methods": [ + "list_environments" + ] + }, + "LookupEnvironmentHistory": { + "methods": [ + "lookup_environment_history" + ] + }, + "RunContinuousTest": { + "methods": [ + "run_continuous_test" + ] + }, + "UpdateEnvironment": { + "methods": [ + "update_environment" + ] + } + } } } }, @@ -426,6 +586,46 @@ ] } } + }, + "rest": { + "libraryClient": "ExperimentsClient", + "rpcs": { + "CreateExperiment": { + "methods": [ + "create_experiment" + ] + }, + "DeleteExperiment": { + "methods": [ + "delete_experiment" + ] + }, + "GetExperiment": { + "methods": [ + "get_experiment" + ] + }, + "ListExperiments": { + "methods": [ + "list_experiments" + ] + }, + "StartExperiment": { + "methods": [ + "start_experiment" + ] + }, + "StopExperiment": { + "methods": [ + "stop_experiment" + ] + }, + "UpdateExperiment": { + "methods": [ + "update_experiment" + ] + } + } } } }, @@ -540,6 +740,61 @@ ] } } + }, + "rest": { + "libraryClient": "FlowsClient", + "rpcs": { + "CreateFlow": { + "methods": [ + "create_flow" + ] + }, + "DeleteFlow": { + "methods": [ + "delete_flow" + ] + }, + "ExportFlow": { + "methods": [ + "export_flow" + ] + }, + "GetFlow": { + "methods": [ + "get_flow" + ] + }, + "GetFlowValidationResult": { + "methods": [ + "get_flow_validation_result" + ] + }, + "ImportFlow": { + "methods": [ + "import_flow" + ] + }, + "ListFlows": { + "methods": [ + "list_flows" + ] + }, + "TrainFlow": { + "methods": [ + "train_flow" + ] + }, + "UpdateFlow": { + "methods": [ + "update_flow" + ] + }, + "ValidateFlow": { + "methods": [ + "validate_flow" + ] + } + } } } }, @@ -604,13 +859,73 @@ ] } } - } - } - }, - "Pages": { - "clients": { - "grpc": { - "libraryClient": "PagesClient", + }, + "rest": { + "libraryClient": "IntentsClient", + "rpcs": { + "CreateIntent": { + "methods": [ + "create_intent" + ] + }, + "DeleteIntent": { + "methods": [ + "delete_intent" + ] + }, + "GetIntent": { + "methods": [ + "get_intent" + ] + }, + "ListIntents": { + "methods": [ + "list_intents" + ] + }, + "UpdateIntent": { + "methods": [ + "update_intent" + ] + } + } + } + } + }, + "Pages": { + "clients": { + "grpc": { + "libraryClient": "PagesClient", + "rpcs": { + "CreatePage": { + "methods": [ + "create_page" + ] + }, + "DeletePage": { + "methods": [ + "delete_page" + ] + }, + "GetPage": { + "methods": [ + "get_page" + ] + }, + "ListPages": { + "methods": [ + "list_pages" + ] + }, + "UpdatePage": { + "methods": [ + "update_page" + ] + } + } + }, + "grpc-async": { + "libraryClient": "PagesAsyncClient", "rpcs": { "CreatePage": { "methods": [ @@ -639,8 +954,8 @@ } } }, - "grpc-async": { - "libraryClient": "PagesAsyncClient", + "rest": { + "libraryClient": "PagesClient", "rpcs": { "CreatePage": { "methods": [ @@ -732,6 +1047,36 @@ ] } } + }, + "rest": { + "libraryClient": "SecuritySettingsServiceClient", + "rpcs": { + "CreateSecuritySettings": { + "methods": [ + "create_security_settings" + ] + }, + "DeleteSecuritySettings": { + "methods": [ + "delete_security_settings" + ] + }, + "GetSecuritySettings": { + "methods": [ + "get_security_settings" + ] + }, + "ListSecuritySettings": { + "methods": [ + "list_security_settings" + ] + }, + "UpdateSecuritySettings": { + "methods": [ + "update_security_settings" + ] + } + } } } }, @@ -796,6 +1141,36 @@ ] } } + }, + "rest": { + "libraryClient": "SessionEntityTypesClient", + "rpcs": { + "CreateSessionEntityType": { + "methods": [ + "create_session_entity_type" + ] + }, + "DeleteSessionEntityType": { + "methods": [ + "delete_session_entity_type" + ] + }, + "GetSessionEntityType": { + "methods": [ + "get_session_entity_type" + ] + }, + "ListSessionEntityTypes": { + "methods": [ + "list_session_entity_types" + ] + }, + "UpdateSessionEntityType": { + "methods": [ + "update_session_entity_type" + ] + } + } } } }, @@ -850,6 +1225,31 @@ ] } } + }, + "rest": { + "libraryClient": "SessionsClient", + "rpcs": { + "DetectIntent": { + "methods": [ + "detect_intent" + ] + }, + "FulfillIntent": { + "methods": [ + "fulfill_intent" + ] + }, + "MatchIntent": { + "methods": [ + "match_intent" + ] + }, + "StreamingDetectIntent": { + "methods": [ + "streaming_detect_intent" + ] + } + } } } }, @@ -984,6 +1384,71 @@ ] } } + }, + "rest": { + "libraryClient": "TestCasesClient", + "rpcs": { + "BatchDeleteTestCases": { + "methods": [ + "batch_delete_test_cases" + ] + }, + "BatchRunTestCases": { + "methods": [ + "batch_run_test_cases" + ] + }, + "CalculateCoverage": { + "methods": [ + "calculate_coverage" + ] + }, + "CreateTestCase": { + "methods": [ + "create_test_case" + ] + }, + "ExportTestCases": { + "methods": [ + "export_test_cases" + ] + }, + "GetTestCase": { + "methods": [ + "get_test_case" + ] + }, + "GetTestCaseResult": { + "methods": [ + "get_test_case_result" + ] + }, + "ImportTestCases": { + "methods": [ + "import_test_cases" + ] + }, + "ListTestCaseResults": { + "methods": [ + "list_test_case_results" + ] + }, + "ListTestCases": { + "methods": [ + "list_test_cases" + ] + }, + "RunTestCase": { + "methods": [ + "run_test_case" + ] + }, + "UpdateTestCase": { + "methods": [ + "update_test_case" + ] + } + } } } }, @@ -1048,6 +1513,36 @@ ] } } + }, + "rest": { + "libraryClient": "TransitionRouteGroupsClient", + "rpcs": { + "CreateTransitionRouteGroup": { + "methods": [ + "create_transition_route_group" + ] + }, + "DeleteTransitionRouteGroup": { + "methods": [ + "delete_transition_route_group" + ] + }, + "GetTransitionRouteGroup": { + "methods": [ + "get_transition_route_group" + ] + }, + "ListTransitionRouteGroups": { + "methods": [ + "list_transition_route_groups" + ] + }, + "UpdateTransitionRouteGroup": { + "methods": [ + "update_transition_route_group" + ] + } + } } } }, @@ -1132,6 +1627,46 @@ ] } } + }, + "rest": { + "libraryClient": "VersionsClient", + "rpcs": { + "CompareVersions": { + "methods": [ + "compare_versions" + ] + }, + "CreateVersion": { + "methods": [ + "create_version" + ] + }, + "DeleteVersion": { + "methods": [ + "delete_version" + ] + }, + "GetVersion": { + "methods": [ + "get_version" + ] + }, + "ListVersions": { + "methods": [ + "list_versions" + ] + }, + "LoadVersion": { + "methods": [ + "load_version" + ] + }, + "UpdateVersion": { + "methods": [ + "update_version" + ] + } + } } } }, @@ -1196,6 +1731,36 @@ ] } } + }, + "rest": { + "libraryClient": "WebhooksClient", + "rpcs": { + "CreateWebhook": { + "methods": [ + "create_webhook" + ] + }, + "DeleteWebhook": { + "methods": [ + "delete_webhook" + ] + }, + "GetWebhook": { + "methods": [ + "get_webhook" + ] + }, + "ListWebhooks": { + "methods": [ + "list_webhooks" + ] + }, + "UpdateWebhook": { + "methods": [ + "update_webhook" + ] + } + } } } } diff --git a/google/cloud/dialogflowcx_v3/gapic_version.py b/google/cloud/dialogflowcx_v3/gapic_version.py index 0028cb17..86f8ab82 100644 --- a/google/cloud/dialogflowcx_v3/gapic_version.py +++ b/google/cloud/dialogflowcx_v3/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "1.19.0" # {x-release-please-version} diff --git a/google/cloud/dialogflowcx_v3/services/agents/async_client.py b/google/cloud/dialogflowcx_v3/services/agents/async_client.py index a19dde3d..9b9d606a 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/agents/async_client.py @@ -48,6 +48,7 @@ from google.cloud.dialogflowcx_v3.types import advanced_settings from google.cloud.dialogflowcx_v3.types import agent from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3.types import audio_config from google.cloud.dialogflowcx_v3.types import flow from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 diff --git a/google/cloud/dialogflowcx_v3/services/agents/client.py b/google/cloud/dialogflowcx_v3/services/agents/client.py index 9939e7d5..6c0dd7ad 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/client.py +++ b/google/cloud/dialogflowcx_v3/services/agents/client.py @@ -52,6 +52,7 @@ from google.cloud.dialogflowcx_v3.types import advanced_settings from google.cloud.dialogflowcx_v3.types import agent from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3.types import audio_config from google.cloud.dialogflowcx_v3.types import flow from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 @@ -61,6 +62,7 @@ from .transports.base import AgentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AgentsGrpcTransport from .transports.grpc_asyncio import AgentsGrpcAsyncIOTransport +from .transports.rest import AgentsRestTransport class AgentsClientMeta(type): @@ -74,6 +76,7 @@ class AgentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport + _transport_registry["rest"] = AgentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/agents/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/agents/transports/__init__.py index 703a3046..a94f62c7 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/agents/transports/__init__.py @@ -19,15 +19,20 @@ from .base import AgentsTransport from .grpc import AgentsGrpcTransport from .grpc_asyncio import AgentsGrpcAsyncIOTransport +from .rest import AgentsRestTransport +from .rest import AgentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport +_transport_registry["rest"] = AgentsRestTransport __all__ = ( "AgentsTransport", "AgentsGrpcTransport", "AgentsGrpcAsyncIOTransport", + "AgentsRestTransport", + "AgentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/agents/transports/rest.py b/google/cloud/dialogflowcx_v3/services/agents/transports/rest.py new file mode 100644 index 00000000..0bdb46c8 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/agents/transports/rest.py @@ -0,0 +1,1890 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import agent +from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import AgentsTransport, 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 AgentsRestInterceptor: + """Interceptor for Agents. + + 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 AgentsRestTransport. + + .. code-block:: python + class MyCustomAgentsInterceptor(AgentsRestInterceptor): + def pre_create_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_agent_validation_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_agent_validation_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_agents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_agents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_restore_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_restore_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_validate_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_validate_agent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AgentsRestTransport(interceptor=MyCustomAgentsInterceptor()) + client = AgentsClient(transport=transport) + + + """ + + def pre_create_agent( + self, + request: gcdc_agent.CreateAgentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_agent.CreateAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_create_agent(self, response: gcdc_agent.Agent) -> gcdc_agent.Agent: + """Post-rpc interceptor for create_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_delete_agent( + self, request: agent.DeleteAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.DeleteAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def pre_export_agent( + self, request: agent.ExportAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ExportAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_export_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_agent( + self, request: agent.GetAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.GetAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_agent(self, response: agent.Agent) -> agent.Agent: + """Post-rpc interceptor for get_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_agent_validation_result( + self, + request: agent.GetAgentValidationResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[agent.GetAgentValidationResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_agent_validation_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_agent_validation_result( + self, response: agent.AgentValidationResult + ) -> agent.AgentValidationResult: + """Post-rpc interceptor for get_agent_validation_result + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_agents( + self, request: agent.ListAgentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ListAgentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_agents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_agents( + self, response: agent.ListAgentsResponse + ) -> agent.ListAgentsResponse: + """Post-rpc interceptor for list_agents + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_restore_agent( + self, request: agent.RestoreAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.RestoreAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for restore_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_restore_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for restore_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_update_agent( + self, + request: gcdc_agent.UpdateAgentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_agent.UpdateAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_update_agent(self, response: gcdc_agent.Agent) -> gcdc_agent.Agent: + """Post-rpc interceptor for update_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_validate_agent( + self, request: agent.ValidateAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ValidateAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for validate_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_validate_agent( + self, response: agent.AgentValidationResult + ) -> agent.AgentValidationResult: + """Post-rpc interceptor for validate_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AgentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AgentsRestInterceptor + + +class AgentsRestTransport(AgentsTransport): + """REST backend transport for Agents. + + Service for managing [Agents][google.cloud.dialogflow.cx.v3.Agent]. + + 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 = "dialogflow.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[AgentsRestInterceptor] = 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 AgentsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/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="v3", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateAgent(AgentsRestStub): + def __hash__(self): + return hash("CreateAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_agent.CreateAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_agent.Agent: + r"""Call the create agent method over HTTP. + + Args: + request (~.gcdc_agent.CreateAgentRequest): + The request object. The request message for + [Agents.CreateAgent][google.cloud.dialogflow.cx.v3.Agents.CreateAgent]. + + 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: + ~.gcdc_agent.Agent: + Agents are best described as Natural Language + Understanding (NLU) modules that transform user requests + into actionable data. You can include agents in your + app, product, or service to determine user intent and + respond to the user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and + so on to manage the conversation flows.. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*}/agents", + "body": "agent", + }, + ] + request, metadata = self._interceptor.pre_create_agent(request, metadata) + pb_request = gcdc_agent.CreateAgentRequest.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 = gcdc_agent.Agent() + pb_resp = gcdc_agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_agent(resp) + return resp + + class _DeleteAgent(AgentsRestStub): + def __hash__(self): + return hash("DeleteAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.DeleteAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete agent method over HTTP. + + Args: + request (~.agent.DeleteAgentRequest): + The request object. The request message for + [Agents.DeleteAgent][google.cloud.dialogflow.cx.v3.Agents.DeleteAgent]. + + 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": "/v3/{name=projects/*/locations/*/agents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_agent(request, metadata) + pb_request = agent.DeleteAgentRequest.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 _ExportAgent(AgentsRestStub): + def __hash__(self): + return hash("ExportAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.ExportAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export agent method over HTTP. + + Args: + request (~.agent.ExportAgentRequest): + The request object. The request message for + [Agents.ExportAgent][google.cloud.dialogflow.cx.v3.Agents.ExportAgent]. + + 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": "/v3/{name=projects/*/locations/*/agents/*}:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_agent(request, metadata) + pb_request = agent.ExportAgentRequest.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_agent(resp) + return resp + + class _GetAgent(AgentsRestStub): + def __hash__(self): + return hash("GetAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.GetAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.Agent: + r"""Call the get agent method over HTTP. + + Args: + request (~.agent.GetAgentRequest): + The request object. The request message for + [Agents.GetAgent][google.cloud.dialogflow.cx.v3.Agents.GetAgent]. + + 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: + ~.agent.Agent: + Agents are best described as Natural Language + Understanding (NLU) modules that transform user requests + into actionable data. You can include agents in your + app, product, or service to determine user intent and + respond to the user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and + so on to manage the conversation flows.. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_agent(request, metadata) + pb_request = agent.GetAgentRequest.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 = agent.Agent() + pb_resp = agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_agent(resp) + return resp + + class _GetAgentValidationResult(AgentsRestStub): + def __hash__(self): + return hash("GetAgentValidationResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.GetAgentValidationResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Call the get agent validation + result method over HTTP. + + Args: + request (~.agent.GetAgentValidationResultRequest): + The request object. The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + 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: + ~.agent.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/validationResult}", + }, + ] + request, metadata = self._interceptor.pre_get_agent_validation_result( + request, metadata + ) + pb_request = agent.GetAgentValidationResultRequest.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 = agent.AgentValidationResult() + pb_resp = agent.AgentValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_agent_validation_result(resp) + return resp + + class _ListAgents(AgentsRestStub): + def __hash__(self): + return hash("ListAgents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.ListAgentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.ListAgentsResponse: + r"""Call the list agents method over HTTP. + + Args: + request (~.agent.ListAgentsRequest): + The request object. The request message for + [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. + + 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: + ~.agent.ListAgentsResponse: + The response message for + [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*}/agents", + }, + ] + request, metadata = self._interceptor.pre_list_agents(request, metadata) + pb_request = agent.ListAgentsRequest.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 = agent.ListAgentsResponse() + pb_resp = agent.ListAgentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_agents(resp) + return resp + + class _RestoreAgent(AgentsRestStub): + def __hash__(self): + return hash("RestoreAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.RestoreAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the restore agent method over HTTP. + + Args: + request (~.agent.RestoreAgentRequest): + The request object. The request message for + [Agents.RestoreAgent][google.cloud.dialogflow.cx.v3.Agents.RestoreAgent]. + + 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": "/v3/{name=projects/*/locations/*/agents/*}:restore", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_restore_agent(request, metadata) + pb_request = agent.RestoreAgentRequest.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_restore_agent(resp) + return resp + + class _UpdateAgent(AgentsRestStub): + def __hash__(self): + return hash("UpdateAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_agent.UpdateAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_agent.Agent: + r"""Call the update agent method over HTTP. + + Args: + request (~.gcdc_agent.UpdateAgentRequest): + The request object. The request message for + [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3.Agents.UpdateAgent]. + + 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: + ~.gcdc_agent.Agent: + Agents are best described as Natural Language + Understanding (NLU) modules that transform user requests + into actionable data. You can include agents in your + app, product, or service to determine user intent and + respond to the user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and + so on to manage the conversation flows.. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{agent.name=projects/*/locations/*/agents/*}", + "body": "agent", + }, + ] + request, metadata = self._interceptor.pre_update_agent(request, metadata) + pb_request = gcdc_agent.UpdateAgentRequest.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 = gcdc_agent.Agent() + pb_resp = gcdc_agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_agent(resp) + return resp + + class _ValidateAgent(AgentsRestStub): + def __hash__(self): + return hash("ValidateAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.ValidateAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Call the validate agent method over HTTP. + + Args: + request (~.agent.ValidateAgentRequest): + The request object. The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3.Agents.ValidateAgent]. + + 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: + ~.agent.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/agents/*}:validate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_validate_agent(request, metadata) + pb_request = agent.ValidateAgentRequest.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 = agent.AgentValidationResult() + pb_resp = agent.AgentValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_validate_agent(resp) + return resp + + @property + def create_agent( + self, + ) -> Callable[[gcdc_agent.CreateAgentRequest], gcdc_agent.Agent]: + # 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._CreateAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_agent(self) -> Callable[[agent.DeleteAgentRequest], 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._DeleteAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_agent( + self, + ) -> Callable[[agent.ExportAgentRequest], 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._ExportAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_agent(self) -> Callable[[agent.GetAgentRequest], agent.Agent]: + # 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._GetAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_agent_validation_result( + self, + ) -> Callable[[agent.GetAgentValidationResultRequest], agent.AgentValidationResult]: + # 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._GetAgentValidationResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_agents( + self, + ) -> Callable[[agent.ListAgentsRequest], agent.ListAgentsResponse]: + # 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._ListAgents(self._session, self._host, self._interceptor) # type: ignore + + @property + def restore_agent( + self, + ) -> Callable[[agent.RestoreAgentRequest], 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._RestoreAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_agent( + self, + ) -> Callable[[gcdc_agent.UpdateAgentRequest], gcdc_agent.Agent]: + # 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._UpdateAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def validate_agent( + self, + ) -> Callable[[agent.ValidateAgentRequest], agent.AgentValidationResult]: + # 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._ValidateAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(AgentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(AgentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(AgentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AgentsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(AgentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AgentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/changelogs/client.py b/google/cloud/dialogflowcx_v3/services/changelogs/client.py index d6ec83dc..e3809074 100644 --- a/google/cloud/dialogflowcx_v3/services/changelogs/client.py +++ b/google/cloud/dialogflowcx_v3/services/changelogs/client.py @@ -54,6 +54,7 @@ from .transports.base import ChangelogsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import ChangelogsGrpcTransport from .transports.grpc_asyncio import ChangelogsGrpcAsyncIOTransport +from .transports.rest import ChangelogsRestTransport class ChangelogsClientMeta(type): @@ -67,6 +68,7 @@ class ChangelogsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ChangelogsTransport]] _transport_registry["grpc"] = ChangelogsGrpcTransport _transport_registry["grpc_asyncio"] = ChangelogsGrpcAsyncIOTransport + _transport_registry["rest"] = ChangelogsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/changelogs/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/changelogs/transports/__init__.py index 34aa1f62..49d7fb49 100644 --- a/google/cloud/dialogflowcx_v3/services/changelogs/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/changelogs/transports/__init__.py @@ -19,15 +19,20 @@ from .base import ChangelogsTransport from .grpc import ChangelogsGrpcTransport from .grpc_asyncio import ChangelogsGrpcAsyncIOTransport +from .rest import ChangelogsRestTransport +from .rest import ChangelogsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ChangelogsTransport]] _transport_registry["grpc"] = ChangelogsGrpcTransport _transport_registry["grpc_asyncio"] = ChangelogsGrpcAsyncIOTransport +_transport_registry["rest"] = ChangelogsRestTransport __all__ = ( "ChangelogsTransport", "ChangelogsGrpcTransport", "ChangelogsGrpcAsyncIOTransport", + "ChangelogsRestTransport", + "ChangelogsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/changelogs/transports/rest.py b/google/cloud/dialogflowcx_v3/services/changelogs/transports/rest.py new file mode 100644 index 00000000..62006579 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/changelogs/transports/rest.py @@ -0,0 +1,895 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import changelog + +from .base import ChangelogsTransport, 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 ChangelogsRestInterceptor: + """Interceptor for Changelogs. + + 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 ChangelogsRestTransport. + + .. code-block:: python + class MyCustomChangelogsInterceptor(ChangelogsRestInterceptor): + def pre_get_changelog(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_changelog(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_changelogs(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_changelogs(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ChangelogsRestTransport(interceptor=MyCustomChangelogsInterceptor()) + client = ChangelogsClient(transport=transport) + + + """ + + def pre_get_changelog( + self, + request: changelog.GetChangelogRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[changelog.GetChangelogRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_changelog + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_get_changelog(self, response: changelog.Changelog) -> changelog.Changelog: + """Post-rpc interceptor for get_changelog + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_list_changelogs( + self, + request: changelog.ListChangelogsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[changelog.ListChangelogsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_changelogs + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_list_changelogs( + self, response: changelog.ListChangelogsResponse + ) -> changelog.ListChangelogsResponse: + """Post-rpc interceptor for list_changelogs + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Changelogs 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ChangelogsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ChangelogsRestInterceptor + + +class ChangelogsRestTransport(ChangelogsTransport): + """REST backend transport for Changelogs. + + Service for managing + [Changelogs][google.cloud.dialogflow.cx.v3.Changelog]. + + 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 = "dialogflow.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[ChangelogsRestInterceptor] = 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 ChangelogsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetChangelog(ChangelogsRestStub): + def __hash__(self): + return hash("GetChangelog") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: changelog.GetChangelogRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> changelog.Changelog: + r"""Call the get changelog method over HTTP. + + Args: + request (~.changelog.GetChangelogRequest): + The request object. The request message for + [Changelogs.GetChangelog][google.cloud.dialogflow.cx.v3.Changelogs.GetChangelog]. + + 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: + ~.changelog.Changelog: + Changelogs represents a change made + to a given agent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/changelogs/*}", + }, + ] + request, metadata = self._interceptor.pre_get_changelog(request, metadata) + pb_request = changelog.GetChangelogRequest.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 = changelog.Changelog() + pb_resp = changelog.Changelog.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_changelog(resp) + return resp + + class _ListChangelogs(ChangelogsRestStub): + def __hash__(self): + return hash("ListChangelogs") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: changelog.ListChangelogsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> changelog.ListChangelogsResponse: + r"""Call the list changelogs method over HTTP. + + Args: + request (~.changelog.ListChangelogsRequest): + The request object. The request message for + [Changelogs.ListChangelogs][google.cloud.dialogflow.cx.v3.Changelogs.ListChangelogs]. + + 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: + ~.changelog.ListChangelogsResponse: + The response message for + [Changelogs.ListChangelogs][google.cloud.dialogflow.cx.v3.Changelogs.ListChangelogs]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/changelogs", + }, + ] + request, metadata = self._interceptor.pre_list_changelogs(request, metadata) + pb_request = changelog.ListChangelogsRequest.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 = changelog.ListChangelogsResponse() + pb_resp = changelog.ListChangelogsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_changelogs(resp) + return resp + + @property + def get_changelog( + self, + ) -> Callable[[changelog.GetChangelogRequest], changelog.Changelog]: + # 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._GetChangelog(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_changelogs( + self, + ) -> Callable[[changelog.ListChangelogsRequest], changelog.ListChangelogsResponse]: + # 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._ListChangelogs(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ChangelogsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ChangelogsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ChangelogsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ChangelogsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ChangelogsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ChangelogsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/deployments/client.py b/google/cloud/dialogflowcx_v3/services/deployments/client.py index c2d4e9aa..2d9f78ad 100644 --- a/google/cloud/dialogflowcx_v3/services/deployments/client.py +++ b/google/cloud/dialogflowcx_v3/services/deployments/client.py @@ -54,6 +54,7 @@ from .transports.base import DeploymentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import DeploymentsGrpcTransport from .transports.grpc_asyncio import DeploymentsGrpcAsyncIOTransport +from .transports.rest import DeploymentsRestTransport class DeploymentsClientMeta(type): @@ -67,6 +68,7 @@ class DeploymentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[DeploymentsTransport]] _transport_registry["grpc"] = DeploymentsGrpcTransport _transport_registry["grpc_asyncio"] = DeploymentsGrpcAsyncIOTransport + _transport_registry["rest"] = DeploymentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/deployments/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/deployments/transports/__init__.py index f902c685..c128af3e 100644 --- a/google/cloud/dialogflowcx_v3/services/deployments/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/deployments/transports/__init__.py @@ -19,15 +19,20 @@ from .base import DeploymentsTransport from .grpc import DeploymentsGrpcTransport from .grpc_asyncio import DeploymentsGrpcAsyncIOTransport +from .rest import DeploymentsRestTransport +from .rest import DeploymentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[DeploymentsTransport]] _transport_registry["grpc"] = DeploymentsGrpcTransport _transport_registry["grpc_asyncio"] = DeploymentsGrpcAsyncIOTransport +_transport_registry["rest"] = DeploymentsRestTransport __all__ = ( "DeploymentsTransport", "DeploymentsGrpcTransport", "DeploymentsGrpcAsyncIOTransport", + "DeploymentsRestTransport", + "DeploymentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/deployments/transports/rest.py b/google/cloud/dialogflowcx_v3/services/deployments/transports/rest.py new file mode 100644 index 00000000..05d5a8dd --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/deployments/transports/rest.py @@ -0,0 +1,906 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import deployment + +from .base import DeploymentsTransport, 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 DeploymentsRestInterceptor: + """Interceptor for Deployments. + + 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 DeploymentsRestTransport. + + .. code-block:: python + class MyCustomDeploymentsInterceptor(DeploymentsRestInterceptor): + def pre_get_deployment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_deployment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_deployments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_deployments(self, response): + logging.log(f"Received response: {response}") + return response + + transport = DeploymentsRestTransport(interceptor=MyCustomDeploymentsInterceptor()) + client = DeploymentsClient(transport=transport) + + + """ + + def pre_get_deployment( + self, + request: deployment.GetDeploymentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[deployment.GetDeploymentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_deployment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_get_deployment( + self, response: deployment.Deployment + ) -> deployment.Deployment: + """Post-rpc interceptor for get_deployment + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_list_deployments( + self, + request: deployment.ListDeploymentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[deployment.ListDeploymentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_deployments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_list_deployments( + self, response: deployment.ListDeploymentsResponse + ) -> deployment.ListDeploymentsResponse: + """Post-rpc interceptor for list_deployments + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Deployments 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class DeploymentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: DeploymentsRestInterceptor + + +class DeploymentsRestTransport(DeploymentsTransport): + """REST backend transport for Deployments. + + Service for managing + [Deployments][google.cloud.dialogflow.cx.v3.Deployment]. + + 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 = "dialogflow.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[DeploymentsRestInterceptor] = 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 DeploymentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetDeployment(DeploymentsRestStub): + def __hash__(self): + return hash("GetDeployment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: deployment.GetDeploymentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> deployment.Deployment: + r"""Call the get deployment method over HTTP. + + Args: + request (~.deployment.GetDeploymentRequest): + The request object. The request message for + [Deployments.GetDeployment][google.cloud.dialogflow.cx.v3.Deployments.GetDeployment]. + + 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: + ~.deployment.Deployment: + Represents an deployment in an + environment. A deployment happens when a + flow version configured to be active in + the environment. You can configure + running pre-deployment steps, e.g. + running validation test cases, + experiment auto-rollout, etc. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*/deployments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_deployment(request, metadata) + pb_request = deployment.GetDeploymentRequest.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 = deployment.Deployment() + pb_resp = deployment.Deployment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_deployment(resp) + return resp + + class _ListDeployments(DeploymentsRestStub): + def __hash__(self): + return hash("ListDeployments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: deployment.ListDeploymentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> deployment.ListDeploymentsResponse: + r"""Call the list deployments method over HTTP. + + Args: + request (~.deployment.ListDeploymentsRequest): + The request object. The request message for + [Deployments.ListDeployments][google.cloud.dialogflow.cx.v3.Deployments.ListDeployments]. + + 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: + ~.deployment.ListDeploymentsResponse: + The response message for + [Deployments.ListDeployments][google.cloud.dialogflow.cx.v3.Deployments.ListDeployments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/environments/*}/deployments", + }, + ] + request, metadata = self._interceptor.pre_list_deployments( + request, metadata + ) + pb_request = deployment.ListDeploymentsRequest.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 = deployment.ListDeploymentsResponse() + pb_resp = deployment.ListDeploymentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_deployments(resp) + return resp + + @property + def get_deployment( + self, + ) -> Callable[[deployment.GetDeploymentRequest], deployment.Deployment]: + # 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._GetDeployment(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_deployments( + self, + ) -> Callable[ + [deployment.ListDeploymentsRequest], deployment.ListDeploymentsResponse + ]: + # 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._ListDeployments(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(DeploymentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(DeploymentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(DeploymentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(DeploymentsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(DeploymentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("DeploymentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/client.py b/google/cloud/dialogflowcx_v3/services/entity_types/client.py index 432c1300..2939c9f4 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/client.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/client.py @@ -55,6 +55,7 @@ from .transports.base import EntityTypesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import EntityTypesGrpcTransport from .transports.grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .transports.rest import EntityTypesRestTransport class EntityTypesClientMeta(type): @@ -68,6 +69,7 @@ class EntityTypesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = EntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/entity_types/transports/__init__.py index 2a22d664..0220987e 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/transports/__init__.py @@ -19,15 +19,20 @@ from .base import EntityTypesTransport from .grpc import EntityTypesGrpcTransport from .grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .rest import EntityTypesRestTransport +from .rest import EntityTypesRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = EntityTypesRestTransport __all__ = ( "EntityTypesTransport", "EntityTypesGrpcTransport", "EntityTypesGrpcAsyncIOTransport", + "EntityTypesRestTransport", + "EntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/transports/rest.py b/google/cloud/dialogflowcx_v3/services/entity_types/transports/rest.py new file mode 100644 index 00000000..382553ab --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/entity_types/transports/rest.py @@ -0,0 +1,1388 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import entity_type +from google.cloud.dialogflowcx_v3.types import entity_type as gcdc_entity_type +from google.protobuf import empty_pb2 # type: ignore + +from .base import EntityTypesTransport, 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 EntityTypesRestInterceptor: + """Interceptor for EntityTypes. + + 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 EntityTypesRestTransport. + + .. code-block:: python + class MyCustomEntityTypesInterceptor(EntityTypesRestInterceptor): + def pre_create_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EntityTypesRestTransport(interceptor=MyCustomEntityTypesInterceptor()) + client = EntityTypesClient(transport=transport) + + + """ + + def pre_create_entity_type( + self, + request: gcdc_entity_type.CreateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_entity_type.CreateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_create_entity_type( + self, response: gcdc_entity_type.EntityType + ) -> gcdc_entity_type.EntityType: + """Post-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_entity_type( + self, + request: entity_type.DeleteEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.DeleteEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def pre_get_entity_type( + self, + request: entity_type.GetEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.GetEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_entity_type( + self, response: entity_type.EntityType + ) -> entity_type.EntityType: + """Post-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_entity_types( + self, + request: entity_type.ListEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.ListEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_entity_types( + self, response: entity_type.ListEntityTypesResponse + ) -> entity_type.ListEntityTypesResponse: + """Post-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_entity_type( + self, + request: gcdc_entity_type.UpdateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_entity_type.UpdateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_update_entity_type( + self, response: gcdc_entity_type.EntityType + ) -> gcdc_entity_type.EntityType: + """Post-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EntityTypesRestInterceptor + + +class EntityTypesRestTransport(EntityTypesTransport): + """REST backend transport for EntityTypes. + + Service for managing + [EntityTypes][google.cloud.dialogflow.cx.v3.EntityType]. + + 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 = "dialogflow.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[EntityTypesRestInterceptor] = 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 EntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("CreateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_entity_type.CreateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_entity_type.EntityType: + r"""Call the create entity type method over HTTP. + + Args: + request (~.gcdc_entity_type.CreateEntityTypeRequest): + The request object. The request message for + [EntityTypes.CreateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.CreateEntityType]. + + 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: + ~.gcdc_entity_type.EntityType: + Entities are extracted from user input and represent + parameters that are meaningful to your application. For + example, a date range, a proper name such as a + geographic location or landmark, and so on. Entities + represent actionable data for your application. + + When you define an entity, you can also include synonyms + that all map to that entity. For example, "soft drink", + "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the ``EntityType`` type. + + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to your + application. For example, you could define a + ``pizza.sauce`` entity for red or white pizza sauce, + a ``pizza.cheese`` entity for the different types of + cheese on a pizza, a ``pizza.topping`` entity for + different toppings, and so on. A custom entity is + represented by the ``EntityType`` type. + + - **User** - entities that are built for an individual + user such as favorites, preferences, playlists, and + so on. A user entity is represented by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/entityTypes", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_entity_type( + request, metadata + ) + pb_request = gcdc_entity_type.CreateEntityTypeRequest.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 = gcdc_entity_type.EntityType() + pb_resp = gcdc_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_entity_type(resp) + return resp + + class _DeleteEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("DeleteEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: entity_type.DeleteEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete entity type method over HTTP. + + Args: + request (~.entity_type.DeleteEntityTypeRequest): + The request object. The request message for + [EntityTypes.DeleteEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.DeleteEntityType]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_entity_type( + request, metadata + ) + pb_request = entity_type.DeleteEntityTypeRequest.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 _GetEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("GetEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: entity_type.GetEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.EntityType: + r"""Call the get entity type method over HTTP. + + Args: + request (~.entity_type.GetEntityTypeRequest): + The request object. The request message for + [EntityTypes.GetEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.GetEntityType]. + + 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: + ~.entity_type.EntityType: + Entities are extracted from user input and represent + parameters that are meaningful to your application. For + example, a date range, a proper name such as a + geographic location or landmark, and so on. Entities + represent actionable data for your application. + + When you define an entity, you can also include synonyms + that all map to that entity. For example, "soft drink", + "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the ``EntityType`` type. + + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to your + application. For example, you could define a + ``pizza.sauce`` entity for red or white pizza sauce, + a ``pizza.cheese`` entity for the different types of + cheese on a pizza, a ``pizza.topping`` entity for + different toppings, and so on. A custom entity is + represented by the ``EntityType`` type. + + - **User** - entities that are built for an individual + user such as favorites, preferences, playlists, and + so on. A user entity is represented by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_entity_type(request, metadata) + pb_request = entity_type.GetEntityTypeRequest.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 = entity_type.EntityType() + pb_resp = entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_entity_type(resp) + return resp + + class _ListEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("ListEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: entity_type.ListEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.ListEntityTypesResponse: + r"""Call the list entity types method over HTTP. + + Args: + request (~.entity_type.ListEntityTypesRequest): + The request object. The request message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. + + 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: + ~.entity_type.ListEntityTypesResponse: + The response message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_entity_types( + request, metadata + ) + pb_request = entity_type.ListEntityTypesRequest.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 = entity_type.ListEntityTypesResponse() + pb_resp = entity_type.ListEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_entity_types(resp) + return resp + + class _UpdateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("UpdateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_entity_type.UpdateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_entity_type.EntityType: + r"""Call the update entity type method over HTTP. + + Args: + request (~.gcdc_entity_type.UpdateEntityTypeRequest): + The request object. The request message for + [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.UpdateEntityType]. + + 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: + ~.gcdc_entity_type.EntityType: + Entities are extracted from user input and represent + parameters that are meaningful to your application. For + example, a date range, a proper name such as a + geographic location or landmark, and so on. Entities + represent actionable data for your application. + + When you define an entity, you can also include synonyms + that all map to that entity. For example, "soft drink", + "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the ``EntityType`` type. + + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to your + application. For example, you could define a + ``pizza.sauce`` entity for red or white pizza sauce, + a ``pizza.cheese`` entity for the different types of + cheese on a pizza, a ``pizza.topping`` entity for + different toppings, and so on. A custom entity is + represented by the ``EntityType`` type. + + - **User** - entities that are built for an individual + user such as favorites, preferences, playlists, and + so on. A user entity is represented by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{entity_type.name=projects/*/locations/*/agents/*/entityTypes/*}", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_entity_type( + request, metadata + ) + pb_request = gcdc_entity_type.UpdateEntityTypeRequest.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 = gcdc_entity_type.EntityType() + pb_resp = gcdc_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_entity_type(resp) + return resp + + @property + def create_entity_type( + self, + ) -> Callable[ + [gcdc_entity_type.CreateEntityTypeRequest], gcdc_entity_type.EntityType + ]: + # 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._CreateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_entity_type( + self, + ) -> Callable[[entity_type.DeleteEntityTypeRequest], 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._DeleteEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_entity_type( + self, + ) -> Callable[[entity_type.GetEntityTypeRequest], entity_type.EntityType]: + # 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._GetEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_entity_types( + self, + ) -> Callable[ + [entity_type.ListEntityTypesRequest], entity_type.ListEntityTypesResponse + ]: + # 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._ListEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_entity_type( + self, + ) -> Callable[ + [gcdc_entity_type.UpdateEntityTypeRequest], gcdc_entity_type.EntityType + ]: + # 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._UpdateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EntityTypesRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EntityTypesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/environments/async_client.py b/google/cloud/dialogflowcx_v3/services/environments/async_client.py index c48b284c..d507dbf2 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/environments/async_client.py @@ -517,7 +517,6 @@ async def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.CreateEnvironmentRequest( parent="parent_value", @@ -672,7 +671,6 @@ async def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.UpdateEnvironmentRequest( environment=environment, diff --git a/google/cloud/dialogflowcx_v3/services/environments/client.py b/google/cloud/dialogflowcx_v3/services/environments/client.py index 2970ac6c..ea174278 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/client.py +++ b/google/cloud/dialogflowcx_v3/services/environments/client.py @@ -59,6 +59,7 @@ from .transports.base import EnvironmentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import EnvironmentsGrpcTransport from .transports.grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .transports.rest import EnvironmentsRestTransport class EnvironmentsClientMeta(type): @@ -72,6 +73,7 @@ class EnvironmentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport + _transport_registry["rest"] = EnvironmentsRestTransport def get_transport_class( cls, @@ -880,7 +882,6 @@ def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.CreateEnvironmentRequest( parent="parent_value", @@ -1035,7 +1036,6 @@ def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.UpdateEnvironmentRequest( environment=environment, diff --git a/google/cloud/dialogflowcx_v3/services/environments/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/environments/transports/__init__.py index 0ecefb61..1f36326c 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/environments/transports/__init__.py @@ -19,15 +19,20 @@ from .base import EnvironmentsTransport from .grpc import EnvironmentsGrpcTransport from .grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .rest import EnvironmentsRestTransport +from .rest import EnvironmentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport +_transport_registry["rest"] = EnvironmentsRestTransport __all__ = ( "EnvironmentsTransport", "EnvironmentsGrpcTransport", "EnvironmentsGrpcAsyncIOTransport", + "EnvironmentsRestTransport", + "EnvironmentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/environments/transports/rest.py b/google/cloud/dialogflowcx_v3/services/environments/transports/rest.py new file mode 100644 index 00000000..30fdc92c --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/environments/transports/rest.py @@ -0,0 +1,1909 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import environment +from google.cloud.dialogflowcx_v3.types import environment as gcdc_environment +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import EnvironmentsTransport, 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 EnvironmentsRestInterceptor: + """Interceptor for Environments. + + 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 EnvironmentsRestTransport. + + .. code-block:: python + class MyCustomEnvironmentsInterceptor(EnvironmentsRestInterceptor): + def pre_create_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_deploy_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_deploy_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_continuous_test_results(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_continuous_test_results(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_environments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_environments(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_lookup_environment_history(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_lookup_environment_history(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_run_continuous_test(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_run_continuous_test(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_environment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EnvironmentsRestTransport(interceptor=MyCustomEnvironmentsInterceptor()) + client = EnvironmentsClient(transport=transport) + + + """ + + def pre_create_environment( + self, + request: gcdc_environment.CreateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_environment.CreateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_create_environment( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_delete_environment( + self, + request: environment.DeleteEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.DeleteEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def pre_deploy_flow( + self, + request: environment.DeployFlowRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.DeployFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for deploy_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_deploy_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for deploy_flow + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_environment( + self, + request: environment.GetEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.GetEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for get_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_continuous_test_results( + self, + request: environment.ListContinuousTestResultsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.ListContinuousTestResultsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_continuous_test_results + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_continuous_test_results( + self, response: environment.ListContinuousTestResultsResponse + ) -> environment.ListContinuousTestResultsResponse: + """Post-rpc interceptor for list_continuous_test_results + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_environments( + self, + request: environment.ListEnvironmentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.ListEnvironmentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_environments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_environments( + self, response: environment.ListEnvironmentsResponse + ) -> environment.ListEnvironmentsResponse: + """Post-rpc interceptor for list_environments + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_lookup_environment_history( + self, + request: environment.LookupEnvironmentHistoryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.LookupEnvironmentHistoryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for lookup_environment_history + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_lookup_environment_history( + self, response: environment.LookupEnvironmentHistoryResponse + ) -> environment.LookupEnvironmentHistoryResponse: + """Post-rpc interceptor for lookup_environment_history + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_run_continuous_test( + self, + request: environment.RunContinuousTestRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.RunContinuousTestRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for run_continuous_test + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_run_continuous_test( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for run_continuous_test + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_update_environment( + self, + request: gcdc_environment.UpdateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_environment.UpdateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_update_environment( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for update_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EnvironmentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EnvironmentsRestInterceptor + + +class EnvironmentsRestTransport(EnvironmentsTransport): + """REST backend transport for Environments. + + Service for managing + [Environments][google.cloud.dialogflow.cx.v3.Environment]. + + 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 = "dialogflow.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[EnvironmentsRestInterceptor] = 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 EnvironmentsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/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="v3", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("CreateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_environment.CreateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create environment method over HTTP. + + Args: + request (~.gcdc_environment.CreateEnvironmentRequest): + The request object. The request message for + [Environments.CreateEnvironment][google.cloud.dialogflow.cx.v3.Environments.CreateEnvironment]. + + 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": "/v3/{parent=projects/*/locations/*/agents/*}/environments", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_create_environment( + request, metadata + ) + pb_request = gcdc_environment.CreateEnvironmentRequest.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_create_environment(resp) + return resp + + class _DeleteEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("DeleteEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.DeleteEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete environment method over HTTP. + + Args: + request (~.environment.DeleteEnvironmentRequest): + The request object. The request message for + [Environments.DeleteEnvironment][google.cloud.dialogflow.cx.v3.Environments.DeleteEnvironment]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_environment( + request, metadata + ) + pb_request = environment.DeleteEnvironmentRequest.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 _DeployFlow(EnvironmentsRestStub): + def __hash__(self): + return hash("DeployFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.DeployFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the deploy flow method over HTTP. + + Args: + request (~.environment.DeployFlowRequest): + The request object. The request message for + [Environments.DeployFlow][google.cloud.dialogflow.cx.v3.Environments.DeployFlow]. + + 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": "/v3/{environment=projects/*/locations/*/agents/*/environments/*}:deployFlow", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_deploy_flow(request, metadata) + pb_request = environment.DeployFlowRequest.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_deploy_flow(resp) + return resp + + class _GetEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("GetEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.GetEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the get environment method over HTTP. + + Args: + request (~.environment.GetEnvironmentRequest): + The request object. The request message for + [Environments.GetEnvironment][google.cloud.dialogflow.cx.v3.Environments.GetEnvironment]. + + 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: + ~.environment.Environment: + Represents an environment for an + agent. You can create multiple versions + of your agent and publish them to + separate environments. When you edit an + agent, you are editing the draft agent. + At any point, you can save the draft + agent as an agent version, which is an + immutable snapshot of your agent. When + you save the draft agent, it is + published to the default environment. + When you create agent versions, you can + publish them to custom environments. You + can create a variety of custom + environments for testing, development, + production, etc. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_environment(request, metadata) + pb_request = environment.GetEnvironmentRequest.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 = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_environment(resp) + return resp + + class _ListContinuousTestResults(EnvironmentsRestStub): + def __hash__(self): + return hash("ListContinuousTestResults") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.ListContinuousTestResultsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.ListContinuousTestResultsResponse: + r"""Call the list continuous test + results method over HTTP. + + Args: + request (~.environment.ListContinuousTestResultsRequest): + The request object. The request message for + [Environments.ListContinuousTestResults][google.cloud.dialogflow.cx.v3.Environments.ListContinuousTestResults]. + + 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: + ~.environment.ListContinuousTestResultsResponse: + The response message for + [Environments.ListTestCaseResults][]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/environments/*}/continuousTestResults", + }, + ] + request, metadata = self._interceptor.pre_list_continuous_test_results( + request, metadata + ) + pb_request = environment.ListContinuousTestResultsRequest.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 = environment.ListContinuousTestResultsResponse() + pb_resp = environment.ListContinuousTestResultsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_continuous_test_results(resp) + return resp + + class _ListEnvironments(EnvironmentsRestStub): + def __hash__(self): + return hash("ListEnvironments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.ListEnvironmentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.ListEnvironmentsResponse: + r"""Call the list environments method over HTTP. + + Args: + request (~.environment.ListEnvironmentsRequest): + The request object. The request message for + [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. + + 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: + ~.environment.ListEnvironmentsResponse: + The response message for + [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/environments", + }, + ] + request, metadata = self._interceptor.pre_list_environments( + request, metadata + ) + pb_request = environment.ListEnvironmentsRequest.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 = environment.ListEnvironmentsResponse() + pb_resp = environment.ListEnvironmentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_environments(resp) + return resp + + class _LookupEnvironmentHistory(EnvironmentsRestStub): + def __hash__(self): + return hash("LookupEnvironmentHistory") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.LookupEnvironmentHistoryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.LookupEnvironmentHistoryResponse: + r"""Call the lookup environment + history method over HTTP. + + Args: + request (~.environment.LookupEnvironmentHistoryRequest): + The request object. The request message for + [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. + + 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: + ~.environment.LookupEnvironmentHistoryResponse: + The response message for + [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*}:lookupEnvironmentHistory", + }, + ] + request, metadata = self._interceptor.pre_lookup_environment_history( + request, metadata + ) + pb_request = environment.LookupEnvironmentHistoryRequest.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 = environment.LookupEnvironmentHistoryResponse() + pb_resp = environment.LookupEnvironmentHistoryResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_lookup_environment_history(resp) + return resp + + class _RunContinuousTest(EnvironmentsRestStub): + def __hash__(self): + return hash("RunContinuousTest") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.RunContinuousTestRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the run continuous test method over HTTP. + + Args: + request (~.environment.RunContinuousTestRequest): + The request object. The request message for + [Environments.RunContinuousTest][google.cloud.dialogflow.cx.v3.Environments.RunContinuousTest]. + + 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": "/v3/{environment=projects/*/locations/*/agents/*/environments/*}:runContinuousTest", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_run_continuous_test( + request, metadata + ) + pb_request = environment.RunContinuousTestRequest.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_run_continuous_test(resp) + return resp + + class _UpdateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("UpdateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_environment.UpdateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the update environment method over HTTP. + + Args: + request (~.gcdc_environment.UpdateEnvironmentRequest): + The request object. The request message for + [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3.Environments.UpdateEnvironment]. + + 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": "patch", + "uri": "/v3/{environment.name=projects/*/locations/*/agents/*/environments/*}", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_update_environment( + request, metadata + ) + pb_request = gcdc_environment.UpdateEnvironmentRequest.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_update_environment(resp) + return resp + + @property + def create_environment( + self, + ) -> Callable[ + [gcdc_environment.CreateEnvironmentRequest], 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._CreateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_environment( + self, + ) -> Callable[[environment.DeleteEnvironmentRequest], 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._DeleteEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def deploy_flow( + self, + ) -> Callable[[environment.DeployFlowRequest], 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._DeployFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_environment( + self, + ) -> Callable[[environment.GetEnvironmentRequest], environment.Environment]: + # 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._GetEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_continuous_test_results( + self, + ) -> Callable[ + [environment.ListContinuousTestResultsRequest], + environment.ListContinuousTestResultsResponse, + ]: + # 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._ListContinuousTestResults(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_environments( + self, + ) -> Callable[ + [environment.ListEnvironmentsRequest], environment.ListEnvironmentsResponse + ]: + # 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._ListEnvironments(self._session, self._host, self._interceptor) # type: ignore + + @property + def lookup_environment_history( + self, + ) -> Callable[ + [environment.LookupEnvironmentHistoryRequest], + environment.LookupEnvironmentHistoryResponse, + ]: + # 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._LookupEnvironmentHistory(self._session, self._host, self._interceptor) # type: ignore + + @property + def run_continuous_test( + self, + ) -> Callable[[environment.RunContinuousTestRequest], 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._RunContinuousTest(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_environment( + self, + ) -> Callable[ + [gcdc_environment.UpdateEnvironmentRequest], 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._UpdateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EnvironmentsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EnvironmentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/experiments/client.py b/google/cloud/dialogflowcx_v3/services/experiments/client.py index 6b5499ec..3e359922 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/client.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/client.py @@ -57,6 +57,7 @@ from .transports.base import ExperimentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import ExperimentsGrpcTransport from .transports.grpc_asyncio import ExperimentsGrpcAsyncIOTransport +from .transports.rest import ExperimentsRestTransport class ExperimentsClientMeta(type): @@ -70,6 +71,7 @@ class ExperimentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ExperimentsTransport]] _transport_registry["grpc"] = ExperimentsGrpcTransport _transport_registry["grpc_asyncio"] = ExperimentsGrpcAsyncIOTransport + _transport_registry["rest"] = ExperimentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/experiments/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/experiments/transports/__init__.py index 3a6183c3..7aeb3d45 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/transports/__init__.py @@ -19,15 +19,20 @@ from .base import ExperimentsTransport from .grpc import ExperimentsGrpcTransport from .grpc_asyncio import ExperimentsGrpcAsyncIOTransport +from .rest import ExperimentsRestTransport +from .rest import ExperimentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ExperimentsTransport]] _transport_registry["grpc"] = ExperimentsGrpcTransport _transport_registry["grpc_asyncio"] = ExperimentsGrpcAsyncIOTransport +_transport_registry["rest"] = ExperimentsRestTransport __all__ = ( "ExperimentsTransport", "ExperimentsGrpcTransport", "ExperimentsGrpcAsyncIOTransport", + "ExperimentsRestTransport", + "ExperimentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/experiments/transports/rest.py b/google/cloud/dialogflowcx_v3/services/experiments/transports/rest.py new file mode 100644 index 00000000..5c4fc9be --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/experiments/transports/rest.py @@ -0,0 +1,1569 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import experiment +from google.cloud.dialogflowcx_v3.types import experiment as gcdc_experiment +from google.protobuf import empty_pb2 # type: ignore + +from .base import ExperimentsTransport, 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 ExperimentsRestInterceptor: + """Interceptor for Experiments. + + 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 ExperimentsRestTransport. + + .. code-block:: python + class MyCustomExperimentsInterceptor(ExperimentsRestInterceptor): + def pre_create_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_experiments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_experiments(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_start_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_start_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_stop_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_stop_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ExperimentsRestTransport(interceptor=MyCustomExperimentsInterceptor()) + client = ExperimentsClient(transport=transport) + + + """ + + def pre_create_experiment( + self, + request: gcdc_experiment.CreateExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_experiment.CreateExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_create_experiment( + self, response: gcdc_experiment.Experiment + ) -> gcdc_experiment.Experiment: + """Post-rpc interceptor for create_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_delete_experiment( + self, + request: experiment.DeleteExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.DeleteExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def pre_get_experiment( + self, + request: experiment.GetExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.GetExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_get_experiment( + self, response: experiment.Experiment + ) -> experiment.Experiment: + """Post-rpc interceptor for get_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_list_experiments( + self, + request: experiment.ListExperimentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.ListExperimentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_experiments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_list_experiments( + self, response: experiment.ListExperimentsResponse + ) -> experiment.ListExperimentsResponse: + """Post-rpc interceptor for list_experiments + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_start_experiment( + self, + request: experiment.StartExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.StartExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for start_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_start_experiment( + self, response: experiment.Experiment + ) -> experiment.Experiment: + """Post-rpc interceptor for start_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_stop_experiment( + self, + request: experiment.StopExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.StopExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for stop_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_stop_experiment( + self, response: experiment.Experiment + ) -> experiment.Experiment: + """Post-rpc interceptor for stop_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_update_experiment( + self, + request: gcdc_experiment.UpdateExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_experiment.UpdateExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_update_experiment( + self, response: gcdc_experiment.Experiment + ) -> gcdc_experiment.Experiment: + """Post-rpc interceptor for update_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Experiments 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ExperimentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ExperimentsRestInterceptor + + +class ExperimentsRestTransport(ExperimentsTransport): + """REST backend transport for Experiments. + + Service for managing + [Experiments][google.cloud.dialogflow.cx.v3.Experiment]. + + 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 = "dialogflow.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[ExperimentsRestInterceptor] = 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 ExperimentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("CreateExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_experiment.CreateExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_experiment.Experiment: + r"""Call the create experiment method over HTTP. + + Args: + request (~.gcdc_experiment.CreateExperimentRequest): + The request object. The request message for + [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3.Experiments.CreateExperiment]. + + 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: + ~.gcdc_experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/environments/*}/experiments", + "body": "experiment", + }, + ] + request, metadata = self._interceptor.pre_create_experiment( + request, metadata + ) + pb_request = gcdc_experiment.CreateExperimentRequest.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 = gcdc_experiment.Experiment() + pb_resp = gcdc_experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_experiment(resp) + return resp + + class _DeleteExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("DeleteExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.DeleteExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete experiment method over HTTP. + + Args: + request (~.experiment.DeleteExperimentRequest): + The request object. The request message for + [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3.Experiments.DeleteExperiment]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_experiment( + request, metadata + ) + pb_request = experiment.DeleteExperimentRequest.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 _GetExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("GetExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.GetExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.Experiment: + r"""Call the get experiment method over HTTP. + + Args: + request (~.experiment.GetExperimentRequest): + The request object. The request message for + [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3.Experiments.GetExperiment]. + + 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: + ~.experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_experiment(request, metadata) + pb_request = experiment.GetExperimentRequest.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 = experiment.Experiment() + pb_resp = experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_experiment(resp) + return resp + + class _ListExperiments(ExperimentsRestStub): + def __hash__(self): + return hash("ListExperiments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.ListExperimentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.ListExperimentsResponse: + r"""Call the list experiments method over HTTP. + + Args: + request (~.experiment.ListExperimentsRequest): + The request object. The request message for + [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. + + 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: + ~.experiment.ListExperimentsResponse: + The response message for + [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/environments/*}/experiments", + }, + ] + request, metadata = self._interceptor.pre_list_experiments( + request, metadata + ) + pb_request = experiment.ListExperimentsRequest.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 = experiment.ListExperimentsResponse() + pb_resp = experiment.ListExperimentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_experiments(resp) + return resp + + class _StartExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("StartExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.StartExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.Experiment: + r"""Call the start experiment method over HTTP. + + Args: + request (~.experiment.StartExperimentRequest): + The request object. The request message for + [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3.Experiments.StartExperiment]. + + 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: + ~.experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:start", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_start_experiment( + request, metadata + ) + pb_request = experiment.StartExperimentRequest.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 = experiment.Experiment() + pb_resp = experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_start_experiment(resp) + return resp + + class _StopExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("StopExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.StopExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.Experiment: + r"""Call the stop experiment method over HTTP. + + Args: + request (~.experiment.StopExperimentRequest): + The request object. The request message for + [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3.Experiments.StopExperiment]. + + 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: + ~.experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:stop", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_stop_experiment(request, metadata) + pb_request = experiment.StopExperimentRequest.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 = experiment.Experiment() + pb_resp = experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_stop_experiment(resp) + return resp + + class _UpdateExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("UpdateExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_experiment.UpdateExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_experiment.Experiment: + r"""Call the update experiment method over HTTP. + + Args: + request (~.gcdc_experiment.UpdateExperimentRequest): + The request object. The request message for + [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3.Experiments.UpdateExperiment]. + + 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: + ~.gcdc_experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{experiment.name=projects/*/locations/*/agents/*/environments/*/experiments/*}", + "body": "experiment", + }, + ] + request, metadata = self._interceptor.pre_update_experiment( + request, metadata + ) + pb_request = gcdc_experiment.UpdateExperimentRequest.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 = gcdc_experiment.Experiment() + pb_resp = gcdc_experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_experiment(resp) + return resp + + @property + def create_experiment( + self, + ) -> Callable[ + [gcdc_experiment.CreateExperimentRequest], gcdc_experiment.Experiment + ]: + # 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._CreateExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_experiment( + self, + ) -> Callable[[experiment.DeleteExperimentRequest], 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._DeleteExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_experiment( + self, + ) -> Callable[[experiment.GetExperimentRequest], experiment.Experiment]: + # 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._GetExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_experiments( + self, + ) -> Callable[ + [experiment.ListExperimentsRequest], experiment.ListExperimentsResponse + ]: + # 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._ListExperiments(self._session, self._host, self._interceptor) # type: ignore + + @property + def start_experiment( + self, + ) -> Callable[[experiment.StartExperimentRequest], experiment.Experiment]: + # 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._StartExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def stop_experiment( + self, + ) -> Callable[[experiment.StopExperimentRequest], experiment.Experiment]: + # 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._StopExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_experiment( + self, + ) -> Callable[ + [gcdc_experiment.UpdateExperimentRequest], gcdc_experiment.Experiment + ]: + # 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._UpdateExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ExperimentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ExperimentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ExperimentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ExperimentsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ExperimentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ExperimentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/flows/client.py b/google/cloud/dialogflowcx_v3/services/flows/client.py index 3cd59da5..9857a26b 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/client.py +++ b/google/cloud/dialogflowcx_v3/services/flows/client.py @@ -62,6 +62,7 @@ from .transports.base import FlowsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import FlowsGrpcTransport from .transports.grpc_asyncio import FlowsGrpcAsyncIOTransport +from .transports.rest import FlowsRestTransport class FlowsClientMeta(type): @@ -75,6 +76,7 @@ class FlowsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[FlowsTransport]] _transport_registry["grpc"] = FlowsGrpcTransport _transport_registry["grpc_asyncio"] = FlowsGrpcAsyncIOTransport + _transport_registry["rest"] = FlowsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/flows/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/flows/transports/__init__.py index d27c76de..5a0a6683 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/flows/transports/__init__.py @@ -19,15 +19,20 @@ from .base import FlowsTransport from .grpc import FlowsGrpcTransport from .grpc_asyncio import FlowsGrpcAsyncIOTransport +from .rest import FlowsRestTransport +from .rest import FlowsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[FlowsTransport]] _transport_registry["grpc"] = FlowsGrpcTransport _transport_registry["grpc_asyncio"] = FlowsGrpcAsyncIOTransport +_transport_registry["rest"] = FlowsRestTransport __all__ = ( "FlowsTransport", "FlowsGrpcTransport", "FlowsGrpcAsyncIOTransport", + "FlowsRestTransport", + "FlowsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/flows/transports/rest.py b/google/cloud/dialogflowcx_v3/services/flows/transports/rest.py new file mode 100644 index 00000000..9e012c24 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/flows/transports/rest.py @@ -0,0 +1,2043 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import flow +from google.cloud.dialogflowcx_v3.types import flow as gcdc_flow +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import FlowsTransport, 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 FlowsRestInterceptor: + """Interceptor for Flows. + + 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 FlowsRestTransport. + + .. code-block:: python + class MyCustomFlowsInterceptor(FlowsRestInterceptor): + def pre_create_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_flow_validation_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_flow_validation_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_flows(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_flows(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_train_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_train_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_validate_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_validate_flow(self, response): + logging.log(f"Received response: {response}") + return response + + transport = FlowsRestTransport(interceptor=MyCustomFlowsInterceptor()) + client = FlowsClient(transport=transport) + + + """ + + def pre_create_flow( + self, request: gcdc_flow.CreateFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_flow.CreateFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_create_flow(self, response: gcdc_flow.Flow) -> gcdc_flow.Flow: + """Post-rpc interceptor for create_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_delete_flow( + self, request: flow.DeleteFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.DeleteFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def pre_export_flow( + self, request: flow.ExportFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ExportFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_export_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_get_flow( + self, request: flow.GetFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.GetFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_flow(self, response: flow.Flow) -> flow.Flow: + """Post-rpc interceptor for get_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_get_flow_validation_result( + self, + request: flow.GetFlowValidationResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[flow.GetFlowValidationResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_flow_validation_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_flow_validation_result( + self, response: flow.FlowValidationResult + ) -> flow.FlowValidationResult: + """Post-rpc interceptor for get_flow_validation_result + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_import_flow( + self, request: flow.ImportFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ImportFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_import_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_list_flows( + self, request: flow.ListFlowsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ListFlowsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_flows + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_list_flows( + self, response: flow.ListFlowsResponse + ) -> flow.ListFlowsResponse: + """Post-rpc interceptor for list_flows + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_train_flow( + self, request: flow.TrainFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.TrainFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for train_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_train_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for train_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_update_flow( + self, request: gcdc_flow.UpdateFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_flow.UpdateFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_update_flow(self, response: gcdc_flow.Flow) -> gcdc_flow.Flow: + """Post-rpc interceptor for update_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_validate_flow( + self, request: flow.ValidateFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ValidateFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for validate_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_validate_flow( + self, response: flow.FlowValidationResult + ) -> flow.FlowValidationResult: + """Post-rpc interceptor for validate_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Flows 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class FlowsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: FlowsRestInterceptor + + +class FlowsRestTransport(FlowsTransport): + """REST backend transport for Flows. + + Service for managing [Flows][google.cloud.dialogflow.cx.v3.Flow]. + + 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 = "dialogflow.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[FlowsRestInterceptor] = 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 FlowsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/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="v3", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateFlow(FlowsRestStub): + def __hash__(self): + return hash("CreateFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_flow.CreateFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_flow.Flow: + r"""Call the create flow method over HTTP. + + Args: + request (~.gcdc_flow.CreateFlowRequest): + The request object. The request message for + [Flows.CreateFlow][google.cloud.dialogflow.cx.v3.Flows.CreateFlow]. + + 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: + ~.gcdc_flow.Flow: + Flows represents the conversation + flows when you build your chatbot agent. + A flow consists of many pages connected + by the transition routes. Conversations + always start with the built-in Start + Flow (with an all-0 ID). Transition + routes can direct the conversation + session from the current flow (parent + flow) to another flow (sub flow). When + the sub flow is finished, Dialogflow + will bring the session back to the + parent flow, where the sub flow is + started. + + Usually, when a transition route is + followed by a matched intent, the intent + will be "consumed". This means the + intent won't activate more transition + routes. However, when the followed + transition route moves the conversation + session into a different flow, the + matched intent can be carried over and + to be consumed in the target flow. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/flows", + "body": "flow", + }, + ] + request, metadata = self._interceptor.pre_create_flow(request, metadata) + pb_request = gcdc_flow.CreateFlowRequest.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 = gcdc_flow.Flow() + pb_resp = gcdc_flow.Flow.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_flow(resp) + return resp + + class _DeleteFlow(FlowsRestStub): + def __hash__(self): + return hash("DeleteFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.DeleteFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete flow method over HTTP. + + Args: + request (~.flow.DeleteFlowRequest): + The request object. The request message for + [Flows.DeleteFlow][google.cloud.dialogflow.cx.v3.Flows.DeleteFlow]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_flow(request, metadata) + pb_request = flow.DeleteFlowRequest.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 _ExportFlow(FlowsRestStub): + def __hash__(self): + return hash("ExportFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ExportFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export flow method over HTTP. + + Args: + request (~.flow.ExportFlowRequest): + The request object. The request message for + [Flows.ExportFlow][google.cloud.dialogflow.cx.v3.Flows.ExportFlow]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*}:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_flow(request, metadata) + pb_request = flow.ExportFlowRequest.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_flow(resp) + return resp + + class _GetFlow(FlowsRestStub): + def __hash__(self): + return hash("GetFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.GetFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.Flow: + r"""Call the get flow method over HTTP. + + Args: + request (~.flow.GetFlowRequest): + The request object. The response message for + [Flows.GetFlow][google.cloud.dialogflow.cx.v3.Flows.GetFlow]. + + 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: + ~.flow.Flow: + Flows represents the conversation + flows when you build your chatbot agent. + A flow consists of many pages connected + by the transition routes. Conversations + always start with the built-in Start + Flow (with an all-0 ID). Transition + routes can direct the conversation + session from the current flow (parent + flow) to another flow (sub flow). When + the sub flow is finished, Dialogflow + will bring the session back to the + parent flow, where the sub flow is + started. + + Usually, when a transition route is + followed by a matched intent, the intent + will be "consumed". This means the + intent won't activate more transition + routes. However, when the followed + transition route moves the conversation + session into a different flow, the + matched intent can be carried over and + to be consumed in the target flow. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/flows/*}", + }, + ] + request, metadata = self._interceptor.pre_get_flow(request, metadata) + pb_request = flow.GetFlowRequest.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 = flow.Flow() + pb_resp = flow.Flow.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_flow(resp) + return resp + + class _GetFlowValidationResult(FlowsRestStub): + def __hash__(self): + return hash("GetFlowValidationResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.GetFlowValidationResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Call the get flow validation + result method over HTTP. + + Args: + request (~.flow.GetFlowValidationResultRequest): + The request object. The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + 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: + ~.flow.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/flows/*/validationResult}", + }, + ] + request, metadata = self._interceptor.pre_get_flow_validation_result( + request, metadata + ) + pb_request = flow.GetFlowValidationResultRequest.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 = flow.FlowValidationResult() + pb_resp = flow.FlowValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_flow_validation_result(resp) + return resp + + class _ImportFlow(FlowsRestStub): + def __hash__(self): + return hash("ImportFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ImportFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import flow method over HTTP. + + Args: + request (~.flow.ImportFlowRequest): + The request object. The request message for + [Flows.ImportFlow][google.cloud.dialogflow.cx.v3.Flows.ImportFlow]. + + 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": "/v3/{parent=projects/*/locations/*/agents/*}/flows:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_flow(request, metadata) + pb_request = flow.ImportFlowRequest.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_import_flow(resp) + return resp + + class _ListFlows(FlowsRestStub): + def __hash__(self): + return hash("ListFlows") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ListFlowsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.ListFlowsResponse: + r"""Call the list flows method over HTTP. + + Args: + request (~.flow.ListFlowsRequest): + The request object. The request message for + [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. + + 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: + ~.flow.ListFlowsResponse: + The response message for + [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/flows", + }, + ] + request, metadata = self._interceptor.pre_list_flows(request, metadata) + pb_request = flow.ListFlowsRequest.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 = flow.ListFlowsResponse() + pb_resp = flow.ListFlowsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_flows(resp) + return resp + + class _TrainFlow(FlowsRestStub): + def __hash__(self): + return hash("TrainFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.TrainFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the train flow method over HTTP. + + Args: + request (~.flow.TrainFlowRequest): + The request object. The request message for + [Flows.TrainFlow][google.cloud.dialogflow.cx.v3.Flows.TrainFlow]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*}:train", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_train_flow(request, metadata) + pb_request = flow.TrainFlowRequest.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_train_flow(resp) + return resp + + class _UpdateFlow(FlowsRestStub): + def __hash__(self): + return hash("UpdateFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_flow.UpdateFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_flow.Flow: + r"""Call the update flow method over HTTP. + + Args: + request (~.gcdc_flow.UpdateFlowRequest): + The request object. The request message for + [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3.Flows.UpdateFlow]. + + 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: + ~.gcdc_flow.Flow: + Flows represents the conversation + flows when you build your chatbot agent. + A flow consists of many pages connected + by the transition routes. Conversations + always start with the built-in Start + Flow (with an all-0 ID). Transition + routes can direct the conversation + session from the current flow (parent + flow) to another flow (sub flow). When + the sub flow is finished, Dialogflow + will bring the session back to the + parent flow, where the sub flow is + started. + + Usually, when a transition route is + followed by a matched intent, the intent + will be "consumed". This means the + intent won't activate more transition + routes. However, when the followed + transition route moves the conversation + session into a different flow, the + matched intent can be carried over and + to be consumed in the target flow. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{flow.name=projects/*/locations/*/agents/*/flows/*}", + "body": "flow", + }, + ] + request, metadata = self._interceptor.pre_update_flow(request, metadata) + pb_request = gcdc_flow.UpdateFlowRequest.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 = gcdc_flow.Flow() + pb_resp = gcdc_flow.Flow.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_flow(resp) + return resp + + class _ValidateFlow(FlowsRestStub): + def __hash__(self): + return hash("ValidateFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ValidateFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Call the validate flow method over HTTP. + + Args: + request (~.flow.ValidateFlowRequest): + The request object. The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3.Flows.ValidateFlow]. + + 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: + ~.flow.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/agents/*/flows/*}:validate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_validate_flow(request, metadata) + pb_request = flow.ValidateFlowRequest.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 = flow.FlowValidationResult() + pb_resp = flow.FlowValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_validate_flow(resp) + return resp + + @property + def create_flow(self) -> Callable[[gcdc_flow.CreateFlowRequest], gcdc_flow.Flow]: + # 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._CreateFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_flow(self) -> Callable[[flow.DeleteFlowRequest], 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._DeleteFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_flow( + self, + ) -> Callable[[flow.ExportFlowRequest], 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._ExportFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_flow(self) -> Callable[[flow.GetFlowRequest], flow.Flow]: + # 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._GetFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_flow_validation_result( + self, + ) -> Callable[[flow.GetFlowValidationResultRequest], flow.FlowValidationResult]: + # 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._GetFlowValidationResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_flow( + self, + ) -> Callable[[flow.ImportFlowRequest], 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._ImportFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_flows(self) -> Callable[[flow.ListFlowsRequest], flow.ListFlowsResponse]: + # 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._ListFlows(self._session, self._host, self._interceptor) # type: ignore + + @property + def train_flow(self) -> Callable[[flow.TrainFlowRequest], 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._TrainFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_flow(self) -> Callable[[gcdc_flow.UpdateFlowRequest], gcdc_flow.Flow]: + # 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._UpdateFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def validate_flow( + self, + ) -> Callable[[flow.ValidateFlowRequest], flow.FlowValidationResult]: + # 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._ValidateFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(FlowsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(FlowsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(FlowsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(FlowsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(FlowsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("FlowsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/intents/client.py b/google/cloud/dialogflowcx_v3/services/intents/client.py index 3cf95e09..94bd1018 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/client.py +++ b/google/cloud/dialogflowcx_v3/services/intents/client.py @@ -55,6 +55,7 @@ from .transports.base import IntentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import IntentsGrpcTransport from .transports.grpc_asyncio import IntentsGrpcAsyncIOTransport +from .transports.rest import IntentsRestTransport class IntentsClientMeta(type): @@ -68,6 +69,7 @@ class IntentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport + _transport_registry["rest"] = IntentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/intents/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/intents/transports/__init__.py index 876b5cd1..a7e402a6 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/intents/transports/__init__.py @@ -19,15 +19,20 @@ from .base import IntentsTransport from .grpc import IntentsGrpcTransport from .grpc_asyncio import IntentsGrpcAsyncIOTransport +from .rest import IntentsRestTransport +from .rest import IntentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport +_transport_registry["rest"] = IntentsRestTransport __all__ = ( "IntentsTransport", "IntentsGrpcTransport", "IntentsGrpcAsyncIOTransport", + "IntentsRestTransport", + "IntentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/intents/transports/rest.py b/google/cloud/dialogflowcx_v3/services/intents/transports/rest.py new file mode 100644 index 00000000..768912ea --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/intents/transports/rest.py @@ -0,0 +1,1274 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import intent +from google.cloud.dialogflowcx_v3.types import intent as gcdc_intent +from google.protobuf import empty_pb2 # type: ignore + +from .base import IntentsTransport, 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 IntentsRestInterceptor: + """Interceptor for Intents. + + 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 IntentsRestTransport. + + .. code-block:: python + class MyCustomIntentsInterceptor(IntentsRestInterceptor): + def pre_create_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = IntentsRestTransport(interceptor=MyCustomIntentsInterceptor()) + client = IntentsClient(transport=transport) + + + """ + + def pre_create_intent( + self, + request: gcdc_intent.CreateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_intent.CreateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_create_intent(self, response: gcdc_intent.Intent) -> gcdc_intent.Intent: + """Post-rpc interceptor for create_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_delete_intent( + self, request: intent.DeleteIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.DeleteIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def pre_get_intent( + self, request: intent.GetIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.GetIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_intent(self, response: intent.Intent) -> intent.Intent: + """Post-rpc interceptor for get_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_intents( + self, request: intent.ListIntentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.ListIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_intents( + self, response: intent.ListIntentsResponse + ) -> intent.ListIntentsResponse: + """Post-rpc interceptor for list_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_update_intent( + self, + request: gcdc_intent.UpdateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_intent.UpdateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_update_intent(self, response: gcdc_intent.Intent) -> gcdc_intent.Intent: + """Post-rpc interceptor for update_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class IntentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: IntentsRestInterceptor + + +class IntentsRestTransport(IntentsTransport): + """REST backend transport for Intents. + + Service for managing + [Intents][google.cloud.dialogflow.cx.v3.Intent]. + + 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 = "dialogflow.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[IntentsRestInterceptor] = 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 IntentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateIntent(IntentsRestStub): + def __hash__(self): + return hash("CreateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_intent.CreateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_intent.Intent: + r"""Call the create intent method over HTTP. + + Args: + request (~.gcdc_intent.CreateIntentRequest): + The request object. The request message for + [Intents.CreateIntent][google.cloud.dialogflow.cx.v3.Intents.CreateIntent]. + + 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: + ~.gcdc_intent.Intent: + An intent represents a user's intent + to interact with a conversational agent. + You can provide information for the + Dialogflow API to use to match user + input to an intent by adding training + phrases (i.e., examples of user input) + to your intent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/intents", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_create_intent(request, metadata) + pb_request = gcdc_intent.CreateIntentRequest.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 = gcdc_intent.Intent() + pb_resp = gcdc_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_intent(resp) + return resp + + class _DeleteIntent(IntentsRestStub): + def __hash__(self): + return hash("DeleteIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: intent.DeleteIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete intent method over HTTP. + + Args: + request (~.intent.DeleteIntentRequest): + The request object. The request message for + [Intents.DeleteIntent][google.cloud.dialogflow.cx.v3.Intents.DeleteIntent]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_intent(request, metadata) + pb_request = intent.DeleteIntentRequest.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 _GetIntent(IntentsRestStub): + def __hash__(self): + return hash("GetIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: intent.GetIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.Intent: + r"""Call the get intent method over HTTP. + + Args: + request (~.intent.GetIntentRequest): + The request object. The request message for + [Intents.GetIntent][google.cloud.dialogflow.cx.v3.Intents.GetIntent]. + + 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: + ~.intent.Intent: + An intent represents a user's intent + to interact with a conversational agent. + You can provide information for the + Dialogflow API to use to match user + input to an intent by adding training + phrases (i.e., examples of user input) + to your intent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_intent(request, metadata) + pb_request = intent.GetIntentRequest.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 = intent.Intent() + pb_resp = intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_intent(resp) + return resp + + class _ListIntents(IntentsRestStub): + def __hash__(self): + return hash("ListIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: intent.ListIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.ListIntentsResponse: + r"""Call the list intents method over HTTP. + + Args: + request (~.intent.ListIntentsRequest): + The request object. The request message for + [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. + + 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: + ~.intent.ListIntentsResponse: + The response message for + [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/intents", + }, + ] + request, metadata = self._interceptor.pre_list_intents(request, metadata) + pb_request = intent.ListIntentsRequest.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 = intent.ListIntentsResponse() + pb_resp = intent.ListIntentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_intents(resp) + return resp + + class _UpdateIntent(IntentsRestStub): + def __hash__(self): + return hash("UpdateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_intent.UpdateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_intent.Intent: + r"""Call the update intent method over HTTP. + + Args: + request (~.gcdc_intent.UpdateIntentRequest): + The request object. The request message for + [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3.Intents.UpdateIntent]. + + 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: + ~.gcdc_intent.Intent: + An intent represents a user's intent + to interact with a conversational agent. + You can provide information for the + Dialogflow API to use to match user + input to an intent by adding training + phrases (i.e., examples of user input) + to your intent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{intent.name=projects/*/locations/*/agents/*/intents/*}", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_update_intent(request, metadata) + pb_request = gcdc_intent.UpdateIntentRequest.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 = gcdc_intent.Intent() + pb_resp = gcdc_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_intent(resp) + return resp + + @property + def create_intent( + self, + ) -> Callable[[gcdc_intent.CreateIntentRequest], gcdc_intent.Intent]: + # 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._CreateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_intent(self) -> Callable[[intent.DeleteIntentRequest], 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._DeleteIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_intent(self) -> Callable[[intent.GetIntentRequest], intent.Intent]: + # 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._GetIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_intents( + self, + ) -> Callable[[intent.ListIntentsRequest], intent.ListIntentsResponse]: + # 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._ListIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_intent( + self, + ) -> Callable[[gcdc_intent.UpdateIntentRequest], gcdc_intent.Intent]: + # 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._UpdateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(IntentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(IntentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(IntentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(IntentsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(IntentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("IntentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/pages/client.py b/google/cloud/dialogflowcx_v3/services/pages/client.py index 36547c2c..cd1b0246 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/client.py +++ b/google/cloud/dialogflowcx_v3/services/pages/client.py @@ -56,6 +56,7 @@ from .transports.base import PagesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import PagesGrpcTransport from .transports.grpc_asyncio import PagesGrpcAsyncIOTransport +from .transports.rest import PagesRestTransport class PagesClientMeta(type): @@ -69,6 +70,7 @@ class PagesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[PagesTransport]] _transport_registry["grpc"] = PagesGrpcTransport _transport_registry["grpc_asyncio"] = PagesGrpcAsyncIOTransport + _transport_registry["rest"] = PagesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/pages/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/pages/transports/__init__.py index fd23f06e..387c6a3a 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/pages/transports/__init__.py @@ -19,15 +19,20 @@ from .base import PagesTransport from .grpc import PagesGrpcTransport from .grpc_asyncio import PagesGrpcAsyncIOTransport +from .rest import PagesRestTransport +from .rest import PagesRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[PagesTransport]] _transport_registry["grpc"] = PagesGrpcTransport _transport_registry["grpc_asyncio"] = PagesGrpcAsyncIOTransport +_transport_registry["rest"] = PagesRestTransport __all__ = ( "PagesTransport", "PagesGrpcTransport", "PagesGrpcAsyncIOTransport", + "PagesRestTransport", + "PagesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/pages/transports/rest.py b/google/cloud/dialogflowcx_v3/services/pages/transports/rest.py new file mode 100644 index 00000000..34c6ef01 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/pages/transports/rest.py @@ -0,0 +1,1305 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import page +from google.cloud.dialogflowcx_v3.types import page as gcdc_page +from google.protobuf import empty_pb2 # type: ignore + +from .base import PagesTransport, 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 PagesRestInterceptor: + """Interceptor for Pages. + + 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 PagesRestTransport. + + .. code-block:: python + class MyCustomPagesInterceptor(PagesRestInterceptor): + def pre_create_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_page(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_page(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_pages(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_pages(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_page(self, response): + logging.log(f"Received response: {response}") + return response + + transport = PagesRestTransport(interceptor=MyCustomPagesInterceptor()) + client = PagesClient(transport=transport) + + + """ + + def pre_create_page( + self, request: gcdc_page.CreatePageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_page.CreatePageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_create_page(self, response: gcdc_page.Page) -> gcdc_page.Page: + """Post-rpc interceptor for create_page + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_delete_page( + self, request: page.DeletePageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[page.DeletePageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def pre_get_page( + self, request: page.GetPageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[page.GetPageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_get_page(self, response: page.Page) -> page.Page: + """Post-rpc interceptor for get_page + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_list_pages( + self, request: page.ListPagesRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[page.ListPagesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_pages + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_list_pages( + self, response: page.ListPagesResponse + ) -> page.ListPagesResponse: + """Post-rpc interceptor for list_pages + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_update_page( + self, request: gcdc_page.UpdatePageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_page.UpdatePageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_update_page(self, response: gcdc_page.Page) -> gcdc_page.Page: + """Post-rpc interceptor for update_page + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Pages 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class PagesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: PagesRestInterceptor + + +class PagesRestTransport(PagesTransport): + """REST backend transport for Pages. + + Service for managing [Pages][google.cloud.dialogflow.cx.v3.Page]. + + 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 = "dialogflow.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[PagesRestInterceptor] = 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 PagesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreatePage(PagesRestStub): + def __hash__(self): + return hash("CreatePage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_page.CreatePageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_page.Page: + r"""Call the create page method over HTTP. + + Args: + request (~.gcdc_page.CreatePageRequest): + The request object. The request message for + [Pages.CreatePage][google.cloud.dialogflow.cx.v3.Pages.CreatePage]. + + 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: + ~.gcdc_page.Page: + A Dialogflow CX conversation (session) can be described + and visualized as a state machine. The states of a CX + session are represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on the + topics the flow is designed for. At any given moment, + exactly one page is the current page, the current page + is considered active, and the flow associated with that + page is considered active. Every flow has a special + start page. When a flow initially becomes active, the + start page page becomes the current page. For each + conversational turn, the current page will either stay + the same or transition to another page. + + You configure each page to collect information from the + end-user that is relevant for the conversational state + represented by the page. + + For more information, see the `Page + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/flows/*}/pages", + "body": "page", + }, + ] + request, metadata = self._interceptor.pre_create_page(request, metadata) + pb_request = gcdc_page.CreatePageRequest.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 = gcdc_page.Page() + pb_resp = gcdc_page.Page.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_page(resp) + return resp + + class _DeletePage(PagesRestStub): + def __hash__(self): + return hash("DeletePage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: page.DeletePageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete page method over HTTP. + + Args: + request (~.page.DeletePageRequest): + The request object. The request message for + [Pages.DeletePage][google.cloud.dialogflow.cx.v3.Pages.DeletePage]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*/pages/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_page(request, metadata) + pb_request = page.DeletePageRequest.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 _GetPage(PagesRestStub): + def __hash__(self): + return hash("GetPage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: page.GetPageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> page.Page: + r"""Call the get page method over HTTP. + + Args: + request (~.page.GetPageRequest): + The request object. The request message for + [Pages.GetPage][google.cloud.dialogflow.cx.v3.Pages.GetPage]. + + 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: + ~.page.Page: + A Dialogflow CX conversation (session) can be described + and visualized as a state machine. The states of a CX + session are represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on the + topics the flow is designed for. At any given moment, + exactly one page is the current page, the current page + is considered active, and the flow associated with that + page is considered active. Every flow has a special + start page. When a flow initially becomes active, the + start page page becomes the current page. For each + conversational turn, the current page will either stay + the same or transition to another page. + + You configure each page to collect information from the + end-user that is relevant for the conversational state + represented by the page. + + For more information, see the `Page + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/flows/*/pages/*}", + }, + ] + request, metadata = self._interceptor.pre_get_page(request, metadata) + pb_request = page.GetPageRequest.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 = page.Page() + pb_resp = page.Page.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_page(resp) + return resp + + class _ListPages(PagesRestStub): + def __hash__(self): + return hash("ListPages") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: page.ListPagesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> page.ListPagesResponse: + r"""Call the list pages method over HTTP. + + Args: + request (~.page.ListPagesRequest): + The request object. The request message for + [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. + + 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: + ~.page.ListPagesResponse: + The response message for + [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/flows/*}/pages", + }, + ] + request, metadata = self._interceptor.pre_list_pages(request, metadata) + pb_request = page.ListPagesRequest.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 = page.ListPagesResponse() + pb_resp = page.ListPagesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_pages(resp) + return resp + + class _UpdatePage(PagesRestStub): + def __hash__(self): + return hash("UpdatePage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_page.UpdatePageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_page.Page: + r"""Call the update page method over HTTP. + + Args: + request (~.gcdc_page.UpdatePageRequest): + The request object. The request message for + [Pages.UpdatePage][google.cloud.dialogflow.cx.v3.Pages.UpdatePage]. + + 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: + ~.gcdc_page.Page: + A Dialogflow CX conversation (session) can be described + and visualized as a state machine. The states of a CX + session are represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on the + topics the flow is designed for. At any given moment, + exactly one page is the current page, the current page + is considered active, and the flow associated with that + page is considered active. Every flow has a special + start page. When a flow initially becomes active, the + start page page becomes the current page. For each + conversational turn, the current page will either stay + the same or transition to another page. + + You configure each page to collect information from the + end-user that is relevant for the conversational state + represented by the page. + + For more information, see the `Page + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{page.name=projects/*/locations/*/agents/*/flows/*/pages/*}", + "body": "page", + }, + ] + request, metadata = self._interceptor.pre_update_page(request, metadata) + pb_request = gcdc_page.UpdatePageRequest.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 = gcdc_page.Page() + pb_resp = gcdc_page.Page.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_page(resp) + return resp + + @property + def create_page(self) -> Callable[[gcdc_page.CreatePageRequest], gcdc_page.Page]: + # 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._CreatePage(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_page(self) -> Callable[[page.DeletePageRequest], 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._DeletePage(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_page(self) -> Callable[[page.GetPageRequest], page.Page]: + # 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._GetPage(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_pages(self) -> Callable[[page.ListPagesRequest], page.ListPagesResponse]: + # 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._ListPages(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_page(self) -> Callable[[gcdc_page.UpdatePageRequest], gcdc_page.Page]: + # 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._UpdatePage(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(PagesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(PagesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(PagesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(PagesRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(PagesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("PagesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py index 90ae8eff..7349eb12 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py @@ -57,6 +57,7 @@ from .transports.base import SecuritySettingsServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc import SecuritySettingsServiceGrpcTransport from .transports.grpc_asyncio import SecuritySettingsServiceGrpcAsyncIOTransport +from .transports.rest import SecuritySettingsServiceRestTransport class SecuritySettingsServiceClientMeta(type): @@ -72,6 +73,7 @@ class SecuritySettingsServiceClientMeta(type): ) # type: Dict[str, Type[SecuritySettingsServiceTransport]] _transport_registry["grpc"] = SecuritySettingsServiceGrpcTransport _transport_registry["grpc_asyncio"] = SecuritySettingsServiceGrpcAsyncIOTransport + _transport_registry["rest"] = SecuritySettingsServiceRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/__init__.py index bcf597b1..8bb194f4 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/__init__.py @@ -19,6 +19,8 @@ from .base import SecuritySettingsServiceTransport from .grpc import SecuritySettingsServiceGrpcTransport from .grpc_asyncio import SecuritySettingsServiceGrpcAsyncIOTransport +from .rest import SecuritySettingsServiceRestTransport +from .rest import SecuritySettingsServiceRestInterceptor # Compile a registry of transports. @@ -27,9 +29,12 @@ ) # type: Dict[str, Type[SecuritySettingsServiceTransport]] _transport_registry["grpc"] = SecuritySettingsServiceGrpcTransport _transport_registry["grpc_asyncio"] = SecuritySettingsServiceGrpcAsyncIOTransport +_transport_registry["rest"] = SecuritySettingsServiceRestTransport __all__ = ( "SecuritySettingsServiceTransport", "SecuritySettingsServiceGrpcTransport", "SecuritySettingsServiceGrpcAsyncIOTransport", + "SecuritySettingsServiceRestTransport", + "SecuritySettingsServiceRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/rest.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/rest.py new file mode 100644 index 00000000..47a86abb --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/rest.py @@ -0,0 +1,1327 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import security_settings +from google.cloud.dialogflowcx_v3.types import ( + security_settings as gcdc_security_settings, +) +from google.protobuf import empty_pb2 # type: ignore + +from .base import ( + SecuritySettingsServiceTransport, + 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 SecuritySettingsServiceRestInterceptor: + """Interceptor for SecuritySettingsService. + + 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 SecuritySettingsServiceRestTransport. + + .. code-block:: python + class MyCustomSecuritySettingsServiceInterceptor(SecuritySettingsServiceRestInterceptor): + def pre_create_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SecuritySettingsServiceRestTransport(interceptor=MyCustomSecuritySettingsServiceInterceptor()) + client = SecuritySettingsServiceClient(transport=transport) + + + """ + + def pre_create_security_settings( + self, + request: gcdc_security_settings.CreateSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_security_settings.CreateSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for create_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_create_security_settings( + self, response: gcdc_security_settings.SecuritySettings + ) -> gcdc_security_settings.SecuritySettings: + """Post-rpc interceptor for create_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_delete_security_settings( + self, + request: security_settings.DeleteSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + security_settings.DeleteSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def pre_get_security_settings( + self, + request: security_settings.GetSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[security_settings.GetSecuritySettingsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_get_security_settings( + self, response: security_settings.SecuritySettings + ) -> security_settings.SecuritySettings: + """Post-rpc interceptor for get_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_list_security_settings( + self, + request: security_settings.ListSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + security_settings.ListSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_list_security_settings( + self, response: security_settings.ListSecuritySettingsResponse + ) -> security_settings.ListSecuritySettingsResponse: + """Post-rpc interceptor for list_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_update_security_settings( + self, + request: gcdc_security_settings.UpdateSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_security_settings.UpdateSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for update_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_update_security_settings( + self, response: gcdc_security_settings.SecuritySettings + ) -> gcdc_security_settings.SecuritySettings: + """Post-rpc interceptor for update_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SecuritySettingsServiceRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SecuritySettingsServiceRestInterceptor + + +class SecuritySettingsServiceRestTransport(SecuritySettingsServiceTransport): + """REST backend transport for SecuritySettingsService. + + Service for managing security settings for Dialogflow. + + 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 = "dialogflow.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[SecuritySettingsServiceRestInterceptor] = 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 SecuritySettingsServiceRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("CreateSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_security_settings.CreateSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_security_settings.SecuritySettings: + r"""Call the create security settings method over HTTP. + + Args: + request (~.gcdc_security_settings.CreateSecuritySettingsRequest): + The request object. The request message for + [SecuritySettings.CreateSecuritySettings][]. + + 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: + ~.gcdc_security_settings.SecuritySettings: + Represents the settings related to + security issues, such as data redaction + and data retention. It may take hours + for updates on the settings to propagate + to all the related components and take + effect. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*}/securitySettings", + "body": "security_settings", + }, + ] + request, metadata = self._interceptor.pre_create_security_settings( + request, metadata + ) + pb_request = gcdc_security_settings.CreateSecuritySettingsRequest.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 = gcdc_security_settings.SecuritySettings() + pb_resp = gcdc_security_settings.SecuritySettings.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_security_settings(resp) + return resp + + class _DeleteSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("DeleteSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: security_settings.DeleteSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete security settings method over HTTP. + + Args: + request (~.security_settings.DeleteSecuritySettingsRequest): + The request object. The request message for + [SecuritySettings.DeleteSecuritySettings][]. + + 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": "/v3/{name=projects/*/locations/*/securitySettings/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_security_settings( + request, metadata + ) + pb_request = security_settings.DeleteSecuritySettingsRequest.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 _GetSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("GetSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: security_settings.GetSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> security_settings.SecuritySettings: + r"""Call the get security settings method over HTTP. + + Args: + request (~.security_settings.GetSecuritySettingsRequest): + The request object. The request message for + [SecuritySettingsService.GetSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.GetSecuritySettings]. + + 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: + ~.security_settings.SecuritySettings: + Represents the settings related to + security issues, such as data redaction + and data retention. It may take hours + for updates on the settings to propagate + to all the related components and take + effect. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/securitySettings/*}", + }, + ] + request, metadata = self._interceptor.pre_get_security_settings( + request, metadata + ) + pb_request = security_settings.GetSecuritySettingsRequest.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 = security_settings.SecuritySettings() + pb_resp = security_settings.SecuritySettings.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_security_settings(resp) + return resp + + class _ListSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("ListSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: security_settings.ListSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> security_settings.ListSecuritySettingsResponse: + r"""Call the list security settings method over HTTP. + + Args: + request (~.security_settings.ListSecuritySettingsRequest): + The request object. The request message for + [SecuritySettings.ListSecuritySettings][]. + + 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: + ~.security_settings.ListSecuritySettingsResponse: + The response message for + [SecuritySettings.ListSecuritySettings][]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*}/securitySettings", + }, + ] + request, metadata = self._interceptor.pre_list_security_settings( + request, metadata + ) + pb_request = security_settings.ListSecuritySettingsRequest.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 = security_settings.ListSecuritySettingsResponse() + pb_resp = security_settings.ListSecuritySettingsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_security_settings(resp) + return resp + + class _UpdateSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("UpdateSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_security_settings.UpdateSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_security_settings.SecuritySettings: + r"""Call the update security settings method over HTTP. + + Args: + request (~.gcdc_security_settings.UpdateSecuritySettingsRequest): + The request object. The request message for + [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.UpdateSecuritySettings]. + + 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: + ~.gcdc_security_settings.SecuritySettings: + Represents the settings related to + security issues, such as data redaction + and data retention. It may take hours + for updates on the settings to propagate + to all the related components and take + effect. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{security_settings.name=projects/*/locations/*/securitySettings/*}", + "body": "security_settings", + }, + ] + request, metadata = self._interceptor.pre_update_security_settings( + request, metadata + ) + pb_request = gcdc_security_settings.UpdateSecuritySettingsRequest.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 = gcdc_security_settings.SecuritySettings() + pb_resp = gcdc_security_settings.SecuritySettings.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_security_settings(resp) + return resp + + @property + def create_security_settings( + self, + ) -> Callable[ + [gcdc_security_settings.CreateSecuritySettingsRequest], + gcdc_security_settings.SecuritySettings, + ]: + # 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._CreateSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_security_settings( + self, + ) -> Callable[[security_settings.DeleteSecuritySettingsRequest], 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._DeleteSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_security_settings( + self, + ) -> Callable[ + [security_settings.GetSecuritySettingsRequest], + security_settings.SecuritySettings, + ]: + # 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._GetSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_security_settings( + self, + ) -> Callable[ + [security_settings.ListSecuritySettingsRequest], + security_settings.ListSecuritySettingsResponse, + ]: + # 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._ListSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_security_settings( + self, + ) -> Callable[ + [gcdc_security_settings.UpdateSecuritySettingsRequest], + gcdc_security_settings.SecuritySettings, + ]: + # 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._UpdateSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SecuritySettingsServiceRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SecuritySettingsServiceRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SecuritySettingsServiceRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SecuritySettingsServiceRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SecuritySettingsServiceRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SecuritySettingsServiceRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py index 9daf6771..6bba5380 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py @@ -58,6 +58,7 @@ from .transports.base import SessionEntityTypesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import SessionEntityTypesGrpcTransport from .transports.grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .transports.rest import SessionEntityTypesRestTransport class SessionEntityTypesClientMeta(type): @@ -73,6 +74,7 @@ class SessionEntityTypesClientMeta(type): ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = SessionEntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/__init__.py index 44e2a8d4..688ff207 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/__init__.py @@ -19,6 +19,8 @@ from .base import SessionEntityTypesTransport from .grpc import SessionEntityTypesGrpcTransport from .grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .rest import SessionEntityTypesRestTransport +from .rest import SessionEntityTypesRestInterceptor # Compile a registry of transports. @@ -27,9 +29,12 @@ ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = SessionEntityTypesRestTransport __all__ = ( "SessionEntityTypesTransport", "SessionEntityTypesGrpcTransport", "SessionEntityTypesGrpcAsyncIOTransport", + "SessionEntityTypesRestTransport", + "SessionEntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/rest.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/rest.py new file mode 100644 index 00000000..9139ecbc --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/rest.py @@ -0,0 +1,1390 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import session_entity_type +from google.cloud.dialogflowcx_v3.types import ( + session_entity_type as gcdc_session_entity_type, +) +from google.protobuf import empty_pb2 # type: ignore + +from .base import ( + SessionEntityTypesTransport, + 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 SessionEntityTypesRestInterceptor: + """Interceptor for SessionEntityTypes. + + 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 SessionEntityTypesRestTransport. + + .. code-block:: python + class MyCustomSessionEntityTypesInterceptor(SessionEntityTypesRestInterceptor): + def pre_create_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_session_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_session_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionEntityTypesRestTransport(interceptor=MyCustomSessionEntityTypesInterceptor()) + client = SessionEntityTypesClient(transport=transport) + + + """ + + def pre_create_session_entity_type( + self, + request: gcdc_session_entity_type.CreateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_session_entity_type.CreateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_create_session_entity_type( + self, response: gcdc_session_entity_type.SessionEntityType + ) -> gcdc_session_entity_type.SessionEntityType: + """Post-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_session_entity_type( + self, + request: session_entity_type.DeleteSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.DeleteSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def pre_get_session_entity_type( + self, + request: session_entity_type.GetSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.GetSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_session_entity_type( + self, response: session_entity_type.SessionEntityType + ) -> session_entity_type.SessionEntityType: + """Post-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_session_entity_types( + self, + request: session_entity_type.ListSessionEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.ListSessionEntityTypesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_session_entity_types( + self, response: session_entity_type.ListSessionEntityTypesResponse + ) -> session_entity_type.ListSessionEntityTypesResponse: + """Post-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_session_entity_type( + self, + request: gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_update_session_entity_type( + self, response: gcdc_session_entity_type.SessionEntityType + ) -> gcdc_session_entity_type.SessionEntityType: + """Post-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionEntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionEntityTypesRestInterceptor + + +class SessionEntityTypesRestTransport(SessionEntityTypesTransport): + """REST backend transport for SessionEntityTypes. + + Service for managing + [SessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityType]. + + 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 = "dialogflow.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[SessionEntityTypesRestInterceptor] = 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 SessionEntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("CreateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_session_entity_type.CreateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_session_entity_type.SessionEntityType: + r"""Call the create session entity + type method over HTTP. + + Args: + request (~.gcdc_session_entity_type.CreateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.CreateSessionEntityType]. + + 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: + ~.gcdc_session_entity_type.SessionEntityType: + Session entity types are referred to as **User** entity + types and are entities that are built for an individual + user such as favorites, preferences, playlists, and so + on. + + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at the + user session level (we refer to the entity types defined + at the agent level as "custom entity types"). + + Note: session entity types apply to all queries, + regardless of the language. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/environments/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_session_entity_type( + request, metadata + ) + pb_request = gcdc_session_entity_type.CreateSessionEntityTypeRequest.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 = gcdc_session_entity_type.SessionEntityType() + pb_resp = gcdc_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_session_entity_type(resp) + return resp + + class _DeleteSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("DeleteSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session_entity_type.DeleteSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete session entity + type method over HTTP. + + Args: + request (~.session_entity_type.DeleteSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.DeleteSessionEntityType]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.DeleteSessionEntityTypeRequest.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 _GetSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("GetSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session_entity_type.GetSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.SessionEntityType: + r"""Call the get session entity type method over HTTP. + + Args: + request (~.session_entity_type.GetSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.GetSessionEntityType]. + + 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: + ~.session_entity_type.SessionEntityType: + Session entity types are referred to as **User** entity + types and are entities that are built for an individual + user such as favorites, preferences, playlists, and so + on. + + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at the + user session level (we refer to the entity types defined + at the agent level as "custom entity types"). + + Note: session entity types apply to all queries, + regardless of the language. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/environments/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.GetSessionEntityTypeRequest.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 = session_entity_type.SessionEntityType() + pb_resp = session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_session_entity_type(resp) + return resp + + class _ListSessionEntityTypes(SessionEntityTypesRestStub): + def __hash__(self): + return hash("ListSessionEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session_entity_type.ListSessionEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.ListSessionEntityTypesResponse: + r"""Call the list session entity types method over HTTP. + + Args: + request (~.session_entity_type.ListSessionEntityTypesRequest): + The request object. The request message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. + + 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: + ~.session_entity_type.ListSessionEntityTypesResponse: + The response message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/environments/*/sessions/*}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_session_entity_types( + request, metadata + ) + pb_request = session_entity_type.ListSessionEntityTypesRequest.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 = session_entity_type.ListSessionEntityTypesResponse() + pb_resp = session_entity_type.ListSessionEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_session_entity_types(resp) + return resp + + class _UpdateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("UpdateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_session_entity_type.SessionEntityType: + r"""Call the update session entity + type method over HTTP. + + Args: + request (~.gcdc_session_entity_type.UpdateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.UpdateSessionEntityType]. + + 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: + ~.gcdc_session_entity_type.SessionEntityType: + Session entity types are referred to as **User** entity + types and are entities that are built for an individual + user such as favorites, preferences, playlists, and so + on. + + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at the + user session level (we refer to the entity types defined + at the agent level as "custom entity types"). + + Note: session entity types apply to all queries, + regardless of the language. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{session_entity_type.name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v3/{session_entity_type.name=projects/*/locations/*/agents/*/environments/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_session_entity_type( + request, metadata + ) + pb_request = gcdc_session_entity_type.UpdateSessionEntityTypeRequest.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 = gcdc_session_entity_type.SessionEntityType() + pb_resp = gcdc_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_session_entity_type(resp) + return resp + + @property + def create_session_entity_type( + self, + ) -> Callable[ + [gcdc_session_entity_type.CreateSessionEntityTypeRequest], + gcdc_session_entity_type.SessionEntityType, + ]: + # 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._CreateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.DeleteSessionEntityTypeRequest], 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._DeleteSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.GetSessionEntityTypeRequest], + session_entity_type.SessionEntityType, + ]: + # 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._GetSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_session_entity_types( + self, + ) -> Callable[ + [session_entity_type.ListSessionEntityTypesRequest], + session_entity_type.ListSessionEntityTypesResponse, + ]: + # 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._ListSessionEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_session_entity_type( + self, + ) -> Callable[ + [gcdc_session_entity_type.UpdateSessionEntityTypeRequest], + gcdc_session_entity_type.SessionEntityType, + ]: + # 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._UpdateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionEntityTypesRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionEntityTypesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/sessions/client.py b/google/cloud/dialogflowcx_v3/services/sessions/client.py index c588ddc4..3339b728 100644 --- a/google/cloud/dialogflowcx_v3/services/sessions/client.py +++ b/google/cloud/dialogflowcx_v3/services/sessions/client.py @@ -56,6 +56,7 @@ from .transports.base import SessionsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import SessionsGrpcTransport from .transports.grpc_asyncio import SessionsGrpcAsyncIOTransport +from .transports.rest import SessionsRestTransport class SessionsClientMeta(type): @@ -69,6 +70,7 @@ class SessionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport + _transport_registry["rest"] = SessionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/sessions/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/sessions/transports/__init__.py index ce00ff37..4417beb6 100644 --- a/google/cloud/dialogflowcx_v3/services/sessions/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/sessions/transports/__init__.py @@ -19,15 +19,20 @@ from .base import SessionsTransport from .grpc import SessionsGrpcTransport from .grpc_asyncio import SessionsGrpcAsyncIOTransport +from .rest import SessionsRestTransport +from .rest import SessionsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport +_transport_registry["rest"] = SessionsRestTransport __all__ = ( "SessionsTransport", "SessionsGrpcTransport", "SessionsGrpcAsyncIOTransport", + "SessionsRestTransport", + "SessionsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/sessions/transports/rest.py b/google/cloud/dialogflowcx_v3/services/sessions/transports/rest.py new file mode 100644 index 00000000..4f749a08 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/sessions/transports/rest.py @@ -0,0 +1,1069 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import session + +from .base import SessionsTransport, 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 SessionsRestInterceptor: + """Interceptor for Sessions. + + 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 SessionsRestTransport. + + .. code-block:: python + class MyCustomSessionsInterceptor(SessionsRestInterceptor): + def pre_detect_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_detect_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_fulfill_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_fulfill_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_match_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_match_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionsRestTransport(interceptor=MyCustomSessionsInterceptor()) + client = SessionsClient(transport=transport) + + + """ + + def pre_detect_intent( + self, request: session.DetectIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[session.DetectIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for detect_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_detect_intent( + self, response: session.DetectIntentResponse + ) -> session.DetectIntentResponse: + """Post-rpc interceptor for detect_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_fulfill_intent( + self, request: session.FulfillIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[session.FulfillIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for fulfill_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_fulfill_intent( + self, response: session.FulfillIntentResponse + ) -> session.FulfillIntentResponse: + """Post-rpc interceptor for fulfill_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_match_intent( + self, request: session.MatchIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[session.MatchIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for match_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_match_intent( + self, response: session.MatchIntentResponse + ) -> session.MatchIntentResponse: + """Post-rpc interceptor for match_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionsRestInterceptor + + +class SessionsRestTransport(SessionsTransport): + """REST backend transport for Sessions. + + A session represents an interaction with a user. You retrieve user + input and pass it to the + [DetectIntent][google.cloud.dialogflow.cx.v3.Sessions.DetectIntent] + method to determine user intent and respond. + + 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 = "dialogflow.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[SessionsRestInterceptor] = 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 SessionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _DetectIntent(SessionsRestStub): + def __hash__(self): + return hash("DetectIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session.DetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session.DetectIntentResponse: + r"""Call the detect intent method over HTTP. + + Args: + request (~.session.DetectIntentRequest): + The request object. The request to detect user's intent. + 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: + ~.session.DetectIntentResponse: + The message returned from the + DetectIntent method. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{session=projects/*/locations/*/agents/*/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v3/{session=projects/*/locations/*/agents/*/environments/*/sessions/*}:detectIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_detect_intent(request, metadata) + pb_request = session.DetectIntentRequest.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 = session.DetectIntentResponse() + pb_resp = session.DetectIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_detect_intent(resp) + return resp + + class _FulfillIntent(SessionsRestStub): + def __hash__(self): + return hash("FulfillIntent") + + def __call__( + self, + request: session.FulfillIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session.FulfillIntentResponse: + r"""Call the fulfill intent method over HTTP. + + Args: + request (~.session.FulfillIntentRequest): + The request object. Request of [FulfillIntent][] + 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: + ~.session.FulfillIntentResponse: + Response of [FulfillIntent][] + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{match_intent_request.session=projects/*/locations/*/agents/*/sessions/*}:fulfillIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v3/{match_intent_request.session=projects/*/locations/*/agents/*/environments/*/sessions/*}:fulfillIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_fulfill_intent(request, metadata) + pb_request = session.FulfillIntentRequest.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["$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 = session.FulfillIntentResponse() + pb_resp = session.FulfillIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_fulfill_intent(resp) + return resp + + class _MatchIntent(SessionsRestStub): + def __hash__(self): + return hash("MatchIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session.MatchIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session.MatchIntentResponse: + r"""Call the match intent method over HTTP. + + Args: + request (~.session.MatchIntentRequest): + The request object. Request of [MatchIntent][]. + 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: + ~.session.MatchIntentResponse: + Response of [MatchIntent][]. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{session=projects/*/locations/*/agents/*/sessions/*}:matchIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v3/{session=projects/*/locations/*/agents/*/environments/*/sessions/*}:matchIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_match_intent(request, metadata) + pb_request = session.MatchIntentRequest.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 = session.MatchIntentResponse() + pb_resp = session.MatchIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_match_intent(resp) + return resp + + class _StreamingDetectIntent(SessionsRestStub): + def __hash__(self): + return hash("StreamingDetectIntent") + + def __call__( + self, + request: session.StreamingDetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> rest_streaming.ResponseIterator: + raise NotImplementedError( + "Method StreamingDetectIntent is not available over REST transport" + ) + + @property + def detect_intent( + self, + ) -> Callable[[session.DetectIntentRequest], session.DetectIntentResponse]: + # 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._DetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def fulfill_intent( + self, + ) -> Callable[[session.FulfillIntentRequest], session.FulfillIntentResponse]: + # 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._FulfillIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def match_intent( + self, + ) -> Callable[[session.MatchIntentRequest], session.MatchIntentResponse]: + # 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._MatchIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def streaming_detect_intent( + self, + ) -> Callable[ + [session.StreamingDetectIntentRequest], session.StreamingDetectIntentResponse + ]: + # 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._StreamingDetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/client.py b/google/cloud/dialogflowcx_v3/services/test_cases/client.py index 9ff4cc8a..7387bd63 100644 --- a/google/cloud/dialogflowcx_v3/services/test_cases/client.py +++ b/google/cloud/dialogflowcx_v3/services/test_cases/client.py @@ -58,6 +58,7 @@ from .transports.base import TestCasesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import TestCasesGrpcTransport from .transports.grpc_asyncio import TestCasesGrpcAsyncIOTransport +from .transports.rest import TestCasesRestTransport class TestCasesClientMeta(type): @@ -71,6 +72,7 @@ class TestCasesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] _transport_registry["grpc"] = TestCasesGrpcTransport _transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport + _transport_registry["rest"] = TestCasesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py index 10d2c977..0b296261 100644 --- a/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py @@ -19,15 +19,20 @@ from .base import TestCasesTransport from .grpc import TestCasesGrpcTransport from .grpc_asyncio import TestCasesGrpcAsyncIOTransport +from .rest import TestCasesRestTransport +from .rest import TestCasesRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] _transport_registry["grpc"] = TestCasesGrpcTransport _transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport +_transport_registry["rest"] = TestCasesRestTransport __all__ = ( "TestCasesTransport", "TestCasesGrpcTransport", "TestCasesGrpcAsyncIOTransport", + "TestCasesRestTransport", + "TestCasesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/transports/rest.py b/google/cloud/dialogflowcx_v3/services/test_cases/transports/rest.py new file mode 100644 index 00000000..8bd0f4ed --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/transports/rest.py @@ -0,0 +1,2295 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import TestCasesTransport, 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 TestCasesRestInterceptor: + """Interceptor for TestCases. + + 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 TestCasesRestTransport. + + .. code-block:: python + class MyCustomTestCasesInterceptor(TestCasesRestInterceptor): + def pre_batch_delete_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_batch_run_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_run_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_calculate_coverage(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_calculate_coverage(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_export_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_test_case_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_test_case_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_test_case_results(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_test_case_results(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_run_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_run_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + transport = TestCasesRestTransport(interceptor=MyCustomTestCasesInterceptor()) + client = TestCasesClient(transport=transport) + + + """ + + def pre_batch_delete_test_cases( + self, + request: test_case.BatchDeleteTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.BatchDeleteTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def pre_batch_run_test_cases( + self, + request: test_case.BatchRunTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.BatchRunTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_run_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_batch_run_test_cases( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_run_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_calculate_coverage( + self, + request: test_case.CalculateCoverageRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.CalculateCoverageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for calculate_coverage + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_calculate_coverage( + self, response: test_case.CalculateCoverageResponse + ) -> test_case.CalculateCoverageResponse: + """Post-rpc interceptor for calculate_coverage + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_create_test_case( + self, + request: gcdc_test_case.CreateTestCaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_test_case.CreateTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_create_test_case( + self, response: gcdc_test_case.TestCase + ) -> gcdc_test_case.TestCase: + """Post-rpc interceptor for create_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_export_test_cases( + self, + request: test_case.ExportTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ExportTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_export_test_cases( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_get_test_case( + self, request: test_case.GetTestCaseRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[test_case.GetTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_test_case(self, response: test_case.TestCase) -> test_case.TestCase: + """Post-rpc interceptor for get_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_get_test_case_result( + self, + request: test_case.GetTestCaseResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.GetTestCaseResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_test_case_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_test_case_result( + self, response: test_case.TestCaseResult + ) -> test_case.TestCaseResult: + """Post-rpc interceptor for get_test_case_result + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_import_test_cases( + self, + request: test_case.ImportTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ImportTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_import_test_cases( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_test_case_results( + self, + request: test_case.ListTestCaseResultsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ListTestCaseResultsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_test_case_results + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_test_case_results( + self, response: test_case.ListTestCaseResultsResponse + ) -> test_case.ListTestCaseResultsResponse: + """Post-rpc interceptor for list_test_case_results + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_test_cases( + self, + request: test_case.ListTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ListTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_test_cases( + self, response: test_case.ListTestCasesResponse + ) -> test_case.ListTestCasesResponse: + """Post-rpc interceptor for list_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_run_test_case( + self, request: test_case.RunTestCaseRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[test_case.RunTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for run_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_run_test_case( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for run_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_update_test_case( + self, + request: gcdc_test_case.UpdateTestCaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_test_case.UpdateTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_update_test_case( + self, response: gcdc_test_case.TestCase + ) -> gcdc_test_case.TestCase: + """Post-rpc interceptor for update_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the TestCases 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class TestCasesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: TestCasesRestInterceptor + + +class TestCasesRestTransport(TestCasesTransport): + """REST backend transport for TestCases. + + Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3.TestCaseResult]. + + 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 = "dialogflow.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[TestCasesRestInterceptor] = 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 TestCasesRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/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="v3", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _BatchDeleteTestCases(TestCasesRestStub): + def __hash__(self): + return hash("BatchDeleteTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.BatchDeleteTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the batch delete test cases method over HTTP. + + Args: + request (~.test_case.BatchDeleteTestCasesRequest): + The request object. The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchDeleteTestCases]. + + 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": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/testCases:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_test_cases( + request, metadata + ) + pb_request = test_case.BatchDeleteTestCasesRequest.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) + + class _BatchRunTestCases(TestCasesRestStub): + def __hash__(self): + return hash("BatchRunTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.BatchRunTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch run test cases method over HTTP. + + Args: + request (~.test_case.BatchRunTestCasesRequest): + The request object. The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + 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": "/v3/{parent=projects/*/locations/*/agents/*}/testCases:batchRun", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_run_test_cases( + request, metadata + ) + pb_request = test_case.BatchRunTestCasesRequest.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_batch_run_test_cases(resp) + return resp + + class _CalculateCoverage(TestCasesRestStub): + def __hash__(self): + return hash("CalculateCoverage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "type": {}, + } + + @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: test_case.CalculateCoverageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.CalculateCoverageResponse: + r"""Call the calculate coverage method over HTTP. + + Args: + request (~.test_case.CalculateCoverageRequest): + The request object. The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + 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: + ~.test_case.CalculateCoverageResponse: + The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{agent=projects/*/locations/*/agents/*}/testCases:calculateCoverage", + }, + ] + request, metadata = self._interceptor.pre_calculate_coverage( + request, metadata + ) + pb_request = test_case.CalculateCoverageRequest.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 = test_case.CalculateCoverageResponse() + pb_resp = test_case.CalculateCoverageResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_calculate_coverage(resp) + return resp + + class _CreateTestCase(TestCasesRestStub): + def __hash__(self): + return hash("CreateTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_test_case.CreateTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Call the create test case method over HTTP. + + Args: + request (~.gcdc_test_case.CreateTestCaseRequest): + The request object. The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3.TestCases.CreateTestCase]. + + 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: + ~.gcdc_test_case.TestCase: + Represents a test case. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/testCases", + "body": "test_case", + }, + ] + request, metadata = self._interceptor.pre_create_test_case( + request, metadata + ) + pb_request = gcdc_test_case.CreateTestCaseRequest.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 = gcdc_test_case.TestCase() + pb_resp = gcdc_test_case.TestCase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_test_case(resp) + return resp + + class _ExportTestCases(TestCasesRestStub): + def __hash__(self): + return hash("ExportTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ExportTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export test cases method over HTTP. + + Args: + request (~.test_case.ExportTestCasesRequest): + The request object. The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + 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": "/v3/{parent=projects/*/locations/*/agents/*}/testCases:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_test_cases( + request, metadata + ) + pb_request = test_case.ExportTestCasesRequest.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_test_cases(resp) + return resp + + class _GetTestCase(TestCasesRestStub): + def __hash__(self): + return hash("GetTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.GetTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCase: + r"""Call the get test case method over HTTP. + + Args: + request (~.test_case.GetTestCaseRequest): + The request object. The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3.TestCases.GetTestCase]. + + 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: + ~.test_case.TestCase: + Represents a test case. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/testCases/*}", + }, + ] + request, metadata = self._interceptor.pre_get_test_case(request, metadata) + pb_request = test_case.GetTestCaseRequest.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 = test_case.TestCase() + pb_resp = test_case.TestCase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_test_case(resp) + return resp + + class _GetTestCaseResult(TestCasesRestStub): + def __hash__(self): + return hash("GetTestCaseResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.GetTestCaseResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCaseResult: + r"""Call the get test case result method over HTTP. + + Args: + request (~.test_case.GetTestCaseResultRequest): + The request object. The request message for + [TestCases.GetTestCaseResult][google.cloud.dialogflow.cx.v3.TestCases.GetTestCaseResult]. + + 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: + ~.test_case.TestCaseResult: + Represents a result from running a + test case in an agent environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/testCases/*/results/*}", + }, + ] + request, metadata = self._interceptor.pre_get_test_case_result( + request, metadata + ) + pb_request = test_case.GetTestCaseResultRequest.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 = test_case.TestCaseResult() + pb_resp = test_case.TestCaseResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_test_case_result(resp) + return resp + + class _ImportTestCases(TestCasesRestStub): + def __hash__(self): + return hash("ImportTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ImportTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import test cases method over HTTP. + + Args: + request (~.test_case.ImportTestCasesRequest): + The request object. The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + 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": "/v3/{parent=projects/*/locations/*/agents/*}/testCases:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_test_cases( + request, metadata + ) + pb_request = test_case.ImportTestCasesRequest.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_import_test_cases(resp) + return resp + + class _ListTestCaseResults(TestCasesRestStub): + def __hash__(self): + return hash("ListTestCaseResults") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ListTestCaseResultsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.ListTestCaseResultsResponse: + r"""Call the list test case results method over HTTP. + + Args: + request (~.test_case.ListTestCaseResultsRequest): + The request object. The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + + 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: + ~.test_case.ListTestCaseResultsResponse: + The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/testCases/*}/results", + }, + ] + request, metadata = self._interceptor.pre_list_test_case_results( + request, metadata + ) + pb_request = test_case.ListTestCaseResultsRequest.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 = test_case.ListTestCaseResultsResponse() + pb_resp = test_case.ListTestCaseResultsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_test_case_results(resp) + return resp + + class _ListTestCases(TestCasesRestStub): + def __hash__(self): + return hash("ListTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ListTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.ListTestCasesResponse: + r"""Call the list test cases method over HTTP. + + Args: + request (~.test_case.ListTestCasesRequest): + The request object. The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + + 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: + ~.test_case.ListTestCasesResponse: + The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/testCases", + }, + ] + request, metadata = self._interceptor.pre_list_test_cases(request, metadata) + pb_request = test_case.ListTestCasesRequest.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 = test_case.ListTestCasesResponse() + pb_resp = test_case.ListTestCasesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_test_cases(resp) + return resp + + class _RunTestCase(TestCasesRestStub): + def __hash__(self): + return hash("RunTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.RunTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the run test case method over HTTP. + + Args: + request (~.test_case.RunTestCaseRequest): + The request object. The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/testCases/*}:run", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_run_test_case(request, metadata) + pb_request = test_case.RunTestCaseRequest.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_run_test_case(resp) + return resp + + class _UpdateTestCase(TestCasesRestStub): + def __hash__(self): + return hash("UpdateTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_test_case.UpdateTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Call the update test case method over HTTP. + + Args: + request (~.gcdc_test_case.UpdateTestCaseRequest): + The request object. The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3.TestCases.UpdateTestCase]. + + 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: + ~.gcdc_test_case.TestCase: + Represents a test case. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{test_case.name=projects/*/locations/*/agents/*/testCases/*}", + "body": "test_case", + }, + ] + request, metadata = self._interceptor.pre_update_test_case( + request, metadata + ) + pb_request = gcdc_test_case.UpdateTestCaseRequest.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 = gcdc_test_case.TestCase() + pb_resp = gcdc_test_case.TestCase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_test_case(resp) + return resp + + @property + def batch_delete_test_cases( + self, + ) -> Callable[[test_case.BatchDeleteTestCasesRequest], 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._BatchDeleteTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_run_test_cases( + self, + ) -> Callable[[test_case.BatchRunTestCasesRequest], 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._BatchRunTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def calculate_coverage( + self, + ) -> Callable[ + [test_case.CalculateCoverageRequest], test_case.CalculateCoverageResponse + ]: + # 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._CalculateCoverage(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_test_case( + self, + ) -> Callable[[gcdc_test_case.CreateTestCaseRequest], gcdc_test_case.TestCase]: + # 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._CreateTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_test_cases( + self, + ) -> Callable[[test_case.ExportTestCasesRequest], 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._ExportTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_test_case( + self, + ) -> Callable[[test_case.GetTestCaseRequest], test_case.TestCase]: + # 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._GetTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_test_case_result( + self, + ) -> Callable[[test_case.GetTestCaseResultRequest], test_case.TestCaseResult]: + # 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._GetTestCaseResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_test_cases( + self, + ) -> Callable[[test_case.ImportTestCasesRequest], 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._ImportTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_test_case_results( + self, + ) -> Callable[ + [test_case.ListTestCaseResultsRequest], test_case.ListTestCaseResultsResponse + ]: + # 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._ListTestCaseResults(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_test_cases( + self, + ) -> Callable[[test_case.ListTestCasesRequest], test_case.ListTestCasesResponse]: + # 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._ListTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def run_test_case( + self, + ) -> Callable[[test_case.RunTestCaseRequest], 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._RunTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_test_case( + self, + ) -> Callable[[gcdc_test_case.UpdateTestCaseRequest], gcdc_test_case.TestCase]: + # 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._UpdateTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(TestCasesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(TestCasesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(TestCasesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(TestCasesRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(TestCasesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("TestCasesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py index ad244522..13d04425 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py @@ -58,6 +58,7 @@ from .transports.base import TransitionRouteGroupsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import TransitionRouteGroupsGrpcTransport from .transports.grpc_asyncio import TransitionRouteGroupsGrpcAsyncIOTransport +from .transports.rest import TransitionRouteGroupsRestTransport class TransitionRouteGroupsClientMeta(type): @@ -73,6 +74,7 @@ class TransitionRouteGroupsClientMeta(type): ) # type: Dict[str, Type[TransitionRouteGroupsTransport]] _transport_registry["grpc"] = TransitionRouteGroupsGrpcTransport _transport_registry["grpc_asyncio"] = TransitionRouteGroupsGrpcAsyncIOTransport + _transport_registry["rest"] = TransitionRouteGroupsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/__init__.py index ed445782..a9ee37b8 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/__init__.py @@ -19,6 +19,8 @@ from .base import TransitionRouteGroupsTransport from .grpc import TransitionRouteGroupsGrpcTransport from .grpc_asyncio import TransitionRouteGroupsGrpcAsyncIOTransport +from .rest import TransitionRouteGroupsRestTransport +from .rest import TransitionRouteGroupsRestInterceptor # Compile a registry of transports. @@ -27,9 +29,12 @@ ) # type: Dict[str, Type[TransitionRouteGroupsTransport]] _transport_registry["grpc"] = TransitionRouteGroupsGrpcTransport _transport_registry["grpc_asyncio"] = TransitionRouteGroupsGrpcAsyncIOTransport +_transport_registry["rest"] = TransitionRouteGroupsRestTransport __all__ = ( "TransitionRouteGroupsTransport", "TransitionRouteGroupsGrpcTransport", "TransitionRouteGroupsGrpcAsyncIOTransport", + "TransitionRouteGroupsRestTransport", + "TransitionRouteGroupsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/rest.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/rest.py new file mode 100644 index 00000000..fe8864f9 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/rest.py @@ -0,0 +1,1343 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import transition_route_group +from google.cloud.dialogflowcx_v3.types import ( + transition_route_group as gcdc_transition_route_group, +) +from google.protobuf import empty_pb2 # type: ignore + +from .base import ( + TransitionRouteGroupsTransport, + 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 TransitionRouteGroupsRestInterceptor: + """Interceptor for TransitionRouteGroups. + + 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 TransitionRouteGroupsRestTransport. + + .. code-block:: python + class MyCustomTransitionRouteGroupsInterceptor(TransitionRouteGroupsRestInterceptor): + def pre_create_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_transition_route_group(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_transition_route_group(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_transition_route_groups(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_transition_route_groups(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_transition_route_group(self, response): + logging.log(f"Received response: {response}") + return response + + transport = TransitionRouteGroupsRestTransport(interceptor=MyCustomTransitionRouteGroupsInterceptor()) + client = TransitionRouteGroupsClient(transport=transport) + + + """ + + def pre_create_transition_route_group( + self, + request: gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_create_transition_route_group( + self, response: gcdc_transition_route_group.TransitionRouteGroup + ) -> gcdc_transition_route_group.TransitionRouteGroup: + """Post-rpc interceptor for create_transition_route_group + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_delete_transition_route_group( + self, + request: transition_route_group.DeleteTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + transition_route_group.DeleteTransitionRouteGroupRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for delete_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def pre_get_transition_route_group( + self, + request: transition_route_group.GetTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + transition_route_group.GetTransitionRouteGroupRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_get_transition_route_group( + self, response: transition_route_group.TransitionRouteGroup + ) -> transition_route_group.TransitionRouteGroup: + """Post-rpc interceptor for get_transition_route_group + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_list_transition_route_groups( + self, + request: transition_route_group.ListTransitionRouteGroupsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + transition_route_group.ListTransitionRouteGroupsRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for list_transition_route_groups + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_list_transition_route_groups( + self, response: transition_route_group.ListTransitionRouteGroupsResponse + ) -> transition_route_group.ListTransitionRouteGroupsResponse: + """Post-rpc interceptor for list_transition_route_groups + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_update_transition_route_group( + self, + request: gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_update_transition_route_group( + self, response: gcdc_transition_route_group.TransitionRouteGroup + ) -> gcdc_transition_route_group.TransitionRouteGroup: + """Post-rpc interceptor for update_transition_route_group + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class TransitionRouteGroupsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: TransitionRouteGroupsRestInterceptor + + +class TransitionRouteGroupsRestTransport(TransitionRouteGroupsTransport): + """REST backend transport for TransitionRouteGroups. + + Service for managing + [TransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. + + 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 = "dialogflow.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[TransitionRouteGroupsRestInterceptor] = 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 TransitionRouteGroupsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("CreateTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_transition_route_group.TransitionRouteGroup: + r"""Call the create transition route + group method over HTTP. + + Args: + request (~.gcdc_transition_route_group.CreateTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.CreateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.CreateTransitionRouteGroup]. + + 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: + ~.gcdc_transition_route_group.TransitionRouteGroup: + An TransitionRouteGroup represents a group of + [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups", + "body": "transition_route_group", + }, + ] + request, metadata = self._interceptor.pre_create_transition_route_group( + request, metadata + ) + pb_request = ( + gcdc_transition_route_group.CreateTransitionRouteGroupRequest.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 = gcdc_transition_route_group.TransitionRouteGroup() + pb_resp = gcdc_transition_route_group.TransitionRouteGroup.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_transition_route_group(resp) + return resp + + class _DeleteTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("DeleteTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: transition_route_group.DeleteTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete transition route + group method over HTTP. + + Args: + request (~.transition_route_group.DeleteTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.DeleteTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.DeleteTransitionRouteGroup]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_transition_route_group( + request, metadata + ) + pb_request = transition_route_group.DeleteTransitionRouteGroupRequest.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 _GetTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("GetTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: transition_route_group.GetTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> transition_route_group.TransitionRouteGroup: + r"""Call the get transition route + group method over HTTP. + + Args: + request (~.transition_route_group.GetTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.GetTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.GetTransitionRouteGroup]. + + 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: + ~.transition_route_group.TransitionRouteGroup: + An TransitionRouteGroup represents a group of + [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}", + }, + ] + request, metadata = self._interceptor.pre_get_transition_route_group( + request, metadata + ) + pb_request = transition_route_group.GetTransitionRouteGroupRequest.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 = transition_route_group.TransitionRouteGroup() + pb_resp = transition_route_group.TransitionRouteGroup.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_transition_route_group(resp) + return resp + + class _ListTransitionRouteGroups(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("ListTransitionRouteGroups") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: transition_route_group.ListTransitionRouteGroupsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> transition_route_group.ListTransitionRouteGroupsResponse: + r"""Call the list transition route + groups method over HTTP. + + Args: + request (~.transition_route_group.ListTransitionRouteGroupsRequest): + The request object. The request message for + [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. + + 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: + ~.transition_route_group.ListTransitionRouteGroupsResponse: + The response message for + [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups", + }, + ] + request, metadata = self._interceptor.pre_list_transition_route_groups( + request, metadata + ) + pb_request = transition_route_group.ListTransitionRouteGroupsRequest.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 = transition_route_group.ListTransitionRouteGroupsResponse() + pb_resp = transition_route_group.ListTransitionRouteGroupsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_transition_route_groups(resp) + return resp + + class _UpdateTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("UpdateTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_transition_route_group.TransitionRouteGroup: + r"""Call the update transition route + group method over HTTP. + + Args: + request (~.gcdc_transition_route_group.UpdateTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.UpdateTransitionRouteGroup]. + + 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: + ~.gcdc_transition_route_group.TransitionRouteGroup: + An TransitionRouteGroup represents a group of + [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{transition_route_group.name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}", + "body": "transition_route_group", + }, + ] + request, metadata = self._interceptor.pre_update_transition_route_group( + request, metadata + ) + pb_request = ( + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest.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 = gcdc_transition_route_group.TransitionRouteGroup() + pb_resp = gcdc_transition_route_group.TransitionRouteGroup.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_transition_route_group(resp) + return resp + + @property + def create_transition_route_group( + self, + ) -> Callable[ + [gcdc_transition_route_group.CreateTransitionRouteGroupRequest], + gcdc_transition_route_group.TransitionRouteGroup, + ]: + # 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._CreateTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_transition_route_group( + self, + ) -> Callable[ + [transition_route_group.DeleteTransitionRouteGroupRequest], 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._DeleteTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_transition_route_group( + self, + ) -> Callable[ + [transition_route_group.GetTransitionRouteGroupRequest], + transition_route_group.TransitionRouteGroup, + ]: + # 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._GetTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_transition_route_groups( + self, + ) -> Callable[ + [transition_route_group.ListTransitionRouteGroupsRequest], + transition_route_group.ListTransitionRouteGroupsResponse, + ]: + # 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._ListTransitionRouteGroups(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_transition_route_group( + self, + ) -> Callable[ + [gcdc_transition_route_group.UpdateTransitionRouteGroupRequest], + gcdc_transition_route_group.TransitionRouteGroup, + ]: + # 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._UpdateTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(TransitionRouteGroupsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(TransitionRouteGroupsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(TransitionRouteGroupsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(TransitionRouteGroupsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(TransitionRouteGroupsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("TransitionRouteGroupsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/versions/client.py b/google/cloud/dialogflowcx_v3/services/versions/client.py index 1f816f46..d3cd81bc 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/client.py +++ b/google/cloud/dialogflowcx_v3/services/versions/client.py @@ -61,6 +61,7 @@ from .transports.base import VersionsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import VersionsGrpcTransport from .transports.grpc_asyncio import VersionsGrpcAsyncIOTransport +from .transports.rest import VersionsRestTransport class VersionsClientMeta(type): @@ -74,6 +75,7 @@ class VersionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport + _transport_registry["rest"] = VersionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/versions/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/versions/transports/__init__.py index ab80b3b5..780f6ec5 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/versions/transports/__init__.py @@ -19,15 +19,20 @@ from .base import VersionsTransport from .grpc import VersionsGrpcTransport from .grpc_asyncio import VersionsGrpcAsyncIOTransport +from .rest import VersionsRestTransport +from .rest import VersionsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport +_transport_registry["rest"] = VersionsRestTransport __all__ = ( "VersionsTransport", "VersionsGrpcTransport", "VersionsGrpcAsyncIOTransport", + "VersionsRestTransport", + "VersionsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/versions/transports/rest.py b/google/cloud/dialogflowcx_v3/services/versions/transports/rest.py new file mode 100644 index 00000000..cefc398b --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/versions/transports/rest.py @@ -0,0 +1,1598 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import version +from google.cloud.dialogflowcx_v3.types import version as gcdc_version +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import VersionsTransport, 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 VersionsRestInterceptor: + """Interceptor for Versions. + + 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 VersionsRestTransport. + + .. code-block:: python + class MyCustomVersionsInterceptor(VersionsRestInterceptor): + def pre_compare_versions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_compare_versions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_versions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_versions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_load_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_load_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_version(self, response): + logging.log(f"Received response: {response}") + return response + + transport = VersionsRestTransport(interceptor=MyCustomVersionsInterceptor()) + client = VersionsClient(transport=transport) + + + """ + + def pre_compare_versions( + self, + request: version.CompareVersionsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[version.CompareVersionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for compare_versions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_compare_versions( + self, response: version.CompareVersionsResponse + ) -> version.CompareVersionsResponse: + """Post-rpc interceptor for compare_versions + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_create_version( + self, + request: gcdc_version.CreateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_version.CreateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_create_version( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_delete_version( + self, request: version.DeleteVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.DeleteVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def pre_get_version( + self, request: version.GetVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.GetVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_version(self, response: version.Version) -> version.Version: + """Post-rpc interceptor for get_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_versions( + self, request: version.ListVersionsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.ListVersionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_versions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_versions( + self, response: version.ListVersionsResponse + ) -> version.ListVersionsResponse: + """Post-rpc interceptor for list_versions + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_load_version( + self, request: version.LoadVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.LoadVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for load_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_load_version( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for load_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_update_version( + self, + request: gcdc_version.UpdateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_version.UpdateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_update_version( + self, response: gcdc_version.Version + ) -> gcdc_version.Version: + """Post-rpc interceptor for update_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class VersionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: VersionsRestInterceptor + + +class VersionsRestTransport(VersionsTransport): + """REST backend transport for Versions. + + Service for managing + [Versions][google.cloud.dialogflow.cx.v3.Version]. + + 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 = "dialogflow.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[VersionsRestInterceptor] = 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 VersionsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/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="v3", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CompareVersions(VersionsRestStub): + def __hash__(self): + return hash("CompareVersions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.CompareVersionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.CompareVersionsResponse: + r"""Call the compare versions method over HTTP. + + Args: + request (~.version.CompareVersionsRequest): + The request object. The request message for + [Versions.CompareVersions][google.cloud.dialogflow.cx.v3.Versions.CompareVersions]. + + 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: + ~.version.CompareVersionsResponse: + The response message for + [Versions.CompareVersions][google.cloud.dialogflow.cx.v3.Versions.CompareVersions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{base_version=projects/*/locations/*/agents/*/flows/*/versions/*}:compareVersions", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_compare_versions( + request, metadata + ) + pb_request = version.CompareVersionsRequest.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 = version.CompareVersionsResponse() + pb_resp = version.CompareVersionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_compare_versions(resp) + return resp + + class _CreateVersion(VersionsRestStub): + def __hash__(self): + return hash("CreateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_version.CreateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create version method over HTTP. + + Args: + request (~.gcdc_version.CreateVersionRequest): + The request object. The request message for + [Versions.CreateVersion][google.cloud.dialogflow.cx.v3.Versions.CreateVersion]. + + 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": "/v3/{parent=projects/*/locations/*/agents/*/flows/*}/versions", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_create_version(request, metadata) + pb_request = gcdc_version.CreateVersionRequest.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_create_version(resp) + return resp + + class _DeleteVersion(VersionsRestStub): + def __hash__(self): + return hash("DeleteVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.DeleteVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete version method over HTTP. + + Args: + request (~.version.DeleteVersionRequest): + The request object. The request message for + [Versions.DeleteVersion][google.cloud.dialogflow.cx.v3.Versions.DeleteVersion]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_version(request, metadata) + pb_request = version.DeleteVersionRequest.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 _GetVersion(VersionsRestStub): + def __hash__(self): + return hash("GetVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.GetVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.Version: + r"""Call the get version method over HTTP. + + Args: + request (~.version.GetVersionRequest): + The request object. The request message for + [Versions.GetVersion][google.cloud.dialogflow.cx.v3.Versions.GetVersion]. + + 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: + ~.version.Version: + Represents a version of a flow. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/flows/*/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_get_version(request, metadata) + pb_request = version.GetVersionRequest.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 = version.Version() + pb_resp = version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_version(resp) + return resp + + class _ListVersions(VersionsRestStub): + def __hash__(self): + return hash("ListVersions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.ListVersionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.ListVersionsResponse: + r"""Call the list versions method over HTTP. + + Args: + request (~.version.ListVersionsRequest): + The request object. The request message for + [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. + + 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: + ~.version.ListVersionsResponse: + The response message for + [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*/flows/*}/versions", + }, + ] + request, metadata = self._interceptor.pre_list_versions(request, metadata) + pb_request = version.ListVersionsRequest.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 = version.ListVersionsResponse() + pb_resp = version.ListVersionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_versions(resp) + return resp + + class _LoadVersion(VersionsRestStub): + def __hash__(self): + return hash("LoadVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.LoadVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the load version method over HTTP. + + Args: + request (~.version.LoadVersionRequest): + The request object. The request message for + [Versions.LoadVersion][google.cloud.dialogflow.cx.v3.Versions.LoadVersion]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/flows/*/versions/*}:load", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_load_version(request, metadata) + pb_request = version.LoadVersionRequest.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_load_version(resp) + return resp + + class _UpdateVersion(VersionsRestStub): + def __hash__(self): + return hash("UpdateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_version.UpdateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_version.Version: + r"""Call the update version method over HTTP. + + Args: + request (~.gcdc_version.UpdateVersionRequest): + The request object. The request message for + [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3.Versions.UpdateVersion]. + + 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: + ~.gcdc_version.Version: + Represents a version of a flow. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{version.name=projects/*/locations/*/agents/*/flows/*/versions/*}", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_update_version(request, metadata) + pb_request = gcdc_version.UpdateVersionRequest.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 = gcdc_version.Version() + pb_resp = gcdc_version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_version(resp) + return resp + + @property + def compare_versions( + self, + ) -> Callable[[version.CompareVersionsRequest], version.CompareVersionsResponse]: + # 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._CompareVersions(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_version( + self, + ) -> Callable[[gcdc_version.CreateVersionRequest], 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._CreateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_version( + self, + ) -> Callable[[version.DeleteVersionRequest], 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._DeleteVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_version(self) -> Callable[[version.GetVersionRequest], version.Version]: + # 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._GetVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_versions( + self, + ) -> Callable[[version.ListVersionsRequest], version.ListVersionsResponse]: + # 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._ListVersions(self._session, self._host, self._interceptor) # type: ignore + + @property + def load_version( + self, + ) -> Callable[[version.LoadVersionRequest], 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._LoadVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_version( + self, + ) -> Callable[[gcdc_version.UpdateVersionRequest], gcdc_version.Version]: + # 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._UpdateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(VersionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(VersionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(VersionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(VersionsRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(VersionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("VersionsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/client.py b/google/cloud/dialogflowcx_v3/services/webhooks/client.py index 1fc4347a..324a5e91 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/client.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/client.py @@ -56,6 +56,7 @@ from .transports.base import WebhooksTransport, DEFAULT_CLIENT_INFO from .transports.grpc import WebhooksGrpcTransport from .transports.grpc_asyncio import WebhooksGrpcAsyncIOTransport +from .transports.rest import WebhooksRestTransport class WebhooksClientMeta(type): @@ -69,6 +70,7 @@ class WebhooksClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[WebhooksTransport]] _transport_registry["grpc"] = WebhooksGrpcTransport _transport_registry["grpc_asyncio"] = WebhooksGrpcAsyncIOTransport + _transport_registry["rest"] = WebhooksRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/webhooks/transports/__init__.py index 2beebd10..bd4c8fb7 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/transports/__init__.py @@ -19,15 +19,20 @@ from .base import WebhooksTransport from .grpc import WebhooksGrpcTransport from .grpc_asyncio import WebhooksGrpcAsyncIOTransport +from .rest import WebhooksRestTransport +from .rest import WebhooksRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[WebhooksTransport]] _transport_registry["grpc"] = WebhooksGrpcTransport _transport_registry["grpc_asyncio"] = WebhooksGrpcAsyncIOTransport +_transport_registry["rest"] = WebhooksRestTransport __all__ = ( "WebhooksTransport", "WebhooksGrpcTransport", "WebhooksGrpcAsyncIOTransport", + "WebhooksRestTransport", + "WebhooksRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/transports/rest.py b/google/cloud/dialogflowcx_v3/services/webhooks/transports/rest.py new file mode 100644 index 00000000..63c09dbd --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/webhooks/transports/rest.py @@ -0,0 +1,1280 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3.types import webhook +from google.cloud.dialogflowcx_v3.types import webhook as gcdc_webhook +from google.protobuf import empty_pb2 # type: ignore + +from .base import WebhooksTransport, 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 WebhooksRestInterceptor: + """Interceptor for Webhooks. + + 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 WebhooksRestTransport. + + .. code-block:: python + class MyCustomWebhooksInterceptor(WebhooksRestInterceptor): + def pre_create_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_webhook(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_webhook(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_webhooks(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_webhooks(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_webhook(self, response): + logging.log(f"Received response: {response}") + return response + + transport = WebhooksRestTransport(interceptor=MyCustomWebhooksInterceptor()) + client = WebhooksClient(transport=transport) + + + """ + + def pre_create_webhook( + self, + request: gcdc_webhook.CreateWebhookRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_webhook.CreateWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_create_webhook( + self, response: gcdc_webhook.Webhook + ) -> gcdc_webhook.Webhook: + """Post-rpc interceptor for create_webhook + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_delete_webhook( + self, request: webhook.DeleteWebhookRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[webhook.DeleteWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def pre_get_webhook( + self, request: webhook.GetWebhookRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[webhook.GetWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_get_webhook(self, response: webhook.Webhook) -> webhook.Webhook: + """Post-rpc interceptor for get_webhook + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_list_webhooks( + self, request: webhook.ListWebhooksRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[webhook.ListWebhooksRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_webhooks + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_list_webhooks( + self, response: webhook.ListWebhooksResponse + ) -> webhook.ListWebhooksResponse: + """Post-rpc interceptor for list_webhooks + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_update_webhook( + self, + request: gcdc_webhook.UpdateWebhookRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_webhook.UpdateWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_update_webhook( + self, response: gcdc_webhook.Webhook + ) -> gcdc_webhook.Webhook: + """Post-rpc interceptor for update_webhook + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Webhooks 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class WebhooksRestStub: + _session: AuthorizedSession + _host: str + _interceptor: WebhooksRestInterceptor + + +class WebhooksRestTransport(WebhooksTransport): + """REST backend transport for Webhooks. + + Service for managing + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook]. + + 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 = "dialogflow.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[WebhooksRestInterceptor] = 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 WebhooksRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateWebhook(WebhooksRestStub): + def __hash__(self): + return hash("CreateWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_webhook.CreateWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_webhook.Webhook: + r"""Call the create webhook method over HTTP. + + Args: + request (~.gcdc_webhook.CreateWebhookRequest): + The request object. The request message for + [Webhooks.CreateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.CreateWebhook]. + + 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: + ~.gcdc_webhook.Webhook: + Webhooks host the developer's + business logic. During a session, + webhooks allow the developer to use the + data extracted by Dialogflow's natural + language processing to generate dynamic + responses, validate collected data, or + trigger actions on the backend. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/webhooks", + "body": "webhook", + }, + ] + request, metadata = self._interceptor.pre_create_webhook(request, metadata) + pb_request = gcdc_webhook.CreateWebhookRequest.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 = gcdc_webhook.Webhook() + pb_resp = gcdc_webhook.Webhook.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_webhook(resp) + return resp + + class _DeleteWebhook(WebhooksRestStub): + def __hash__(self): + return hash("DeleteWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: webhook.DeleteWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete webhook method over HTTP. + + Args: + request (~.webhook.DeleteWebhookRequest): + The request object. The request message for + [Webhooks.DeleteWebhook][google.cloud.dialogflow.cx.v3.Webhooks.DeleteWebhook]. + + 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": "/v3/{name=projects/*/locations/*/agents/*/webhooks/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_webhook(request, metadata) + pb_request = webhook.DeleteWebhookRequest.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 _GetWebhook(WebhooksRestStub): + def __hash__(self): + return hash("GetWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: webhook.GetWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> webhook.Webhook: + r"""Call the get webhook method over HTTP. + + Args: + request (~.webhook.GetWebhookRequest): + The request object. The request message for + [Webhooks.GetWebhook][google.cloud.dialogflow.cx.v3.Webhooks.GetWebhook]. + + 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: + ~.webhook.Webhook: + Webhooks host the developer's + business logic. During a session, + webhooks allow the developer to use the + data extracted by Dialogflow's natural + language processing to generate dynamic + responses, validate collected data, or + trigger actions on the backend. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/agents/*/webhooks/*}", + }, + ] + request, metadata = self._interceptor.pre_get_webhook(request, metadata) + pb_request = webhook.GetWebhookRequest.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 = webhook.Webhook() + pb_resp = webhook.Webhook.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_webhook(resp) + return resp + + class _ListWebhooks(WebhooksRestStub): + def __hash__(self): + return hash("ListWebhooks") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: webhook.ListWebhooksRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> webhook.ListWebhooksResponse: + r"""Call the list webhooks method over HTTP. + + Args: + request (~.webhook.ListWebhooksRequest): + The request object. The request message for + [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. + + 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: + ~.webhook.ListWebhooksResponse: + The response message for + [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{parent=projects/*/locations/*/agents/*}/webhooks", + }, + ] + request, metadata = self._interceptor.pre_list_webhooks(request, metadata) + pb_request = webhook.ListWebhooksRequest.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 = webhook.ListWebhooksResponse() + pb_resp = webhook.ListWebhooksResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_webhooks(resp) + return resp + + class _UpdateWebhook(WebhooksRestStub): + def __hash__(self): + return hash("UpdateWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_webhook.UpdateWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_webhook.Webhook: + r"""Call the update webhook method over HTTP. + + Args: + request (~.gcdc_webhook.UpdateWebhookRequest): + The request object. The request message for + [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.UpdateWebhook]. + + 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: + ~.gcdc_webhook.Webhook: + Webhooks host the developer's + business logic. During a session, + webhooks allow the developer to use the + data extracted by Dialogflow's natural + language processing to generate dynamic + responses, validate collected data, or + trigger actions on the backend. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3/{webhook.name=projects/*/locations/*/agents/*/webhooks/*}", + "body": "webhook", + }, + ] + request, metadata = self._interceptor.pre_update_webhook(request, metadata) + pb_request = gcdc_webhook.UpdateWebhookRequest.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 = gcdc_webhook.Webhook() + pb_resp = gcdc_webhook.Webhook.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_webhook(resp) + return resp + + @property + def create_webhook( + self, + ) -> Callable[[gcdc_webhook.CreateWebhookRequest], gcdc_webhook.Webhook]: + # 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._CreateWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_webhook( + self, + ) -> Callable[[webhook.DeleteWebhookRequest], 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._DeleteWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_webhook(self) -> Callable[[webhook.GetWebhookRequest], webhook.Webhook]: + # 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._GetWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_webhooks( + self, + ) -> Callable[[webhook.ListWebhooksRequest], webhook.ListWebhooksResponse]: + # 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._ListWebhooks(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_webhook( + self, + ) -> Callable[[gcdc_webhook.UpdateWebhookRequest], gcdc_webhook.Webhook]: + # 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._UpdateWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(WebhooksRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(WebhooksRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(WebhooksRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(WebhooksRestStub): + 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": "/v3/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(WebhooksRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("WebhooksRestTransport",) diff --git a/google/cloud/dialogflowcx_v3/types/__init__.py b/google/cloud/dialogflowcx_v3/types/__init__.py index fe4a75ea..6f53c3e8 100644 --- a/google/cloud/dialogflowcx_v3/types/__init__.py +++ b/google/cloud/dialogflowcx_v3/types/__init__.py @@ -37,6 +37,7 @@ OutputAudioConfig, SpeechWordInfo, SynthesizeSpeechConfig, + TextToSpeechSettings, VoiceSelectionParams, AudioEncoding, OutputAudioEncoding, @@ -120,6 +121,9 @@ from .fulfillment import ( Fulfillment, ) +from .gcs import ( + GcsDestination, +) from .intent import ( CreateIntentRequest, DeleteIntentRequest, @@ -280,6 +284,7 @@ "OutputAudioConfig", "SpeechWordInfo", "SynthesizeSpeechConfig", + "TextToSpeechSettings", "VoiceSelectionParams", "AudioEncoding", "OutputAudioEncoding", @@ -348,6 +353,7 @@ "UpdateFlowRequest", "ValidateFlowRequest", "Fulfillment", + "GcsDestination", "CreateIntentRequest", "DeleteIntentRequest", "GetIntentRequest", diff --git a/google/cloud/dialogflowcx_v3/types/advanced_settings.py b/google/cloud/dialogflowcx_v3/types/advanced_settings.py index 33e68ea4..973a5319 100644 --- a/google/cloud/dialogflowcx_v3/types/advanced_settings.py +++ b/google/cloud/dialogflowcx_v3/types/advanced_settings.py @@ -13,10 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore +from google.cloud.dialogflowcx_v3.types import gcs + __protobuf__ = proto.module( package="google.cloud.dialogflow.cx.v3", @@ -41,6 +45,13 @@ class AdvancedSettings(proto.Message): Hierarchy: Agent->Flow->Page->Fulfillment/Parameter. Attributes: + audio_export_gcs_destination (google.cloud.dialogflowcx_v3.types.GcsDestination): + If present, incoming audio is exported by + Dialogflow to the configured Google Cloud + Storage destination. Exposed at the following + levels: + - Agent level + - Flow level logging_settings (google.cloud.dialogflowcx_v3.types.AdvancedSettings.LoggingSettings): Settings for logging. Settings for Dialogflow History, Contact Center @@ -70,6 +81,11 @@ class LoggingSettings(proto.Message): number=3, ) + audio_export_gcs_destination: gcs.GcsDestination = proto.Field( + proto.MESSAGE, + number=2, + message=gcs.GcsDestination, + ) logging_settings: LoggingSettings = proto.Field( proto.MESSAGE, number=6, diff --git a/google/cloud/dialogflowcx_v3/types/agent.py b/google/cloud/dialogflowcx_v3/types/agent.py index d3da9422..85ee687d 100644 --- a/google/cloud/dialogflowcx_v3/types/agent.py +++ b/google/cloud/dialogflowcx_v3/types/agent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -20,6 +22,7 @@ from google.cloud.dialogflowcx_v3.types import ( advanced_settings as gcdc_advanced_settings, ) +from google.cloud.dialogflowcx_v3.types import audio_config from google.cloud.dialogflowcx_v3.types import flow from google.protobuf import field_mask_pb2 # type: ignore @@ -139,6 +142,10 @@ class Agent(proto.Message): agent. The settings exposed at the lower level overrides the settings exposed at the higher level. + text_to_speech_settings (google.cloud.dialogflowcx_v3.types.TextToSpeechSettings): + Settings on instructing the speech + synthesizer on how to generate the output audio + content. """ name: str = proto.Field( @@ -199,6 +206,11 @@ class Agent(proto.Message): number=22, message=gcdc_advanced_settings.AdvancedSettings, ) + text_to_speech_settings: audio_config.TextToSpeechSettings = proto.Field( + proto.MESSAGE, + number=31, + message=audio_config.TextToSpeechSettings, + ) class ListAgentsRequest(proto.Message): diff --git a/google/cloud/dialogflowcx_v3/types/audio_config.py b/google/cloud/dialogflowcx_v3/types/audio_config.py index 1bd98426..64f80bb6 100644 --- a/google/cloud/dialogflowcx_v3/types/audio_config.py +++ b/google/cloud/dialogflowcx_v3/types/audio_config.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -32,6 +34,7 @@ "VoiceSelectionParams", "SynthesizeSpeechConfig", "OutputAudioConfig", + "TextToSpeechSettings", }, ) @@ -471,4 +474,25 @@ class OutputAudioConfig(proto.Message): ) +class TextToSpeechSettings(proto.Message): + r"""Settings related to speech generating. + + Attributes: + synthesize_speech_configs (MutableMapping[str, google.cloud.dialogflowcx_v3.types.SynthesizeSpeechConfig]): + Configuration of how speech should be + synthesized, mapping from language + (https://dialogflow.com/docs/reference/language) + to SynthesizeSpeechConfig. + """ + + synthesize_speech_configs: MutableMapping[ + str, "SynthesizeSpeechConfig" + ] = proto.MapField( + proto.STRING, + proto.MESSAGE, + number=1, + message="SynthesizeSpeechConfig", + ) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3/types/changelog.py b/google/cloud/dialogflowcx_v3/types/changelog.py index 897655ff..b58c3ca3 100644 --- a/google/cloud/dialogflowcx_v3/types/changelog.py +++ b/google/cloud/dialogflowcx_v3/types/changelog.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/deployment.py b/google/cloud/dialogflowcx_v3/types/deployment.py index ff3999cf..e1ede854 100644 --- a/google/cloud/dialogflowcx_v3/types/deployment.py +++ b/google/cloud/dialogflowcx_v3/types/deployment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/entity_type.py b/google/cloud/dialogflowcx_v3/types/entity_type.py index 3bd32947..173465c4 100644 --- a/google/cloud/dialogflowcx_v3/types/entity_type.py +++ b/google/cloud/dialogflowcx_v3/types/entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/environment.py b/google/cloud/dialogflowcx_v3/types/environment.py index 9c898532..da073c40 100644 --- a/google/cloud/dialogflowcx_v3/types/environment.py +++ b/google/cloud/dialogflowcx_v3/types/environment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -73,10 +75,10 @@ class Environment(proto.Message): characters. If exceeded, the request is rejected. version_configs (MutableSequence[google.cloud.dialogflowcx_v3.types.Environment.VersionConfig]): - Required. A list of configurations for flow versions. You - should include version configs for all flows that are - reachable from [``Start Flow``][Agent.start_flow] in the - agent. Otherwise, an error will be returned. + A list of configurations for flow versions. You should + include version configs for all flows that are reachable + from [``Start Flow``][Agent.start_flow] in the agent. + Otherwise, an error will be returned. update_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Update time of this environment. test_cases_config (google.cloud.dialogflowcx_v3.types.Environment.TestCasesConfig): diff --git a/google/cloud/dialogflowcx_v3/types/experiment.py b/google/cloud/dialogflowcx_v3/types/experiment.py index 4e818afb..ab769d3b 100644 --- a/google/cloud/dialogflowcx_v3/types/experiment.py +++ b/google/cloud/dialogflowcx_v3/types/experiment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/flow.py b/google/cloud/dialogflowcx_v3/types/flow.py index 56ea6e87..fe1eb76d 100644 --- a/google/cloud/dialogflowcx_v3/types/flow.py +++ b/google/cloud/dialogflowcx_v3/types/flow.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/fulfillment.py b/google/cloud/dialogflowcx_v3/types/fulfillment.py index f334a394..2c21e2dc 100644 --- a/google/cloud/dialogflowcx_v3/types/fulfillment.py +++ b/google/cloud/dialogflowcx_v3/types/fulfillment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/gcs.py b/google/cloud/dialogflowcx_v3/types/gcs.py new file mode 100644 index 00000000..ed80ec06 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/types/gcs.py @@ -0,0 +1,51 @@ +# -*- 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 __future__ import annotations + +from typing import MutableMapping, MutableSequence + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.dialogflow.cx.v3", + manifest={ + "GcsDestination", + }, +) + + +class GcsDestination(proto.Message): + r"""Google Cloud Storage location for a Dialogflow operation that + writes or exports objects (e.g. exported agent or transcripts) + outside of Dialogflow. + + Attributes: + uri (str): + Required. The Google Cloud Storage URI for + the exported objects. A URI is of the form: + gs://bucket/object-name-or-prefix + Whether a full object name, or just a prefix, + its usage depends on the Dialogflow operation. + """ + + uri: str = proto.Field( + proto.STRING, + number=1, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3/types/intent.py b/google/cloud/dialogflowcx_v3/types/intent.py index fa0db3c0..e195081d 100644 --- a/google/cloud/dialogflowcx_v3/types/intent.py +++ b/google/cloud/dialogflowcx_v3/types/intent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/page.py b/google/cloud/dialogflowcx_v3/types/page.py index bf5d7f66..5a23a888 100644 --- a/google/cloud/dialogflowcx_v3/types/page.py +++ b/google/cloud/dialogflowcx_v3/types/page.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/response_message.py b/google/cloud/dialogflowcx_v3/types/response_message.py index fe91f886..6defdb94 100644 --- a/google/cloud/dialogflowcx_v3/types/response_message.py +++ b/google/cloud/dialogflowcx_v3/types/response_message.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/security_settings.py b/google/cloud/dialogflowcx_v3/types/security_settings.py index bad4e404..6fb8ffe6 100644 --- a/google/cloud/dialogflowcx_v3/types/security_settings.py +++ b/google/cloud/dialogflowcx_v3/types/security_settings.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/session.py b/google/cloud/dialogflowcx_v3/types/session.py index 9e63592b..ff760d0b 100644 --- a/google/cloud/dialogflowcx_v3/types/session.py +++ b/google/cloud/dialogflowcx_v3/types/session.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -1195,6 +1197,8 @@ class MatchIntentRequest(proto.Message): The parameters of this query. query_input (google.cloud.dialogflowcx_v3.types.QueryInput): Required. The input specification. + persist_parameter_changes (bool): + Persist session parameter changes from ``query_params``. """ session: str = proto.Field( @@ -1211,6 +1215,10 @@ class MatchIntentRequest(proto.Message): number=3, message="QueryInput", ) + persist_parameter_changes: bool = proto.Field( + proto.BOOL, + number=5, + ) class MatchIntentResponse(proto.Message): diff --git a/google/cloud/dialogflowcx_v3/types/session_entity_type.py b/google/cloud/dialogflowcx_v3/types/session_entity_type.py index b8909b91..0946c5be 100644 --- a/google/cloud/dialogflowcx_v3/types/session_entity_type.py +++ b/google/cloud/dialogflowcx_v3/types/session_entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/test_case.py b/google/cloud/dialogflowcx_v3/types/test_case.py index 5da744db..05377871 100644 --- a/google/cloud/dialogflowcx_v3/types/test_case.py +++ b/google/cloud/dialogflowcx_v3/types/test_case.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/transition_route_group.py b/google/cloud/dialogflowcx_v3/types/transition_route_group.py index 96f33960..9fe04a44 100644 --- a/google/cloud/dialogflowcx_v3/types/transition_route_group.py +++ b/google/cloud/dialogflowcx_v3/types/transition_route_group.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/validation_message.py b/google/cloud/dialogflowcx_v3/types/validation_message.py index a4eb928b..d421b9b0 100644 --- a/google/cloud/dialogflowcx_v3/types/validation_message.py +++ b/google/cloud/dialogflowcx_v3/types/validation_message.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/version.py b/google/cloud/dialogflowcx_v3/types/version.py index bfdbd290..20ae4aab 100644 --- a/google/cloud/dialogflowcx_v3/types/version.py +++ b/google/cloud/dialogflowcx_v3/types/version.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3/types/webhook.py b/google/cloud/dialogflowcx_v3/types/webhook.py index 716702d9..c3a35dd4 100644 --- a/google/cloud/dialogflowcx_v3/types/webhook.py +++ b/google/cloud/dialogflowcx_v3/types/webhook.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/__init__.py b/google/cloud/dialogflowcx_v3beta1/__init__.py index 2f3fe08b..a1833057 100644 --- a/google/cloud/dialogflowcx_v3beta1/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/__init__.py @@ -70,6 +70,7 @@ from .types.audio_config import OutputAudioConfig from .types.audio_config import SpeechWordInfo from .types.audio_config import SynthesizeSpeechConfig +from .types.audio_config import TextToSpeechSettings from .types.audio_config import VoiceSelectionParams from .types.audio_config import AudioEncoding from .types.audio_config import OutputAudioEncoding @@ -138,6 +139,7 @@ from .types.flow import UpdateFlowRequest from .types.flow import ValidateFlowRequest from .types.fulfillment import Fulfillment +from .types.gcs import GcsDestination from .types.intent import CreateIntentRequest from .types.intent import DeleteIntentRequest from .types.intent import GetIntentRequest @@ -347,6 +349,7 @@ "FulfillIntentRequest", "FulfillIntentResponse", "Fulfillment", + "GcsDestination", "GetAgentRequest", "GetAgentValidationResultRequest", "GetChangelogRequest", @@ -462,6 +465,7 @@ "TestResult", "TestRunDifference", "TextInput", + "TextToSpeechSettings", "TrainFlowRequest", "TransitionCoverage", "TransitionRoute", diff --git a/google/cloud/dialogflowcx_v3beta1/gapic_metadata.json b/google/cloud/dialogflowcx_v3beta1/gapic_metadata.json index a59ccd58..6c371762 100644 --- a/google/cloud/dialogflowcx_v3beta1/gapic_metadata.json +++ b/google/cloud/dialogflowcx_v3beta1/gapic_metadata.json @@ -106,6 +106,56 @@ ] } } + }, + "rest": { + "libraryClient": "AgentsClient", + "rpcs": { + "CreateAgent": { + "methods": [ + "create_agent" + ] + }, + "DeleteAgent": { + "methods": [ + "delete_agent" + ] + }, + "ExportAgent": { + "methods": [ + "export_agent" + ] + }, + "GetAgent": { + "methods": [ + "get_agent" + ] + }, + "GetAgentValidationResult": { + "methods": [ + "get_agent_validation_result" + ] + }, + "ListAgents": { + "methods": [ + "list_agents" + ] + }, + "RestoreAgent": { + "methods": [ + "restore_agent" + ] + }, + "UpdateAgent": { + "methods": [ + "update_agent" + ] + }, + "ValidateAgent": { + "methods": [ + "validate_agent" + ] + } + } } } }, @@ -140,6 +190,21 @@ ] } } + }, + "rest": { + "libraryClient": "ChangelogsClient", + "rpcs": { + "GetChangelog": { + "methods": [ + "get_changelog" + ] + }, + "ListChangelogs": { + "methods": [ + "list_changelogs" + ] + } + } } } }, @@ -174,6 +239,21 @@ ] } } + }, + "rest": { + "libraryClient": "DeploymentsClient", + "rpcs": { + "GetDeployment": { + "methods": [ + "get_deployment" + ] + }, + "ListDeployments": { + "methods": [ + "list_deployments" + ] + } + } } } }, @@ -238,6 +318,36 @@ ] } } + }, + "rest": { + "libraryClient": "EntityTypesClient", + "rpcs": { + "CreateEntityType": { + "methods": [ + "create_entity_type" + ] + }, + "DeleteEntityType": { + "methods": [ + "delete_entity_type" + ] + }, + "GetEntityType": { + "methods": [ + "get_entity_type" + ] + }, + "ListEntityTypes": { + "methods": [ + "list_entity_types" + ] + }, + "UpdateEntityType": { + "methods": [ + "update_entity_type" + ] + } + } } } }, @@ -342,6 +452,56 @@ ] } } + }, + "rest": { + "libraryClient": "EnvironmentsClient", + "rpcs": { + "CreateEnvironment": { + "methods": [ + "create_environment" + ] + }, + "DeleteEnvironment": { + "methods": [ + "delete_environment" + ] + }, + "DeployFlow": { + "methods": [ + "deploy_flow" + ] + }, + "GetEnvironment": { + "methods": [ + "get_environment" + ] + }, + "ListContinuousTestResults": { + "methods": [ + "list_continuous_test_results" + ] + }, + "ListEnvironments": { + "methods": [ + "list_environments" + ] + }, + "LookupEnvironmentHistory": { + "methods": [ + "lookup_environment_history" + ] + }, + "RunContinuousTest": { + "methods": [ + "run_continuous_test" + ] + }, + "UpdateEnvironment": { + "methods": [ + "update_environment" + ] + } + } } } }, @@ -426,6 +586,46 @@ ] } } + }, + "rest": { + "libraryClient": "ExperimentsClient", + "rpcs": { + "CreateExperiment": { + "methods": [ + "create_experiment" + ] + }, + "DeleteExperiment": { + "methods": [ + "delete_experiment" + ] + }, + "GetExperiment": { + "methods": [ + "get_experiment" + ] + }, + "ListExperiments": { + "methods": [ + "list_experiments" + ] + }, + "StartExperiment": { + "methods": [ + "start_experiment" + ] + }, + "StopExperiment": { + "methods": [ + "stop_experiment" + ] + }, + "UpdateExperiment": { + "methods": [ + "update_experiment" + ] + } + } } } }, @@ -540,6 +740,61 @@ ] } } + }, + "rest": { + "libraryClient": "FlowsClient", + "rpcs": { + "CreateFlow": { + "methods": [ + "create_flow" + ] + }, + "DeleteFlow": { + "methods": [ + "delete_flow" + ] + }, + "ExportFlow": { + "methods": [ + "export_flow" + ] + }, + "GetFlow": { + "methods": [ + "get_flow" + ] + }, + "GetFlowValidationResult": { + "methods": [ + "get_flow_validation_result" + ] + }, + "ImportFlow": { + "methods": [ + "import_flow" + ] + }, + "ListFlows": { + "methods": [ + "list_flows" + ] + }, + "TrainFlow": { + "methods": [ + "train_flow" + ] + }, + "UpdateFlow": { + "methods": [ + "update_flow" + ] + }, + "ValidateFlow": { + "methods": [ + "validate_flow" + ] + } + } } } }, @@ -604,13 +859,73 @@ ] } } - } - } - }, - "Pages": { - "clients": { - "grpc": { - "libraryClient": "PagesClient", + }, + "rest": { + "libraryClient": "IntentsClient", + "rpcs": { + "CreateIntent": { + "methods": [ + "create_intent" + ] + }, + "DeleteIntent": { + "methods": [ + "delete_intent" + ] + }, + "GetIntent": { + "methods": [ + "get_intent" + ] + }, + "ListIntents": { + "methods": [ + "list_intents" + ] + }, + "UpdateIntent": { + "methods": [ + "update_intent" + ] + } + } + } + } + }, + "Pages": { + "clients": { + "grpc": { + "libraryClient": "PagesClient", + "rpcs": { + "CreatePage": { + "methods": [ + "create_page" + ] + }, + "DeletePage": { + "methods": [ + "delete_page" + ] + }, + "GetPage": { + "methods": [ + "get_page" + ] + }, + "ListPages": { + "methods": [ + "list_pages" + ] + }, + "UpdatePage": { + "methods": [ + "update_page" + ] + } + } + }, + "grpc-async": { + "libraryClient": "PagesAsyncClient", "rpcs": { "CreatePage": { "methods": [ @@ -639,8 +954,8 @@ } } }, - "grpc-async": { - "libraryClient": "PagesAsyncClient", + "rest": { + "libraryClient": "PagesClient", "rpcs": { "CreatePage": { "methods": [ @@ -732,6 +1047,36 @@ ] } } + }, + "rest": { + "libraryClient": "SecuritySettingsServiceClient", + "rpcs": { + "CreateSecuritySettings": { + "methods": [ + "create_security_settings" + ] + }, + "DeleteSecuritySettings": { + "methods": [ + "delete_security_settings" + ] + }, + "GetSecuritySettings": { + "methods": [ + "get_security_settings" + ] + }, + "ListSecuritySettings": { + "methods": [ + "list_security_settings" + ] + }, + "UpdateSecuritySettings": { + "methods": [ + "update_security_settings" + ] + } + } } } }, @@ -796,6 +1141,36 @@ ] } } + }, + "rest": { + "libraryClient": "SessionEntityTypesClient", + "rpcs": { + "CreateSessionEntityType": { + "methods": [ + "create_session_entity_type" + ] + }, + "DeleteSessionEntityType": { + "methods": [ + "delete_session_entity_type" + ] + }, + "GetSessionEntityType": { + "methods": [ + "get_session_entity_type" + ] + }, + "ListSessionEntityTypes": { + "methods": [ + "list_session_entity_types" + ] + }, + "UpdateSessionEntityType": { + "methods": [ + "update_session_entity_type" + ] + } + } } } }, @@ -850,6 +1225,31 @@ ] } } + }, + "rest": { + "libraryClient": "SessionsClient", + "rpcs": { + "DetectIntent": { + "methods": [ + "detect_intent" + ] + }, + "FulfillIntent": { + "methods": [ + "fulfill_intent" + ] + }, + "MatchIntent": { + "methods": [ + "match_intent" + ] + }, + "StreamingDetectIntent": { + "methods": [ + "streaming_detect_intent" + ] + } + } } } }, @@ -984,6 +1384,71 @@ ] } } + }, + "rest": { + "libraryClient": "TestCasesClient", + "rpcs": { + "BatchDeleteTestCases": { + "methods": [ + "batch_delete_test_cases" + ] + }, + "BatchRunTestCases": { + "methods": [ + "batch_run_test_cases" + ] + }, + "CalculateCoverage": { + "methods": [ + "calculate_coverage" + ] + }, + "CreateTestCase": { + "methods": [ + "create_test_case" + ] + }, + "ExportTestCases": { + "methods": [ + "export_test_cases" + ] + }, + "GetTestCase": { + "methods": [ + "get_test_case" + ] + }, + "GetTestCaseResult": { + "methods": [ + "get_test_case_result" + ] + }, + "ImportTestCases": { + "methods": [ + "import_test_cases" + ] + }, + "ListTestCaseResults": { + "methods": [ + "list_test_case_results" + ] + }, + "ListTestCases": { + "methods": [ + "list_test_cases" + ] + }, + "RunTestCase": { + "methods": [ + "run_test_case" + ] + }, + "UpdateTestCase": { + "methods": [ + "update_test_case" + ] + } + } } } }, @@ -1048,6 +1513,36 @@ ] } } + }, + "rest": { + "libraryClient": "TransitionRouteGroupsClient", + "rpcs": { + "CreateTransitionRouteGroup": { + "methods": [ + "create_transition_route_group" + ] + }, + "DeleteTransitionRouteGroup": { + "methods": [ + "delete_transition_route_group" + ] + }, + "GetTransitionRouteGroup": { + "methods": [ + "get_transition_route_group" + ] + }, + "ListTransitionRouteGroups": { + "methods": [ + "list_transition_route_groups" + ] + }, + "UpdateTransitionRouteGroup": { + "methods": [ + "update_transition_route_group" + ] + } + } } } }, @@ -1132,6 +1627,46 @@ ] } } + }, + "rest": { + "libraryClient": "VersionsClient", + "rpcs": { + "CompareVersions": { + "methods": [ + "compare_versions" + ] + }, + "CreateVersion": { + "methods": [ + "create_version" + ] + }, + "DeleteVersion": { + "methods": [ + "delete_version" + ] + }, + "GetVersion": { + "methods": [ + "get_version" + ] + }, + "ListVersions": { + "methods": [ + "list_versions" + ] + }, + "LoadVersion": { + "methods": [ + "load_version" + ] + }, + "UpdateVersion": { + "methods": [ + "update_version" + ] + } + } } } }, @@ -1196,6 +1731,36 @@ ] } } + }, + "rest": { + "libraryClient": "WebhooksClient", + "rpcs": { + "CreateWebhook": { + "methods": [ + "create_webhook" + ] + }, + "DeleteWebhook": { + "methods": [ + "delete_webhook" + ] + }, + "GetWebhook": { + "methods": [ + "get_webhook" + ] + }, + "ListWebhooks": { + "methods": [ + "list_webhooks" + ] + }, + "UpdateWebhook": { + "methods": [ + "update_webhook" + ] + } + } } } } diff --git a/google/cloud/dialogflowcx_v3beta1/gapic_version.py b/google/cloud/dialogflowcx_v3beta1/gapic_version.py index 0028cb17..86f8ab82 100644 --- a/google/cloud/dialogflowcx_v3beta1/gapic_version.py +++ b/google/cloud/dialogflowcx_v3beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "1.18.0" # {x-release-please-version} +__version__ = "1.19.0" # {x-release-please-version} diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py index a94a1794..c7dc989f 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py @@ -48,6 +48,7 @@ from google.cloud.dialogflowcx_v3beta1.types import advanced_settings from google.cloud.dialogflowcx_v3beta1.types import agent from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3beta1.types import audio_config from google.cloud.dialogflowcx_v3beta1.types import flow from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/client.py b/google/cloud/dialogflowcx_v3beta1/services/agents/client.py index c20d20e8..40d9deaa 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/client.py @@ -52,6 +52,7 @@ from google.cloud.dialogflowcx_v3beta1.types import advanced_settings from google.cloud.dialogflowcx_v3beta1.types import agent from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3beta1.types import audio_config from google.cloud.dialogflowcx_v3beta1.types import flow from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 @@ -61,6 +62,7 @@ from .transports.base import AgentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import AgentsGrpcTransport from .transports.grpc_asyncio import AgentsGrpcAsyncIOTransport +from .transports.rest import AgentsRestTransport class AgentsClientMeta(type): @@ -74,6 +76,7 @@ class AgentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport + _transport_registry["rest"] = AgentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/__init__.py index 703a3046..a94f62c7 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/__init__.py @@ -19,15 +19,20 @@ from .base import AgentsTransport from .grpc import AgentsGrpcTransport from .grpc_asyncio import AgentsGrpcAsyncIOTransport +from .rest import AgentsRestTransport +from .rest import AgentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport +_transport_registry["rest"] = AgentsRestTransport __all__ = ( "AgentsTransport", "AgentsGrpcTransport", "AgentsGrpcAsyncIOTransport", + "AgentsRestTransport", + "AgentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/rest.py new file mode 100644 index 00000000..a4aa2fe1 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/rest.py @@ -0,0 +1,1894 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import agent +from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import AgentsTransport, 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 AgentsRestInterceptor: + """Interceptor for Agents. + + 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 AgentsRestTransport. + + .. code-block:: python + class MyCustomAgentsInterceptor(AgentsRestInterceptor): + def pre_create_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_agent_validation_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_agent_validation_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_agents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_agents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_restore_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_restore_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_validate_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_validate_agent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AgentsRestTransport(interceptor=MyCustomAgentsInterceptor()) + client = AgentsClient(transport=transport) + + + """ + + def pre_create_agent( + self, + request: gcdc_agent.CreateAgentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_agent.CreateAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_create_agent(self, response: gcdc_agent.Agent) -> gcdc_agent.Agent: + """Post-rpc interceptor for create_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_delete_agent( + self, request: agent.DeleteAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.DeleteAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def pre_export_agent( + self, request: agent.ExportAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ExportAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_export_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_agent( + self, request: agent.GetAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.GetAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_agent(self, response: agent.Agent) -> agent.Agent: + """Post-rpc interceptor for get_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_agent_validation_result( + self, + request: agent.GetAgentValidationResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[agent.GetAgentValidationResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_agent_validation_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_agent_validation_result( + self, response: agent.AgentValidationResult + ) -> agent.AgentValidationResult: + """Post-rpc interceptor for get_agent_validation_result + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_agents( + self, request: agent.ListAgentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ListAgentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_agents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_agents( + self, response: agent.ListAgentsResponse + ) -> agent.ListAgentsResponse: + """Post-rpc interceptor for list_agents + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_restore_agent( + self, request: agent.RestoreAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.RestoreAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for restore_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_restore_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for restore_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_update_agent( + self, + request: gcdc_agent.UpdateAgentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_agent.UpdateAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_update_agent(self, response: gcdc_agent.Agent) -> gcdc_agent.Agent: + """Post-rpc interceptor for update_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_validate_agent( + self, request: agent.ValidateAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ValidateAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for validate_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_validate_agent( + self, response: agent.AgentValidationResult + ) -> agent.AgentValidationResult: + """Post-rpc interceptor for validate_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AgentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AgentsRestInterceptor + + +class AgentsRestTransport(AgentsTransport): + """REST backend transport for Agents. + + Service for managing + [Agents][google.cloud.dialogflow.cx.v3beta1.Agent]. + + 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 = "dialogflow.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[AgentsRestInterceptor] = 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 AgentsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/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="v3beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateAgent(AgentsRestStub): + def __hash__(self): + return hash("CreateAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_agent.CreateAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_agent.Agent: + r"""Call the create agent method over HTTP. + + Args: + request (~.gcdc_agent.CreateAgentRequest): + The request object. The request message for + [Agents.CreateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.CreateAgent]. + + 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: + ~.gcdc_agent.Agent: + Agents are best described as Natural Language + Understanding (NLU) modules that transform user requests + into actionable data. You can include agents in your + app, product, or service to determine user intent and + respond to the user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*}/agents", + "body": "agent", + }, + ] + request, metadata = self._interceptor.pre_create_agent(request, metadata) + pb_request = gcdc_agent.CreateAgentRequest.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 = gcdc_agent.Agent() + pb_resp = gcdc_agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_agent(resp) + return resp + + class _DeleteAgent(AgentsRestStub): + def __hash__(self): + return hash("DeleteAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.DeleteAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete agent method over HTTP. + + Args: + request (~.agent.DeleteAgentRequest): + The request object. The request message for + [Agents.DeleteAgent][google.cloud.dialogflow.cx.v3beta1.Agents.DeleteAgent]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_agent(request, metadata) + pb_request = agent.DeleteAgentRequest.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 _ExportAgent(AgentsRestStub): + def __hash__(self): + return hash("ExportAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.ExportAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export agent method over HTTP. + + Args: + request (~.agent.ExportAgentRequest): + The request object. The request message for + [Agents.ExportAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ExportAgent]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*}:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_agent(request, metadata) + pb_request = agent.ExportAgentRequest.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_agent(resp) + return resp + + class _GetAgent(AgentsRestStub): + def __hash__(self): + return hash("GetAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.GetAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.Agent: + r"""Call the get agent method over HTTP. + + Args: + request (~.agent.GetAgentRequest): + The request object. The request message for + [Agents.GetAgent][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgent]. + + 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: + ~.agent.Agent: + Agents are best described as Natural Language + Understanding (NLU) modules that transform user requests + into actionable data. You can include agents in your + app, product, or service to determine user intent and + respond to the user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_agent(request, metadata) + pb_request = agent.GetAgentRequest.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 = agent.Agent() + pb_resp = agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_agent(resp) + return resp + + class _GetAgentValidationResult(AgentsRestStub): + def __hash__(self): + return hash("GetAgentValidationResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.GetAgentValidationResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Call the get agent validation + result method over HTTP. + + Args: + request (~.agent.GetAgentValidationResultRequest): + The request object. The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + 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: + ~.agent.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/validationResult}", + }, + ] + request, metadata = self._interceptor.pre_get_agent_validation_result( + request, metadata + ) + pb_request = agent.GetAgentValidationResultRequest.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 = agent.AgentValidationResult() + pb_resp = agent.AgentValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_agent_validation_result(resp) + return resp + + class _ListAgents(AgentsRestStub): + def __hash__(self): + return hash("ListAgents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.ListAgentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.ListAgentsResponse: + r"""Call the list agents method over HTTP. + + Args: + request (~.agent.ListAgentsRequest): + The request object. The request message for + [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. + + 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: + ~.agent.ListAgentsResponse: + The response message for + [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*}/agents", + }, + ] + request, metadata = self._interceptor.pre_list_agents(request, metadata) + pb_request = agent.ListAgentsRequest.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 = agent.ListAgentsResponse() + pb_resp = agent.ListAgentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_agents(resp) + return resp + + class _RestoreAgent(AgentsRestStub): + def __hash__(self): + return hash("RestoreAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.RestoreAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the restore agent method over HTTP. + + Args: + request (~.agent.RestoreAgentRequest): + The request object. The request message for + [Agents.RestoreAgent][google.cloud.dialogflow.cx.v3beta1.Agents.RestoreAgent]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*}:restore", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_restore_agent(request, metadata) + pb_request = agent.RestoreAgentRequest.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_restore_agent(resp) + return resp + + class _UpdateAgent(AgentsRestStub): + def __hash__(self): + return hash("UpdateAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_agent.UpdateAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_agent.Agent: + r"""Call the update agent method over HTTP. + + Args: + request (~.gcdc_agent.UpdateAgentRequest): + The request object. The request message for + [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.UpdateAgent]. + + 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: + ~.gcdc_agent.Agent: + Agents are best described as Natural Language + Understanding (NLU) modules that transform user requests + into actionable data. You can include agents in your + app, product, or service to determine user intent and + respond to the user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{agent.name=projects/*/locations/*/agents/*}", + "body": "agent", + }, + ] + request, metadata = self._interceptor.pre_update_agent(request, metadata) + pb_request = gcdc_agent.UpdateAgentRequest.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 = gcdc_agent.Agent() + pb_resp = gcdc_agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_agent(resp) + return resp + + class _ValidateAgent(AgentsRestStub): + def __hash__(self): + return hash("ValidateAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: agent.ValidateAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Call the validate agent method over HTTP. + + Args: + request (~.agent.ValidateAgentRequest): + The request object. The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ValidateAgent]. + + 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: + ~.agent.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*}:validate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_validate_agent(request, metadata) + pb_request = agent.ValidateAgentRequest.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 = agent.AgentValidationResult() + pb_resp = agent.AgentValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_validate_agent(resp) + return resp + + @property + def create_agent( + self, + ) -> Callable[[gcdc_agent.CreateAgentRequest], gcdc_agent.Agent]: + # 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._CreateAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_agent(self) -> Callable[[agent.DeleteAgentRequest], 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._DeleteAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_agent( + self, + ) -> Callable[[agent.ExportAgentRequest], 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._ExportAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_agent(self) -> Callable[[agent.GetAgentRequest], agent.Agent]: + # 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._GetAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_agent_validation_result( + self, + ) -> Callable[[agent.GetAgentValidationResultRequest], agent.AgentValidationResult]: + # 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._GetAgentValidationResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_agents( + self, + ) -> Callable[[agent.ListAgentsRequest], agent.ListAgentsResponse]: + # 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._ListAgents(self._session, self._host, self._interceptor) # type: ignore + + @property + def restore_agent( + self, + ) -> Callable[[agent.RestoreAgentRequest], 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._RestoreAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_agent( + self, + ) -> Callable[[gcdc_agent.UpdateAgentRequest], gcdc_agent.Agent]: + # 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._UpdateAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def validate_agent( + self, + ) -> Callable[[agent.ValidateAgentRequest], agent.AgentValidationResult]: + # 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._ValidateAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(AgentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(AgentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(AgentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AgentsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(AgentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AgentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/changelogs/client.py b/google/cloud/dialogflowcx_v3beta1/services/changelogs/client.py index 250501d1..e7d7ba69 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/changelogs/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/changelogs/client.py @@ -54,6 +54,7 @@ from .transports.base import ChangelogsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import ChangelogsGrpcTransport from .transports.grpc_asyncio import ChangelogsGrpcAsyncIOTransport +from .transports.rest import ChangelogsRestTransport class ChangelogsClientMeta(type): @@ -67,6 +68,7 @@ class ChangelogsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ChangelogsTransport]] _transport_registry["grpc"] = ChangelogsGrpcTransport _transport_registry["grpc_asyncio"] = ChangelogsGrpcAsyncIOTransport + _transport_registry["rest"] = ChangelogsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/__init__.py index 34aa1f62..49d7fb49 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/__init__.py @@ -19,15 +19,20 @@ from .base import ChangelogsTransport from .grpc import ChangelogsGrpcTransport from .grpc_asyncio import ChangelogsGrpcAsyncIOTransport +from .rest import ChangelogsRestTransport +from .rest import ChangelogsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ChangelogsTransport]] _transport_registry["grpc"] = ChangelogsGrpcTransport _transport_registry["grpc_asyncio"] = ChangelogsGrpcAsyncIOTransport +_transport_registry["rest"] = ChangelogsRestTransport __all__ = ( "ChangelogsTransport", "ChangelogsGrpcTransport", "ChangelogsGrpcAsyncIOTransport", + "ChangelogsRestTransport", + "ChangelogsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/rest.py new file mode 100644 index 00000000..693a5981 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/changelogs/transports/rest.py @@ -0,0 +1,895 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import changelog + +from .base import ChangelogsTransport, 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 ChangelogsRestInterceptor: + """Interceptor for Changelogs. + + 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 ChangelogsRestTransport. + + .. code-block:: python + class MyCustomChangelogsInterceptor(ChangelogsRestInterceptor): + def pre_get_changelog(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_changelog(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_changelogs(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_changelogs(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ChangelogsRestTransport(interceptor=MyCustomChangelogsInterceptor()) + client = ChangelogsClient(transport=transport) + + + """ + + def pre_get_changelog( + self, + request: changelog.GetChangelogRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[changelog.GetChangelogRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_changelog + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_get_changelog(self, response: changelog.Changelog) -> changelog.Changelog: + """Post-rpc interceptor for get_changelog + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_list_changelogs( + self, + request: changelog.ListChangelogsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[changelog.ListChangelogsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_changelogs + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_list_changelogs( + self, response: changelog.ListChangelogsResponse + ) -> changelog.ListChangelogsResponse: + """Post-rpc interceptor for list_changelogs + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Changelogs 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Changelogs server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Changelogs server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ChangelogsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ChangelogsRestInterceptor + + +class ChangelogsRestTransport(ChangelogsTransport): + """REST backend transport for Changelogs. + + Service for managing + [Changelogs][google.cloud.dialogflow.cx.v3beta1.Changelog]. + + 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 = "dialogflow.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[ChangelogsRestInterceptor] = 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 ChangelogsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetChangelog(ChangelogsRestStub): + def __hash__(self): + return hash("GetChangelog") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: changelog.GetChangelogRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> changelog.Changelog: + r"""Call the get changelog method over HTTP. + + Args: + request (~.changelog.GetChangelogRequest): + The request object. The request message for + [Changelogs.GetChangelog][google.cloud.dialogflow.cx.v3beta1.Changelogs.GetChangelog]. + + 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: + ~.changelog.Changelog: + Changelogs represents a change made + to a given agent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/changelogs/*}", + }, + ] + request, metadata = self._interceptor.pre_get_changelog(request, metadata) + pb_request = changelog.GetChangelogRequest.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 = changelog.Changelog() + pb_resp = changelog.Changelog.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_changelog(resp) + return resp + + class _ListChangelogs(ChangelogsRestStub): + def __hash__(self): + return hash("ListChangelogs") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: changelog.ListChangelogsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> changelog.ListChangelogsResponse: + r"""Call the list changelogs method over HTTP. + + Args: + request (~.changelog.ListChangelogsRequest): + The request object. The request message for + [Changelogs.ListChangelogs][google.cloud.dialogflow.cx.v3beta1.Changelogs.ListChangelogs]. + + 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: + ~.changelog.ListChangelogsResponse: + The response message for + [Changelogs.ListChangelogs][google.cloud.dialogflow.cx.v3beta1.Changelogs.ListChangelogs]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/changelogs", + }, + ] + request, metadata = self._interceptor.pre_list_changelogs(request, metadata) + pb_request = changelog.ListChangelogsRequest.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 = changelog.ListChangelogsResponse() + pb_resp = changelog.ListChangelogsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_changelogs(resp) + return resp + + @property + def get_changelog( + self, + ) -> Callable[[changelog.GetChangelogRequest], changelog.Changelog]: + # 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._GetChangelog(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_changelogs( + self, + ) -> Callable[[changelog.ListChangelogsRequest], changelog.ListChangelogsResponse]: + # 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._ListChangelogs(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ChangelogsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ChangelogsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ChangelogsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ChangelogsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ChangelogsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ChangelogsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/deployments/client.py b/google/cloud/dialogflowcx_v3beta1/services/deployments/client.py index 4dec80e9..e477cd9c 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/deployments/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/deployments/client.py @@ -54,6 +54,7 @@ from .transports.base import DeploymentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import DeploymentsGrpcTransport from .transports.grpc_asyncio import DeploymentsGrpcAsyncIOTransport +from .transports.rest import DeploymentsRestTransport class DeploymentsClientMeta(type): @@ -67,6 +68,7 @@ class DeploymentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[DeploymentsTransport]] _transport_registry["grpc"] = DeploymentsGrpcTransport _transport_registry["grpc_asyncio"] = DeploymentsGrpcAsyncIOTransport + _transport_registry["rest"] = DeploymentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/__init__.py index f902c685..c128af3e 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/__init__.py @@ -19,15 +19,20 @@ from .base import DeploymentsTransport from .grpc import DeploymentsGrpcTransport from .grpc_asyncio import DeploymentsGrpcAsyncIOTransport +from .rest import DeploymentsRestTransport +from .rest import DeploymentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[DeploymentsTransport]] _transport_registry["grpc"] = DeploymentsGrpcTransport _transport_registry["grpc_asyncio"] = DeploymentsGrpcAsyncIOTransport +_transport_registry["rest"] = DeploymentsRestTransport __all__ = ( "DeploymentsTransport", "DeploymentsGrpcTransport", "DeploymentsGrpcAsyncIOTransport", + "DeploymentsRestTransport", + "DeploymentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/rest.py new file mode 100644 index 00000000..7e232356 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/deployments/transports/rest.py @@ -0,0 +1,906 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import deployment + +from .base import DeploymentsTransport, 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 DeploymentsRestInterceptor: + """Interceptor for Deployments. + + 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 DeploymentsRestTransport. + + .. code-block:: python + class MyCustomDeploymentsInterceptor(DeploymentsRestInterceptor): + def pre_get_deployment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_deployment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_deployments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_deployments(self, response): + logging.log(f"Received response: {response}") + return response + + transport = DeploymentsRestTransport(interceptor=MyCustomDeploymentsInterceptor()) + client = DeploymentsClient(transport=transport) + + + """ + + def pre_get_deployment( + self, + request: deployment.GetDeploymentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[deployment.GetDeploymentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_deployment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_get_deployment( + self, response: deployment.Deployment + ) -> deployment.Deployment: + """Post-rpc interceptor for get_deployment + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_list_deployments( + self, + request: deployment.ListDeploymentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[deployment.ListDeploymentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_deployments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_list_deployments( + self, response: deployment.ListDeploymentsResponse + ) -> deployment.ListDeploymentsResponse: + """Post-rpc interceptor for list_deployments + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Deployments 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Deployments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Deployments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class DeploymentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: DeploymentsRestInterceptor + + +class DeploymentsRestTransport(DeploymentsTransport): + """REST backend transport for Deployments. + + Service for managing + [Deployments][google.cloud.dialogflow.cx.v3beta1.Deployment]. + + 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 = "dialogflow.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[DeploymentsRestInterceptor] = 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 DeploymentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetDeployment(DeploymentsRestStub): + def __hash__(self): + return hash("GetDeployment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: deployment.GetDeploymentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> deployment.Deployment: + r"""Call the get deployment method over HTTP. + + Args: + request (~.deployment.GetDeploymentRequest): + The request object. The request message for + [Deployments.GetDeployment][google.cloud.dialogflow.cx.v3beta1.Deployments.GetDeployment]. + + 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: + ~.deployment.Deployment: + Represents an deployment in an + environment. A deployment happens when a + flow version configured to be active in + the environment. You can configure + running pre-deployment steps, e.g. + running validation test cases, + experiment auto-rollout, etc. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/deployments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_deployment(request, metadata) + pb_request = deployment.GetDeploymentRequest.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 = deployment.Deployment() + pb_resp = deployment.Deployment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_deployment(resp) + return resp + + class _ListDeployments(DeploymentsRestStub): + def __hash__(self): + return hash("ListDeployments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: deployment.ListDeploymentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> deployment.ListDeploymentsResponse: + r"""Call the list deployments method over HTTP. + + Args: + request (~.deployment.ListDeploymentsRequest): + The request object. The request message for + [Deployments.ListDeployments][google.cloud.dialogflow.cx.v3beta1.Deployments.ListDeployments]. + + 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: + ~.deployment.ListDeploymentsResponse: + The response message for + [Deployments.ListDeployments][google.cloud.dialogflow.cx.v3beta1.Deployments.ListDeployments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/deployments", + }, + ] + request, metadata = self._interceptor.pre_list_deployments( + request, metadata + ) + pb_request = deployment.ListDeploymentsRequest.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 = deployment.ListDeploymentsResponse() + pb_resp = deployment.ListDeploymentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_deployments(resp) + return resp + + @property + def get_deployment( + self, + ) -> Callable[[deployment.GetDeploymentRequest], deployment.Deployment]: + # 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._GetDeployment(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_deployments( + self, + ) -> Callable[ + [deployment.ListDeploymentsRequest], deployment.ListDeploymentsResponse + ]: + # 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._ListDeployments(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(DeploymentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(DeploymentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(DeploymentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(DeploymentsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(DeploymentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("DeploymentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py index d212601c..f6e3bdb6 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py @@ -55,6 +55,7 @@ from .transports.base import EntityTypesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import EntityTypesGrpcTransport from .transports.grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .transports.rest import EntityTypesRestTransport class EntityTypesClientMeta(type): @@ -68,6 +69,7 @@ class EntityTypesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = EntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/__init__.py index 2a22d664..0220987e 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/__init__.py @@ -19,15 +19,20 @@ from .base import EntityTypesTransport from .grpc import EntityTypesGrpcTransport from .grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .rest import EntityTypesRestTransport +from .rest import EntityTypesRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = EntityTypesRestTransport __all__ = ( "EntityTypesTransport", "EntityTypesGrpcTransport", "EntityTypesGrpcAsyncIOTransport", + "EntityTypesRestTransport", + "EntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/rest.py new file mode 100644 index 00000000..147cc1d6 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/rest.py @@ -0,0 +1,1388 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import entity_type +from google.cloud.dialogflowcx_v3beta1.types import entity_type as gcdc_entity_type +from google.protobuf import empty_pb2 # type: ignore + +from .base import EntityTypesTransport, 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 EntityTypesRestInterceptor: + """Interceptor for EntityTypes. + + 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 EntityTypesRestTransport. + + .. code-block:: python + class MyCustomEntityTypesInterceptor(EntityTypesRestInterceptor): + def pre_create_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EntityTypesRestTransport(interceptor=MyCustomEntityTypesInterceptor()) + client = EntityTypesClient(transport=transport) + + + """ + + def pre_create_entity_type( + self, + request: gcdc_entity_type.CreateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_entity_type.CreateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_create_entity_type( + self, response: gcdc_entity_type.EntityType + ) -> gcdc_entity_type.EntityType: + """Post-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_entity_type( + self, + request: entity_type.DeleteEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.DeleteEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def pre_get_entity_type( + self, + request: entity_type.GetEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.GetEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_entity_type( + self, response: entity_type.EntityType + ) -> entity_type.EntityType: + """Post-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_entity_types( + self, + request: entity_type.ListEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.ListEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_entity_types( + self, response: entity_type.ListEntityTypesResponse + ) -> entity_type.ListEntityTypesResponse: + """Post-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_entity_type( + self, + request: gcdc_entity_type.UpdateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_entity_type.UpdateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_update_entity_type( + self, response: gcdc_entity_type.EntityType + ) -> gcdc_entity_type.EntityType: + """Post-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EntityTypesRestInterceptor + + +class EntityTypesRestTransport(EntityTypesTransport): + """REST backend transport for EntityTypes. + + Service for managing + [EntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityType]. + + 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 = "dialogflow.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[EntityTypesRestInterceptor] = 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 EntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("CreateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_entity_type.CreateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_entity_type.EntityType: + r"""Call the create entity type method over HTTP. + + Args: + request (~.gcdc_entity_type.CreateEntityTypeRequest): + The request object. The request message for + [EntityTypes.CreateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.CreateEntityType]. + + 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: + ~.gcdc_entity_type.EntityType: + Entities are extracted from user input and represent + parameters that are meaningful to your application. For + example, a date range, a proper name such as a + geographic location or landmark, and so on. Entities + represent actionable data for your application. + + When you define an entity, you can also include synonyms + that all map to that entity. For example, "soft drink", + "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the ``EntityType`` type. + + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to your + application. For example, you could define a + ``pizza.sauce`` entity for red or white pizza sauce, + a ``pizza.cheese`` entity for the different types of + cheese on a pizza, a ``pizza.topping`` entity for + different toppings, and so on. A custom entity is + represented by the ``EntityType`` type. + + - **User** - entities that are built for an individual + user such as favorites, preferences, playlists, and + so on. A user entity is represented by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/entityTypes", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_entity_type( + request, metadata + ) + pb_request = gcdc_entity_type.CreateEntityTypeRequest.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 = gcdc_entity_type.EntityType() + pb_resp = gcdc_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_entity_type(resp) + return resp + + class _DeleteEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("DeleteEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: entity_type.DeleteEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete entity type method over HTTP. + + Args: + request (~.entity_type.DeleteEntityTypeRequest): + The request object. The request message for + [EntityTypes.DeleteEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.DeleteEntityType]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_entity_type( + request, metadata + ) + pb_request = entity_type.DeleteEntityTypeRequest.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 _GetEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("GetEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: entity_type.GetEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.EntityType: + r"""Call the get entity type method over HTTP. + + Args: + request (~.entity_type.GetEntityTypeRequest): + The request object. The request message for + [EntityTypes.GetEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.GetEntityType]. + + 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: + ~.entity_type.EntityType: + Entities are extracted from user input and represent + parameters that are meaningful to your application. For + example, a date range, a proper name such as a + geographic location or landmark, and so on. Entities + represent actionable data for your application. + + When you define an entity, you can also include synonyms + that all map to that entity. For example, "soft drink", + "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the ``EntityType`` type. + + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to your + application. For example, you could define a + ``pizza.sauce`` entity for red or white pizza sauce, + a ``pizza.cheese`` entity for the different types of + cheese on a pizza, a ``pizza.topping`` entity for + different toppings, and so on. A custom entity is + represented by the ``EntityType`` type. + + - **User** - entities that are built for an individual + user such as favorites, preferences, playlists, and + so on. A user entity is represented by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_entity_type(request, metadata) + pb_request = entity_type.GetEntityTypeRequest.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 = entity_type.EntityType() + pb_resp = entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_entity_type(resp) + return resp + + class _ListEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("ListEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: entity_type.ListEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.ListEntityTypesResponse: + r"""Call the list entity types method over HTTP. + + Args: + request (~.entity_type.ListEntityTypesRequest): + The request object. The request message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. + + 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: + ~.entity_type.ListEntityTypesResponse: + The response message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_entity_types( + request, metadata + ) + pb_request = entity_type.ListEntityTypesRequest.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 = entity_type.ListEntityTypesResponse() + pb_resp = entity_type.ListEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_entity_types(resp) + return resp + + class _UpdateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("UpdateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_entity_type.UpdateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_entity_type.EntityType: + r"""Call the update entity type method over HTTP. + + Args: + request (~.gcdc_entity_type.UpdateEntityTypeRequest): + The request object. The request message for + [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.UpdateEntityType]. + + 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: + ~.gcdc_entity_type.EntityType: + Entities are extracted from user input and represent + parameters that are meaningful to your application. For + example, a date range, a proper name such as a + geographic location or landmark, and so on. Entities + represent actionable data for your application. + + When you define an entity, you can also include synonyms + that all map to that entity. For example, "soft drink", + "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the ``EntityType`` type. + + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to your + application. For example, you could define a + ``pizza.sauce`` entity for red or white pizza sauce, + a ``pizza.cheese`` entity for the different types of + cheese on a pizza, a ``pizza.topping`` entity for + different toppings, and so on. A custom entity is + represented by the ``EntityType`` type. + + - **User** - entities that are built for an individual + user such as favorites, preferences, playlists, and + so on. A user entity is represented by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{entity_type.name=projects/*/locations/*/agents/*/entityTypes/*}", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_entity_type( + request, metadata + ) + pb_request = gcdc_entity_type.UpdateEntityTypeRequest.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 = gcdc_entity_type.EntityType() + pb_resp = gcdc_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_entity_type(resp) + return resp + + @property + def create_entity_type( + self, + ) -> Callable[ + [gcdc_entity_type.CreateEntityTypeRequest], gcdc_entity_type.EntityType + ]: + # 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._CreateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_entity_type( + self, + ) -> Callable[[entity_type.DeleteEntityTypeRequest], 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._DeleteEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_entity_type( + self, + ) -> Callable[[entity_type.GetEntityTypeRequest], entity_type.EntityType]: + # 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._GetEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_entity_types( + self, + ) -> Callable[ + [entity_type.ListEntityTypesRequest], entity_type.ListEntityTypesResponse + ]: + # 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._ListEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_entity_type( + self, + ) -> Callable[ + [gcdc_entity_type.UpdateEntityTypeRequest], gcdc_entity_type.EntityType + ]: + # 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._UpdateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EntityTypesRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EntityTypesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py index 6e6f2a85..ede9bc7b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py @@ -517,7 +517,6 @@ async def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.CreateEnvironmentRequest( parent="parent_value", @@ -672,7 +671,6 @@ async def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.UpdateEnvironmentRequest( environment=environment, diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/client.py b/google/cloud/dialogflowcx_v3beta1/services/environments/client.py index a35d6421..2518d668 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/client.py @@ -59,6 +59,7 @@ from .transports.base import EnvironmentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import EnvironmentsGrpcTransport from .transports.grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .transports.rest import EnvironmentsRestTransport class EnvironmentsClientMeta(type): @@ -72,6 +73,7 @@ class EnvironmentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport + _transport_registry["rest"] = EnvironmentsRestTransport def get_transport_class( cls, @@ -880,7 +882,6 @@ def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.CreateEnvironmentRequest( parent="parent_value", @@ -1035,7 +1036,6 @@ def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.UpdateEnvironmentRequest( environment=environment, diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/__init__.py index 0ecefb61..1f36326c 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/__init__.py @@ -19,15 +19,20 @@ from .base import EnvironmentsTransport from .grpc import EnvironmentsGrpcTransport from .grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .rest import EnvironmentsRestTransport +from .rest import EnvironmentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport +_transport_registry["rest"] = EnvironmentsRestTransport __all__ = ( "EnvironmentsTransport", "EnvironmentsGrpcTransport", "EnvironmentsGrpcAsyncIOTransport", + "EnvironmentsRestTransport", + "EnvironmentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/rest.py new file mode 100644 index 00000000..5385c324 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/rest.py @@ -0,0 +1,1909 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import environment +from google.cloud.dialogflowcx_v3beta1.types import environment as gcdc_environment +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import EnvironmentsTransport, 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 EnvironmentsRestInterceptor: + """Interceptor for Environments. + + 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 EnvironmentsRestTransport. + + .. code-block:: python + class MyCustomEnvironmentsInterceptor(EnvironmentsRestInterceptor): + def pre_create_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_deploy_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_deploy_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_continuous_test_results(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_continuous_test_results(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_environments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_environments(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_lookup_environment_history(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_lookup_environment_history(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_run_continuous_test(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_run_continuous_test(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_environment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EnvironmentsRestTransport(interceptor=MyCustomEnvironmentsInterceptor()) + client = EnvironmentsClient(transport=transport) + + + """ + + def pre_create_environment( + self, + request: gcdc_environment.CreateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_environment.CreateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_create_environment( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_delete_environment( + self, + request: environment.DeleteEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.DeleteEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def pre_deploy_flow( + self, + request: environment.DeployFlowRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.DeployFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for deploy_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_deploy_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for deploy_flow + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_environment( + self, + request: environment.GetEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.GetEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for get_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_continuous_test_results( + self, + request: environment.ListContinuousTestResultsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.ListContinuousTestResultsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_continuous_test_results + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_continuous_test_results( + self, response: environment.ListContinuousTestResultsResponse + ) -> environment.ListContinuousTestResultsResponse: + """Post-rpc interceptor for list_continuous_test_results + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_environments( + self, + request: environment.ListEnvironmentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.ListEnvironmentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_environments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_environments( + self, response: environment.ListEnvironmentsResponse + ) -> environment.ListEnvironmentsResponse: + """Post-rpc interceptor for list_environments + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_lookup_environment_history( + self, + request: environment.LookupEnvironmentHistoryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.LookupEnvironmentHistoryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for lookup_environment_history + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_lookup_environment_history( + self, response: environment.LookupEnvironmentHistoryResponse + ) -> environment.LookupEnvironmentHistoryResponse: + """Post-rpc interceptor for lookup_environment_history + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_run_continuous_test( + self, + request: environment.RunContinuousTestRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.RunContinuousTestRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for run_continuous_test + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_run_continuous_test( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for run_continuous_test + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_update_environment( + self, + request: gcdc_environment.UpdateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_environment.UpdateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_update_environment( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for update_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EnvironmentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EnvironmentsRestInterceptor + + +class EnvironmentsRestTransport(EnvironmentsTransport): + """REST backend transport for Environments. + + Service for managing + [Environments][google.cloud.dialogflow.cx.v3beta1.Environment]. + + 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 = "dialogflow.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[EnvironmentsRestInterceptor] = 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 EnvironmentsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/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="v3beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("CreateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_environment.CreateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create environment method over HTTP. + + Args: + request (~.gcdc_environment.CreateEnvironmentRequest): + The request object. The request message for + [Environments.CreateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.CreateEnvironment]. + + 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": "/v3beta1/{parent=projects/*/locations/*/agents/*}/environments", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_create_environment( + request, metadata + ) + pb_request = gcdc_environment.CreateEnvironmentRequest.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_create_environment(resp) + return resp + + class _DeleteEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("DeleteEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.DeleteEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete environment method over HTTP. + + Args: + request (~.environment.DeleteEnvironmentRequest): + The request object. The request message for + [Environments.DeleteEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.DeleteEnvironment]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_environment( + request, metadata + ) + pb_request = environment.DeleteEnvironmentRequest.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 _DeployFlow(EnvironmentsRestStub): + def __hash__(self): + return hash("DeployFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.DeployFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the deploy flow method over HTTP. + + Args: + request (~.environment.DeployFlowRequest): + The request object. The request message for + [Environments.DeployFlow][google.cloud.dialogflow.cx.v3beta1.Environments.DeployFlow]. + + 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": "/v3beta1/{environment=projects/*/locations/*/agents/*/environments/*}:deployFlow", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_deploy_flow(request, metadata) + pb_request = environment.DeployFlowRequest.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_deploy_flow(resp) + return resp + + class _GetEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("GetEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.GetEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the get environment method over HTTP. + + Args: + request (~.environment.GetEnvironmentRequest): + The request object. The request message for + [Environments.GetEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.GetEnvironment]. + + 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: + ~.environment.Environment: + Represents an environment for an + agent. You can create multiple versions + of your agent and publish them to + separate environments. When you edit an + agent, you are editing the draft agent. + At any point, you can save the draft + agent as an agent version, which is an + immutable snapshot of your agent. When + you save the draft agent, it is + published to the default environment. + When you create agent versions, you can + publish them to custom environments. You + can create a variety of custom + environments for testing, development, + production, etc. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_environment(request, metadata) + pb_request = environment.GetEnvironmentRequest.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 = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_environment(resp) + return resp + + class _ListContinuousTestResults(EnvironmentsRestStub): + def __hash__(self): + return hash("ListContinuousTestResults") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.ListContinuousTestResultsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.ListContinuousTestResultsResponse: + r"""Call the list continuous test + results method over HTTP. + + Args: + request (~.environment.ListContinuousTestResultsRequest): + The request object. The request message for + [Environments.ListContinuousTestResults][google.cloud.dialogflow.cx.v3beta1.Environments.ListContinuousTestResults]. + + 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: + ~.environment.ListContinuousTestResultsResponse: + The response message for + [Environments.ListTestCaseResults][]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/continuousTestResults", + }, + ] + request, metadata = self._interceptor.pre_list_continuous_test_results( + request, metadata + ) + pb_request = environment.ListContinuousTestResultsRequest.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 = environment.ListContinuousTestResultsResponse() + pb_resp = environment.ListContinuousTestResultsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_continuous_test_results(resp) + return resp + + class _ListEnvironments(EnvironmentsRestStub): + def __hash__(self): + return hash("ListEnvironments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.ListEnvironmentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.ListEnvironmentsResponse: + r"""Call the list environments method over HTTP. + + Args: + request (~.environment.ListEnvironmentsRequest): + The request object. The request message for + [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. + + 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: + ~.environment.ListEnvironmentsResponse: + The response message for + [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/environments", + }, + ] + request, metadata = self._interceptor.pre_list_environments( + request, metadata + ) + pb_request = environment.ListEnvironmentsRequest.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 = environment.ListEnvironmentsResponse() + pb_resp = environment.ListEnvironmentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_environments(resp) + return resp + + class _LookupEnvironmentHistory(EnvironmentsRestStub): + def __hash__(self): + return hash("LookupEnvironmentHistory") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.LookupEnvironmentHistoryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.LookupEnvironmentHistoryResponse: + r"""Call the lookup environment + history method over HTTP. + + Args: + request (~.environment.LookupEnvironmentHistoryRequest): + The request object. The request message for + [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. + + 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: + ~.environment.LookupEnvironmentHistoryResponse: + The response message for + [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*}:lookupEnvironmentHistory", + }, + ] + request, metadata = self._interceptor.pre_lookup_environment_history( + request, metadata + ) + pb_request = environment.LookupEnvironmentHistoryRequest.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 = environment.LookupEnvironmentHistoryResponse() + pb_resp = environment.LookupEnvironmentHistoryResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_lookup_environment_history(resp) + return resp + + class _RunContinuousTest(EnvironmentsRestStub): + def __hash__(self): + return hash("RunContinuousTest") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: environment.RunContinuousTestRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the run continuous test method over HTTP. + + Args: + request (~.environment.RunContinuousTestRequest): + The request object. The request message for + [Environments.RunContinuousTest][google.cloud.dialogflow.cx.v3beta1.Environments.RunContinuousTest]. + + 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": "/v3beta1/{environment=projects/*/locations/*/agents/*/environments/*}:runContinuousTest", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_run_continuous_test( + request, metadata + ) + pb_request = environment.RunContinuousTestRequest.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_run_continuous_test(resp) + return resp + + class _UpdateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("UpdateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_environment.UpdateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the update environment method over HTTP. + + Args: + request (~.gcdc_environment.UpdateEnvironmentRequest): + The request object. The request message for + [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.UpdateEnvironment]. + + 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": "patch", + "uri": "/v3beta1/{environment.name=projects/*/locations/*/agents/*/environments/*}", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_update_environment( + request, metadata + ) + pb_request = gcdc_environment.UpdateEnvironmentRequest.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_update_environment(resp) + return resp + + @property + def create_environment( + self, + ) -> Callable[ + [gcdc_environment.CreateEnvironmentRequest], 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._CreateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_environment( + self, + ) -> Callable[[environment.DeleteEnvironmentRequest], 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._DeleteEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def deploy_flow( + self, + ) -> Callable[[environment.DeployFlowRequest], 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._DeployFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_environment( + self, + ) -> Callable[[environment.GetEnvironmentRequest], environment.Environment]: + # 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._GetEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_continuous_test_results( + self, + ) -> Callable[ + [environment.ListContinuousTestResultsRequest], + environment.ListContinuousTestResultsResponse, + ]: + # 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._ListContinuousTestResults(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_environments( + self, + ) -> Callable[ + [environment.ListEnvironmentsRequest], environment.ListEnvironmentsResponse + ]: + # 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._ListEnvironments(self._session, self._host, self._interceptor) # type: ignore + + @property + def lookup_environment_history( + self, + ) -> Callable[ + [environment.LookupEnvironmentHistoryRequest], + environment.LookupEnvironmentHistoryResponse, + ]: + # 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._LookupEnvironmentHistory(self._session, self._host, self._interceptor) # type: ignore + + @property + def run_continuous_test( + self, + ) -> Callable[[environment.RunContinuousTestRequest], 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._RunContinuousTest(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_environment( + self, + ) -> Callable[ + [gcdc_environment.UpdateEnvironmentRequest], 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._UpdateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EnvironmentsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EnvironmentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py index 271d2985..daef0eb8 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py @@ -57,6 +57,7 @@ from .transports.base import ExperimentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import ExperimentsGrpcTransport from .transports.grpc_asyncio import ExperimentsGrpcAsyncIOTransport +from .transports.rest import ExperimentsRestTransport class ExperimentsClientMeta(type): @@ -70,6 +71,7 @@ class ExperimentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ExperimentsTransport]] _transport_registry["grpc"] = ExperimentsGrpcTransport _transport_registry["grpc_asyncio"] = ExperimentsGrpcAsyncIOTransport + _transport_registry["rest"] = ExperimentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/__init__.py index 3a6183c3..7aeb3d45 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/__init__.py @@ -19,15 +19,20 @@ from .base import ExperimentsTransport from .grpc import ExperimentsGrpcTransport from .grpc_asyncio import ExperimentsGrpcAsyncIOTransport +from .rest import ExperimentsRestTransport +from .rest import ExperimentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ExperimentsTransport]] _transport_registry["grpc"] = ExperimentsGrpcTransport _transport_registry["grpc_asyncio"] = ExperimentsGrpcAsyncIOTransport +_transport_registry["rest"] = ExperimentsRestTransport __all__ = ( "ExperimentsTransport", "ExperimentsGrpcTransport", "ExperimentsGrpcAsyncIOTransport", + "ExperimentsRestTransport", + "ExperimentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/rest.py new file mode 100644 index 00000000..0477a862 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/rest.py @@ -0,0 +1,1569 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import experiment +from google.cloud.dialogflowcx_v3beta1.types import experiment as gcdc_experiment +from google.protobuf import empty_pb2 # type: ignore + +from .base import ExperimentsTransport, 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 ExperimentsRestInterceptor: + """Interceptor for Experiments. + + 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 ExperimentsRestTransport. + + .. code-block:: python + class MyCustomExperimentsInterceptor(ExperimentsRestInterceptor): + def pre_create_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_experiments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_experiments(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_start_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_start_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_stop_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_stop_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_experiment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_experiment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ExperimentsRestTransport(interceptor=MyCustomExperimentsInterceptor()) + client = ExperimentsClient(transport=transport) + + + """ + + def pre_create_experiment( + self, + request: gcdc_experiment.CreateExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_experiment.CreateExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_create_experiment( + self, response: gcdc_experiment.Experiment + ) -> gcdc_experiment.Experiment: + """Post-rpc interceptor for create_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_delete_experiment( + self, + request: experiment.DeleteExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.DeleteExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def pre_get_experiment( + self, + request: experiment.GetExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.GetExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_get_experiment( + self, response: experiment.Experiment + ) -> experiment.Experiment: + """Post-rpc interceptor for get_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_list_experiments( + self, + request: experiment.ListExperimentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.ListExperimentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_experiments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_list_experiments( + self, response: experiment.ListExperimentsResponse + ) -> experiment.ListExperimentsResponse: + """Post-rpc interceptor for list_experiments + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_start_experiment( + self, + request: experiment.StartExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.StartExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for start_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_start_experiment( + self, response: experiment.Experiment + ) -> experiment.Experiment: + """Post-rpc interceptor for start_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_stop_experiment( + self, + request: experiment.StopExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[experiment.StopExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for stop_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_stop_experiment( + self, response: experiment.Experiment + ) -> experiment.Experiment: + """Post-rpc interceptor for stop_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_update_experiment( + self, + request: gcdc_experiment.UpdateExperimentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_experiment.UpdateExperimentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_experiment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_update_experiment( + self, response: gcdc_experiment.Experiment + ) -> gcdc_experiment.Experiment: + """Post-rpc interceptor for update_experiment + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Experiments 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Experiments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Experiments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ExperimentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ExperimentsRestInterceptor + + +class ExperimentsRestTransport(ExperimentsTransport): + """REST backend transport for Experiments. + + Service for managing + [Experiments][google.cloud.dialogflow.cx.v3beta1.Experiment]. + + 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 = "dialogflow.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[ExperimentsRestInterceptor] = 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 ExperimentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("CreateExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_experiment.CreateExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_experiment.Experiment: + r"""Call the create experiment method over HTTP. + + Args: + request (~.gcdc_experiment.CreateExperimentRequest): + The request object. The request message for + [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.CreateExperiment]. + + 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: + ~.gcdc_experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/experiments", + "body": "experiment", + }, + ] + request, metadata = self._interceptor.pre_create_experiment( + request, metadata + ) + pb_request = gcdc_experiment.CreateExperimentRequest.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 = gcdc_experiment.Experiment() + pb_resp = gcdc_experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_experiment(resp) + return resp + + class _DeleteExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("DeleteExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.DeleteExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete experiment method over HTTP. + + Args: + request (~.experiment.DeleteExperimentRequest): + The request object. The request message for + [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.DeleteExperiment]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_experiment( + request, metadata + ) + pb_request = experiment.DeleteExperimentRequest.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 _GetExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("GetExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.GetExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.Experiment: + r"""Call the get experiment method over HTTP. + + Args: + request (~.experiment.GetExperimentRequest): + The request object. The request message for + [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.GetExperiment]. + + 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: + ~.experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_experiment(request, metadata) + pb_request = experiment.GetExperimentRequest.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 = experiment.Experiment() + pb_resp = experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_experiment(resp) + return resp + + class _ListExperiments(ExperimentsRestStub): + def __hash__(self): + return hash("ListExperiments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.ListExperimentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.ListExperimentsResponse: + r"""Call the list experiments method over HTTP. + + Args: + request (~.experiment.ListExperimentsRequest): + The request object. The request message for + [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. + + 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: + ~.experiment.ListExperimentsResponse: + The response message for + [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/experiments", + }, + ] + request, metadata = self._interceptor.pre_list_experiments( + request, metadata + ) + pb_request = experiment.ListExperimentsRequest.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 = experiment.ListExperimentsResponse() + pb_resp = experiment.ListExperimentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_experiments(resp) + return resp + + class _StartExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("StartExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.StartExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.Experiment: + r"""Call the start experiment method over HTTP. + + Args: + request (~.experiment.StartExperimentRequest): + The request object. The request message for + [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.StartExperiment]. + + 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: + ~.experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:start", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_start_experiment( + request, metadata + ) + pb_request = experiment.StartExperimentRequest.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 = experiment.Experiment() + pb_resp = experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_start_experiment(resp) + return resp + + class _StopExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("StopExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: experiment.StopExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> experiment.Experiment: + r"""Call the stop experiment method over HTTP. + + Args: + request (~.experiment.StopExperimentRequest): + The request object. The request message for + [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.StopExperiment]. + + 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: + ~.experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:stop", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_stop_experiment(request, metadata) + pb_request = experiment.StopExperimentRequest.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 = experiment.Experiment() + pb_resp = experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_stop_experiment(resp) + return resp + + class _UpdateExperiment(ExperimentsRestStub): + def __hash__(self): + return hash("UpdateExperiment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_experiment.UpdateExperimentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_experiment.Experiment: + r"""Call the update experiment method over HTTP. + + Args: + request (~.gcdc_experiment.UpdateExperimentRequest): + The request object. The request message for + [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.UpdateExperiment]. + + 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: + ~.gcdc_experiment.Experiment: + Represents an experiment in an + environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{experiment.name=projects/*/locations/*/agents/*/environments/*/experiments/*}", + "body": "experiment", + }, + ] + request, metadata = self._interceptor.pre_update_experiment( + request, metadata + ) + pb_request = gcdc_experiment.UpdateExperimentRequest.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 = gcdc_experiment.Experiment() + pb_resp = gcdc_experiment.Experiment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_experiment(resp) + return resp + + @property + def create_experiment( + self, + ) -> Callable[ + [gcdc_experiment.CreateExperimentRequest], gcdc_experiment.Experiment + ]: + # 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._CreateExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_experiment( + self, + ) -> Callable[[experiment.DeleteExperimentRequest], 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._DeleteExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_experiment( + self, + ) -> Callable[[experiment.GetExperimentRequest], experiment.Experiment]: + # 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._GetExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_experiments( + self, + ) -> Callable[ + [experiment.ListExperimentsRequest], experiment.ListExperimentsResponse + ]: + # 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._ListExperiments(self._session, self._host, self._interceptor) # type: ignore + + @property + def start_experiment( + self, + ) -> Callable[[experiment.StartExperimentRequest], experiment.Experiment]: + # 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._StartExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def stop_experiment( + self, + ) -> Callable[[experiment.StopExperimentRequest], experiment.Experiment]: + # 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._StopExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_experiment( + self, + ) -> Callable[ + [gcdc_experiment.UpdateExperimentRequest], gcdc_experiment.Experiment + ]: + # 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._UpdateExperiment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ExperimentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ExperimentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ExperimentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ExperimentsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ExperimentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ExperimentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/client.py b/google/cloud/dialogflowcx_v3beta1/services/flows/client.py index 6c1e637f..5dde6d9a 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/client.py @@ -62,6 +62,7 @@ from .transports.base import FlowsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import FlowsGrpcTransport from .transports.grpc_asyncio import FlowsGrpcAsyncIOTransport +from .transports.rest import FlowsRestTransport class FlowsClientMeta(type): @@ -75,6 +76,7 @@ class FlowsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[FlowsTransport]] _transport_registry["grpc"] = FlowsGrpcTransport _transport_registry["grpc_asyncio"] = FlowsGrpcAsyncIOTransport + _transport_registry["rest"] = FlowsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/__init__.py index d27c76de..5a0a6683 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/__init__.py @@ -19,15 +19,20 @@ from .base import FlowsTransport from .grpc import FlowsGrpcTransport from .grpc_asyncio import FlowsGrpcAsyncIOTransport +from .rest import FlowsRestTransport +from .rest import FlowsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[FlowsTransport]] _transport_registry["grpc"] = FlowsGrpcTransport _transport_registry["grpc_asyncio"] = FlowsGrpcAsyncIOTransport +_transport_registry["rest"] = FlowsRestTransport __all__ = ( "FlowsTransport", "FlowsGrpcTransport", "FlowsGrpcAsyncIOTransport", + "FlowsRestTransport", + "FlowsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/rest.py new file mode 100644 index 00000000..efba88cb --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/rest.py @@ -0,0 +1,2044 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import flow +from google.cloud.dialogflowcx_v3beta1.types import flow as gcdc_flow +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import FlowsTransport, 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 FlowsRestInterceptor: + """Interceptor for Flows. + + 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 FlowsRestTransport. + + .. code-block:: python + class MyCustomFlowsInterceptor(FlowsRestInterceptor): + def pre_create_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_flow_validation_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_flow_validation_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_flows(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_flows(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_train_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_train_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_flow(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_validate_flow(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_validate_flow(self, response): + logging.log(f"Received response: {response}") + return response + + transport = FlowsRestTransport(interceptor=MyCustomFlowsInterceptor()) + client = FlowsClient(transport=transport) + + + """ + + def pre_create_flow( + self, request: gcdc_flow.CreateFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_flow.CreateFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_create_flow(self, response: gcdc_flow.Flow) -> gcdc_flow.Flow: + """Post-rpc interceptor for create_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_delete_flow( + self, request: flow.DeleteFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.DeleteFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def pre_export_flow( + self, request: flow.ExportFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ExportFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_export_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_get_flow( + self, request: flow.GetFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.GetFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_flow(self, response: flow.Flow) -> flow.Flow: + """Post-rpc interceptor for get_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_get_flow_validation_result( + self, + request: flow.GetFlowValidationResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[flow.GetFlowValidationResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_flow_validation_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_flow_validation_result( + self, response: flow.FlowValidationResult + ) -> flow.FlowValidationResult: + """Post-rpc interceptor for get_flow_validation_result + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_import_flow( + self, request: flow.ImportFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ImportFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_import_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_list_flows( + self, request: flow.ListFlowsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ListFlowsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_flows + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_list_flows( + self, response: flow.ListFlowsResponse + ) -> flow.ListFlowsResponse: + """Post-rpc interceptor for list_flows + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_train_flow( + self, request: flow.TrainFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.TrainFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for train_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_train_flow( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for train_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_update_flow( + self, request: gcdc_flow.UpdateFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_flow.UpdateFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_update_flow(self, response: gcdc_flow.Flow) -> gcdc_flow.Flow: + """Post-rpc interceptor for update_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_validate_flow( + self, request: flow.ValidateFlowRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[flow.ValidateFlowRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for validate_flow + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_validate_flow( + self, response: flow.FlowValidationResult + ) -> flow.FlowValidationResult: + """Post-rpc interceptor for validate_flow + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Flows 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Flows server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Flows server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class FlowsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: FlowsRestInterceptor + + +class FlowsRestTransport(FlowsTransport): + """REST backend transport for Flows. + + Service for managing + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow]. + + 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 = "dialogflow.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[FlowsRestInterceptor] = 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 FlowsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/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="v3beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateFlow(FlowsRestStub): + def __hash__(self): + return hash("CreateFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_flow.CreateFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_flow.Flow: + r"""Call the create flow method over HTTP. + + Args: + request (~.gcdc_flow.CreateFlowRequest): + The request object. The request message for + [Flows.CreateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.CreateFlow]. + + 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: + ~.gcdc_flow.Flow: + Flows represents the conversation + flows when you build your chatbot agent. + A flow consists of many pages connected + by the transition routes. Conversations + always start with the built-in Start + Flow (with an all-0 ID). Transition + routes can direct the conversation + session from the current flow (parent + flow) to another flow (sub flow). When + the sub flow is finished, Dialogflow + will bring the session back to the + parent flow, where the sub flow is + started. + + Usually, when a transition route is + followed by a matched intent, the intent + will be "consumed". This means the + intent won't activate more transition + routes. However, when the followed + transition route moves the conversation + session into a different flow, the + matched intent can be carried over and + to be consumed in the target flow. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/flows", + "body": "flow", + }, + ] + request, metadata = self._interceptor.pre_create_flow(request, metadata) + pb_request = gcdc_flow.CreateFlowRequest.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 = gcdc_flow.Flow() + pb_resp = gcdc_flow.Flow.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_flow(resp) + return resp + + class _DeleteFlow(FlowsRestStub): + def __hash__(self): + return hash("DeleteFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.DeleteFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete flow method over HTTP. + + Args: + request (~.flow.DeleteFlowRequest): + The request object. The request message for + [Flows.DeleteFlow][google.cloud.dialogflow.cx.v3beta1.Flows.DeleteFlow]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_flow(request, metadata) + pb_request = flow.DeleteFlowRequest.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 _ExportFlow(FlowsRestStub): + def __hash__(self): + return hash("ExportFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ExportFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export flow method over HTTP. + + Args: + request (~.flow.ExportFlowRequest): + The request object. The request message for + [Flows.ExportFlow][google.cloud.dialogflow.cx.v3beta1.Flows.ExportFlow]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_flow(request, metadata) + pb_request = flow.ExportFlowRequest.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_flow(resp) + return resp + + class _GetFlow(FlowsRestStub): + def __hash__(self): + return hash("GetFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.GetFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.Flow: + r"""Call the get flow method over HTTP. + + Args: + request (~.flow.GetFlowRequest): + The request object. The response message for + [Flows.GetFlow][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlow]. + + 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: + ~.flow.Flow: + Flows represents the conversation + flows when you build your chatbot agent. + A flow consists of many pages connected + by the transition routes. Conversations + always start with the built-in Start + Flow (with an all-0 ID). Transition + routes can direct the conversation + session from the current flow (parent + flow) to another flow (sub flow). When + the sub flow is finished, Dialogflow + will bring the session back to the + parent flow, where the sub flow is + started. + + Usually, when a transition route is + followed by a matched intent, the intent + will be "consumed". This means the + intent won't activate more transition + routes. However, when the followed + transition route moves the conversation + session into a different flow, the + matched intent can be carried over and + to be consumed in the target flow. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}", + }, + ] + request, metadata = self._interceptor.pre_get_flow(request, metadata) + pb_request = flow.GetFlowRequest.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 = flow.Flow() + pb_resp = flow.Flow.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_flow(resp) + return resp + + class _GetFlowValidationResult(FlowsRestStub): + def __hash__(self): + return hash("GetFlowValidationResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.GetFlowValidationResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Call the get flow validation + result method over HTTP. + + Args: + request (~.flow.GetFlowValidationResultRequest): + The request object. The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + 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: + ~.flow.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/validationResult}", + }, + ] + request, metadata = self._interceptor.pre_get_flow_validation_result( + request, metadata + ) + pb_request = flow.GetFlowValidationResultRequest.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 = flow.FlowValidationResult() + pb_resp = flow.FlowValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_flow_validation_result(resp) + return resp + + class _ImportFlow(FlowsRestStub): + def __hash__(self): + return hash("ImportFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ImportFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import flow method over HTTP. + + Args: + request (~.flow.ImportFlowRequest): + The request object. The request message for + [Flows.ImportFlow][google.cloud.dialogflow.cx.v3beta1.Flows.ImportFlow]. + + 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": "/v3beta1/{parent=projects/*/locations/*/agents/*}/flows:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_flow(request, metadata) + pb_request = flow.ImportFlowRequest.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_import_flow(resp) + return resp + + class _ListFlows(FlowsRestStub): + def __hash__(self): + return hash("ListFlows") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ListFlowsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.ListFlowsResponse: + r"""Call the list flows method over HTTP. + + Args: + request (~.flow.ListFlowsRequest): + The request object. The request message for + [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. + + 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: + ~.flow.ListFlowsResponse: + The response message for + [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/flows", + }, + ] + request, metadata = self._interceptor.pre_list_flows(request, metadata) + pb_request = flow.ListFlowsRequest.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 = flow.ListFlowsResponse() + pb_resp = flow.ListFlowsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_flows(resp) + return resp + + class _TrainFlow(FlowsRestStub): + def __hash__(self): + return hash("TrainFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.TrainFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the train flow method over HTTP. + + Args: + request (~.flow.TrainFlowRequest): + The request object. The request message for + [Flows.TrainFlow][google.cloud.dialogflow.cx.v3beta1.Flows.TrainFlow]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}:train", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_train_flow(request, metadata) + pb_request = flow.TrainFlowRequest.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_train_flow(resp) + return resp + + class _UpdateFlow(FlowsRestStub): + def __hash__(self): + return hash("UpdateFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_flow.UpdateFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_flow.Flow: + r"""Call the update flow method over HTTP. + + Args: + request (~.gcdc_flow.UpdateFlowRequest): + The request object. The request message for + [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.UpdateFlow]. + + 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: + ~.gcdc_flow.Flow: + Flows represents the conversation + flows when you build your chatbot agent. + A flow consists of many pages connected + by the transition routes. Conversations + always start with the built-in Start + Flow (with an all-0 ID). Transition + routes can direct the conversation + session from the current flow (parent + flow) to another flow (sub flow). When + the sub flow is finished, Dialogflow + will bring the session back to the + parent flow, where the sub flow is + started. + + Usually, when a transition route is + followed by a matched intent, the intent + will be "consumed". This means the + intent won't activate more transition + routes. However, when the followed + transition route moves the conversation + session into a different flow, the + matched intent can be carried over and + to be consumed in the target flow. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{flow.name=projects/*/locations/*/agents/*/flows/*}", + "body": "flow", + }, + ] + request, metadata = self._interceptor.pre_update_flow(request, metadata) + pb_request = gcdc_flow.UpdateFlowRequest.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 = gcdc_flow.Flow() + pb_resp = gcdc_flow.Flow.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_flow(resp) + return resp + + class _ValidateFlow(FlowsRestStub): + def __hash__(self): + return hash("ValidateFlow") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: flow.ValidateFlowRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Call the validate flow method over HTTP. + + Args: + request (~.flow.ValidateFlowRequest): + The request object. The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.ValidateFlow]. + + 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: + ~.flow.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}:validate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_validate_flow(request, metadata) + pb_request = flow.ValidateFlowRequest.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 = flow.FlowValidationResult() + pb_resp = flow.FlowValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_validate_flow(resp) + return resp + + @property + def create_flow(self) -> Callable[[gcdc_flow.CreateFlowRequest], gcdc_flow.Flow]: + # 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._CreateFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_flow(self) -> Callable[[flow.DeleteFlowRequest], 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._DeleteFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_flow( + self, + ) -> Callable[[flow.ExportFlowRequest], 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._ExportFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_flow(self) -> Callable[[flow.GetFlowRequest], flow.Flow]: + # 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._GetFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_flow_validation_result( + self, + ) -> Callable[[flow.GetFlowValidationResultRequest], flow.FlowValidationResult]: + # 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._GetFlowValidationResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_flow( + self, + ) -> Callable[[flow.ImportFlowRequest], 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._ImportFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_flows(self) -> Callable[[flow.ListFlowsRequest], flow.ListFlowsResponse]: + # 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._ListFlows(self._session, self._host, self._interceptor) # type: ignore + + @property + def train_flow(self) -> Callable[[flow.TrainFlowRequest], 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._TrainFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_flow(self) -> Callable[[gcdc_flow.UpdateFlowRequest], gcdc_flow.Flow]: + # 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._UpdateFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def validate_flow( + self, + ) -> Callable[[flow.ValidateFlowRequest], flow.FlowValidationResult]: + # 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._ValidateFlow(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(FlowsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(FlowsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(FlowsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(FlowsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(FlowsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("FlowsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/client.py b/google/cloud/dialogflowcx_v3beta1/services/intents/client.py index ec876b95..06041c58 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/client.py @@ -55,6 +55,7 @@ from .transports.base import IntentsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import IntentsGrpcTransport from .transports.grpc_asyncio import IntentsGrpcAsyncIOTransport +from .transports.rest import IntentsRestTransport class IntentsClientMeta(type): @@ -68,6 +69,7 @@ class IntentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport + _transport_registry["rest"] = IntentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/__init__.py index 876b5cd1..a7e402a6 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/__init__.py @@ -19,15 +19,20 @@ from .base import IntentsTransport from .grpc import IntentsGrpcTransport from .grpc_asyncio import IntentsGrpcAsyncIOTransport +from .rest import IntentsRestTransport +from .rest import IntentsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport +_transport_registry["rest"] = IntentsRestTransport __all__ = ( "IntentsTransport", "IntentsGrpcTransport", "IntentsGrpcAsyncIOTransport", + "IntentsRestTransport", + "IntentsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/rest.py new file mode 100644 index 00000000..b793a934 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/rest.py @@ -0,0 +1,1274 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import intent +from google.cloud.dialogflowcx_v3beta1.types import intent as gcdc_intent +from google.protobuf import empty_pb2 # type: ignore + +from .base import IntentsTransport, 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 IntentsRestInterceptor: + """Interceptor for Intents. + + 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 IntentsRestTransport. + + .. code-block:: python + class MyCustomIntentsInterceptor(IntentsRestInterceptor): + def pre_create_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = IntentsRestTransport(interceptor=MyCustomIntentsInterceptor()) + client = IntentsClient(transport=transport) + + + """ + + def pre_create_intent( + self, + request: gcdc_intent.CreateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_intent.CreateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_create_intent(self, response: gcdc_intent.Intent) -> gcdc_intent.Intent: + """Post-rpc interceptor for create_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_delete_intent( + self, request: intent.DeleteIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.DeleteIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def pre_get_intent( + self, request: intent.GetIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.GetIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_intent(self, response: intent.Intent) -> intent.Intent: + """Post-rpc interceptor for get_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_intents( + self, request: intent.ListIntentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.ListIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_intents( + self, response: intent.ListIntentsResponse + ) -> intent.ListIntentsResponse: + """Post-rpc interceptor for list_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_update_intent( + self, + request: gcdc_intent.UpdateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_intent.UpdateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_update_intent(self, response: gcdc_intent.Intent) -> gcdc_intent.Intent: + """Post-rpc interceptor for update_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class IntentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: IntentsRestInterceptor + + +class IntentsRestTransport(IntentsTransport): + """REST backend transport for Intents. + + Service for managing + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent]. + + 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 = "dialogflow.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[IntentsRestInterceptor] = 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 IntentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateIntent(IntentsRestStub): + def __hash__(self): + return hash("CreateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_intent.CreateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_intent.Intent: + r"""Call the create intent method over HTTP. + + Args: + request (~.gcdc_intent.CreateIntentRequest): + The request object. The request message for + [Intents.CreateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.CreateIntent]. + + 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: + ~.gcdc_intent.Intent: + An intent represents a user's intent + to interact with a conversational agent. + You can provide information for the + Dialogflow API to use to match user + input to an intent by adding training + phrases (i.e., examples of user input) + to your intent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/intents", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_create_intent(request, metadata) + pb_request = gcdc_intent.CreateIntentRequest.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 = gcdc_intent.Intent() + pb_resp = gcdc_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_intent(resp) + return resp + + class _DeleteIntent(IntentsRestStub): + def __hash__(self): + return hash("DeleteIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: intent.DeleteIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete intent method over HTTP. + + Args: + request (~.intent.DeleteIntentRequest): + The request object. The request message for + [Intents.DeleteIntent][google.cloud.dialogflow.cx.v3beta1.Intents.DeleteIntent]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_intent(request, metadata) + pb_request = intent.DeleteIntentRequest.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 _GetIntent(IntentsRestStub): + def __hash__(self): + return hash("GetIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: intent.GetIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.Intent: + r"""Call the get intent method over HTTP. + + Args: + request (~.intent.GetIntentRequest): + The request object. The request message for + [Intents.GetIntent][google.cloud.dialogflow.cx.v3beta1.Intents.GetIntent]. + + 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: + ~.intent.Intent: + An intent represents a user's intent + to interact with a conversational agent. + You can provide information for the + Dialogflow API to use to match user + input to an intent by adding training + phrases (i.e., examples of user input) + to your intent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_intent(request, metadata) + pb_request = intent.GetIntentRequest.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 = intent.Intent() + pb_resp = intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_intent(resp) + return resp + + class _ListIntents(IntentsRestStub): + def __hash__(self): + return hash("ListIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: intent.ListIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.ListIntentsResponse: + r"""Call the list intents method over HTTP. + + Args: + request (~.intent.ListIntentsRequest): + The request object. The request message for + [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. + + 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: + ~.intent.ListIntentsResponse: + The response message for + [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/intents", + }, + ] + request, metadata = self._interceptor.pre_list_intents(request, metadata) + pb_request = intent.ListIntentsRequest.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 = intent.ListIntentsResponse() + pb_resp = intent.ListIntentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_intents(resp) + return resp + + class _UpdateIntent(IntentsRestStub): + def __hash__(self): + return hash("UpdateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_intent.UpdateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_intent.Intent: + r"""Call the update intent method over HTTP. + + Args: + request (~.gcdc_intent.UpdateIntentRequest): + The request object. The request message for + [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.UpdateIntent]. + + 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: + ~.gcdc_intent.Intent: + An intent represents a user's intent + to interact with a conversational agent. + You can provide information for the + Dialogflow API to use to match user + input to an intent by adding training + phrases (i.e., examples of user input) + to your intent. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{intent.name=projects/*/locations/*/agents/*/intents/*}", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_update_intent(request, metadata) + pb_request = gcdc_intent.UpdateIntentRequest.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 = gcdc_intent.Intent() + pb_resp = gcdc_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_intent(resp) + return resp + + @property + def create_intent( + self, + ) -> Callable[[gcdc_intent.CreateIntentRequest], gcdc_intent.Intent]: + # 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._CreateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_intent(self) -> Callable[[intent.DeleteIntentRequest], 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._DeleteIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_intent(self) -> Callable[[intent.GetIntentRequest], intent.Intent]: + # 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._GetIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_intents( + self, + ) -> Callable[[intent.ListIntentsRequest], intent.ListIntentsResponse]: + # 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._ListIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_intent( + self, + ) -> Callable[[gcdc_intent.UpdateIntentRequest], gcdc_intent.Intent]: + # 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._UpdateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(IntentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(IntentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(IntentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(IntentsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(IntentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("IntentsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/client.py b/google/cloud/dialogflowcx_v3beta1/services/pages/client.py index 6768a75a..2bf41727 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/client.py @@ -56,6 +56,7 @@ from .transports.base import PagesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import PagesGrpcTransport from .transports.grpc_asyncio import PagesGrpcAsyncIOTransport +from .transports.rest import PagesRestTransport class PagesClientMeta(type): @@ -69,6 +70,7 @@ class PagesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[PagesTransport]] _transport_registry["grpc"] = PagesGrpcTransport _transport_registry["grpc_asyncio"] = PagesGrpcAsyncIOTransport + _transport_registry["rest"] = PagesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/__init__.py index fd23f06e..387c6a3a 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/__init__.py @@ -19,15 +19,20 @@ from .base import PagesTransport from .grpc import PagesGrpcTransport from .grpc_asyncio import PagesGrpcAsyncIOTransport +from .rest import PagesRestTransport +from .rest import PagesRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[PagesTransport]] _transport_registry["grpc"] = PagesGrpcTransport _transport_registry["grpc_asyncio"] = PagesGrpcAsyncIOTransport +_transport_registry["rest"] = PagesRestTransport __all__ = ( "PagesTransport", "PagesGrpcTransport", "PagesGrpcAsyncIOTransport", + "PagesRestTransport", + "PagesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/rest.py new file mode 100644 index 00000000..9ee68d25 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/rest.py @@ -0,0 +1,1306 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import page +from google.cloud.dialogflowcx_v3beta1.types import page as gcdc_page +from google.protobuf import empty_pb2 # type: ignore + +from .base import PagesTransport, 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 PagesRestInterceptor: + """Interceptor for Pages. + + 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 PagesRestTransport. + + .. code-block:: python + class MyCustomPagesInterceptor(PagesRestInterceptor): + def pre_create_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_page(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_page(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_pages(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_pages(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_page(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_page(self, response): + logging.log(f"Received response: {response}") + return response + + transport = PagesRestTransport(interceptor=MyCustomPagesInterceptor()) + client = PagesClient(transport=transport) + + + """ + + def pre_create_page( + self, request: gcdc_page.CreatePageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_page.CreatePageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_create_page(self, response: gcdc_page.Page) -> gcdc_page.Page: + """Post-rpc interceptor for create_page + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_delete_page( + self, request: page.DeletePageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[page.DeletePageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def pre_get_page( + self, request: page.GetPageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[page.GetPageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_get_page(self, response: page.Page) -> page.Page: + """Post-rpc interceptor for get_page + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_list_pages( + self, request: page.ListPagesRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[page.ListPagesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_pages + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_list_pages( + self, response: page.ListPagesResponse + ) -> page.ListPagesResponse: + """Post-rpc interceptor for list_pages + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_update_page( + self, request: gcdc_page.UpdatePageRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcdc_page.UpdatePageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_page + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_update_page(self, response: gcdc_page.Page) -> gcdc_page.Page: + """Post-rpc interceptor for update_page + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Pages 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Pages server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Pages server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class PagesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: PagesRestInterceptor + + +class PagesRestTransport(PagesTransport): + """REST backend transport for Pages. + + Service for managing + [Pages][google.cloud.dialogflow.cx.v3beta1.Page]. + + 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 = "dialogflow.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[PagesRestInterceptor] = 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 PagesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreatePage(PagesRestStub): + def __hash__(self): + return hash("CreatePage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_page.CreatePageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_page.Page: + r"""Call the create page method over HTTP. + + Args: + request (~.gcdc_page.CreatePageRequest): + The request object. The request message for + [Pages.CreatePage][google.cloud.dialogflow.cx.v3beta1.Pages.CreatePage]. + + 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: + ~.gcdc_page.Page: + A Dialogflow CX conversation (session) can be described + and visualized as a state machine. The states of a CX + session are represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on the + topics the flow is designed for. At any given moment, + exactly one page is the current page, the current page + is considered active, and the flow associated with that + page is considered active. Every flow has a special + start page. When a flow initially becomes active, the + start page page becomes the current page. For each + conversational turn, the current page will either stay + the same or transition to another page. + + You configure each page to collect information from the + end-user that is relevant for the conversational state + represented by the page. + + For more information, see the `Page + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/pages", + "body": "page", + }, + ] + request, metadata = self._interceptor.pre_create_page(request, metadata) + pb_request = gcdc_page.CreatePageRequest.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 = gcdc_page.Page() + pb_resp = gcdc_page.Page.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_page(resp) + return resp + + class _DeletePage(PagesRestStub): + def __hash__(self): + return hash("DeletePage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: page.DeletePageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete page method over HTTP. + + Args: + request (~.page.DeletePageRequest): + The request object. The request message for + [Pages.DeletePage][google.cloud.dialogflow.cx.v3beta1.Pages.DeletePage]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/pages/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_page(request, metadata) + pb_request = page.DeletePageRequest.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 _GetPage(PagesRestStub): + def __hash__(self): + return hash("GetPage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: page.GetPageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> page.Page: + r"""Call the get page method over HTTP. + + Args: + request (~.page.GetPageRequest): + The request object. The request message for + [Pages.GetPage][google.cloud.dialogflow.cx.v3beta1.Pages.GetPage]. + + 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: + ~.page.Page: + A Dialogflow CX conversation (session) can be described + and visualized as a state machine. The states of a CX + session are represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on the + topics the flow is designed for. At any given moment, + exactly one page is the current page, the current page + is considered active, and the flow associated with that + page is considered active. Every flow has a special + start page. When a flow initially becomes active, the + start page page becomes the current page. For each + conversational turn, the current page will either stay + the same or transition to another page. + + You configure each page to collect information from the + end-user that is relevant for the conversational state + represented by the page. + + For more information, see the `Page + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/pages/*}", + }, + ] + request, metadata = self._interceptor.pre_get_page(request, metadata) + pb_request = page.GetPageRequest.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 = page.Page() + pb_resp = page.Page.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_page(resp) + return resp + + class _ListPages(PagesRestStub): + def __hash__(self): + return hash("ListPages") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: page.ListPagesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> page.ListPagesResponse: + r"""Call the list pages method over HTTP. + + Args: + request (~.page.ListPagesRequest): + The request object. The request message for + [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. + + 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: + ~.page.ListPagesResponse: + The response message for + [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/pages", + }, + ] + request, metadata = self._interceptor.pre_list_pages(request, metadata) + pb_request = page.ListPagesRequest.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 = page.ListPagesResponse() + pb_resp = page.ListPagesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_pages(resp) + return resp + + class _UpdatePage(PagesRestStub): + def __hash__(self): + return hash("UpdatePage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_page.UpdatePageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_page.Page: + r"""Call the update page method over HTTP. + + Args: + request (~.gcdc_page.UpdatePageRequest): + The request object. The request message for + [Pages.UpdatePage][google.cloud.dialogflow.cx.v3beta1.Pages.UpdatePage]. + + 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: + ~.gcdc_page.Page: + A Dialogflow CX conversation (session) can be described + and visualized as a state machine. The states of a CX + session are represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on the + topics the flow is designed for. At any given moment, + exactly one page is the current page, the current page + is considered active, and the flow associated with that + page is considered active. Every flow has a special + start page. When a flow initially becomes active, the + start page page becomes the current page. For each + conversational turn, the current page will either stay + the same or transition to another page. + + You configure each page to collect information from the + end-user that is relevant for the conversational state + represented by the page. + + For more information, see the `Page + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{page.name=projects/*/locations/*/agents/*/flows/*/pages/*}", + "body": "page", + }, + ] + request, metadata = self._interceptor.pre_update_page(request, metadata) + pb_request = gcdc_page.UpdatePageRequest.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 = gcdc_page.Page() + pb_resp = gcdc_page.Page.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_page(resp) + return resp + + @property + def create_page(self) -> Callable[[gcdc_page.CreatePageRequest], gcdc_page.Page]: + # 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._CreatePage(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_page(self) -> Callable[[page.DeletePageRequest], 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._DeletePage(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_page(self) -> Callable[[page.GetPageRequest], page.Page]: + # 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._GetPage(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_pages(self) -> Callable[[page.ListPagesRequest], page.ListPagesResponse]: + # 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._ListPages(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_page(self) -> Callable[[gcdc_page.UpdatePageRequest], gcdc_page.Page]: + # 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._UpdatePage(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(PagesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(PagesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(PagesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(PagesRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(PagesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("PagesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py index 7651ec43..7d1e534f 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py @@ -57,6 +57,7 @@ from .transports.base import SecuritySettingsServiceTransport, DEFAULT_CLIENT_INFO from .transports.grpc import SecuritySettingsServiceGrpcTransport from .transports.grpc_asyncio import SecuritySettingsServiceGrpcAsyncIOTransport +from .transports.rest import SecuritySettingsServiceRestTransport class SecuritySettingsServiceClientMeta(type): @@ -72,6 +73,7 @@ class SecuritySettingsServiceClientMeta(type): ) # type: Dict[str, Type[SecuritySettingsServiceTransport]] _transport_registry["grpc"] = SecuritySettingsServiceGrpcTransport _transport_registry["grpc_asyncio"] = SecuritySettingsServiceGrpcAsyncIOTransport + _transport_registry["rest"] = SecuritySettingsServiceRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/__init__.py index bcf597b1..8bb194f4 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/__init__.py @@ -19,6 +19,8 @@ from .base import SecuritySettingsServiceTransport from .grpc import SecuritySettingsServiceGrpcTransport from .grpc_asyncio import SecuritySettingsServiceGrpcAsyncIOTransport +from .rest import SecuritySettingsServiceRestTransport +from .rest import SecuritySettingsServiceRestInterceptor # Compile a registry of transports. @@ -27,9 +29,12 @@ ) # type: Dict[str, Type[SecuritySettingsServiceTransport]] _transport_registry["grpc"] = SecuritySettingsServiceGrpcTransport _transport_registry["grpc_asyncio"] = SecuritySettingsServiceGrpcAsyncIOTransport +_transport_registry["rest"] = SecuritySettingsServiceRestTransport __all__ = ( "SecuritySettingsServiceTransport", "SecuritySettingsServiceGrpcTransport", "SecuritySettingsServiceGrpcAsyncIOTransport", + "SecuritySettingsServiceRestTransport", + "SecuritySettingsServiceRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/rest.py new file mode 100644 index 00000000..bc1a087c --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/rest.py @@ -0,0 +1,1327 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import security_settings +from google.cloud.dialogflowcx_v3beta1.types import ( + security_settings as gcdc_security_settings, +) +from google.protobuf import empty_pb2 # type: ignore + +from .base import ( + SecuritySettingsServiceTransport, + 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 SecuritySettingsServiceRestInterceptor: + """Interceptor for SecuritySettingsService. + + 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 SecuritySettingsServiceRestTransport. + + .. code-block:: python + class MyCustomSecuritySettingsServiceInterceptor(SecuritySettingsServiceRestInterceptor): + def pre_create_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_security_settings(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_security_settings(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SecuritySettingsServiceRestTransport(interceptor=MyCustomSecuritySettingsServiceInterceptor()) + client = SecuritySettingsServiceClient(transport=transport) + + + """ + + def pre_create_security_settings( + self, + request: gcdc_security_settings.CreateSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_security_settings.CreateSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for create_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_create_security_settings( + self, response: gcdc_security_settings.SecuritySettings + ) -> gcdc_security_settings.SecuritySettings: + """Post-rpc interceptor for create_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_delete_security_settings( + self, + request: security_settings.DeleteSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + security_settings.DeleteSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def pre_get_security_settings( + self, + request: security_settings.GetSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[security_settings.GetSecuritySettingsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_get_security_settings( + self, response: security_settings.SecuritySettings + ) -> security_settings.SecuritySettings: + """Post-rpc interceptor for get_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_list_security_settings( + self, + request: security_settings.ListSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + security_settings.ListSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_list_security_settings( + self, response: security_settings.ListSecuritySettingsResponse + ) -> security_settings.ListSecuritySettingsResponse: + """Post-rpc interceptor for list_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_update_security_settings( + self, + request: gcdc_security_settings.UpdateSecuritySettingsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_security_settings.UpdateSecuritySettingsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for update_security_settings + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_update_security_settings( + self, response: gcdc_security_settings.SecuritySettings + ) -> gcdc_security_settings.SecuritySettings: + """Post-rpc interceptor for update_security_settings + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SecuritySettingsService server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the SecuritySettingsService server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SecuritySettingsServiceRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SecuritySettingsServiceRestInterceptor + + +class SecuritySettingsServiceRestTransport(SecuritySettingsServiceTransport): + """REST backend transport for SecuritySettingsService. + + Service for managing security settings for Dialogflow. + + 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 = "dialogflow.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[SecuritySettingsServiceRestInterceptor] = 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 SecuritySettingsServiceRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("CreateSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_security_settings.CreateSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_security_settings.SecuritySettings: + r"""Call the create security settings method over HTTP. + + Args: + request (~.gcdc_security_settings.CreateSecuritySettingsRequest): + The request object. The request message for + [SecuritySettings.CreateSecuritySettings][]. + + 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: + ~.gcdc_security_settings.SecuritySettings: + Represents the settings related to + security issues, such as data redaction + and data retention. It may take hours + for updates on the settings to propagate + to all the related components and take + effect. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*}/securitySettings", + "body": "security_settings", + }, + ] + request, metadata = self._interceptor.pre_create_security_settings( + request, metadata + ) + pb_request = gcdc_security_settings.CreateSecuritySettingsRequest.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 = gcdc_security_settings.SecuritySettings() + pb_resp = gcdc_security_settings.SecuritySettings.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_security_settings(resp) + return resp + + class _DeleteSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("DeleteSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: security_settings.DeleteSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete security settings method over HTTP. + + Args: + request (~.security_settings.DeleteSecuritySettingsRequest): + The request object. The request message for + [SecuritySettings.DeleteSecuritySettings][]. + + 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": "/v3beta1/{name=projects/*/locations/*/securitySettings/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_security_settings( + request, metadata + ) + pb_request = security_settings.DeleteSecuritySettingsRequest.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 _GetSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("GetSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: security_settings.GetSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> security_settings.SecuritySettings: + r"""Call the get security settings method over HTTP. + + Args: + request (~.security_settings.GetSecuritySettingsRequest): + The request object. The request message for + [SecuritySettingsService.GetSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.GetSecuritySettings]. + + 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: + ~.security_settings.SecuritySettings: + Represents the settings related to + security issues, such as data redaction + and data retention. It may take hours + for updates on the settings to propagate + to all the related components and take + effect. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/securitySettings/*}", + }, + ] + request, metadata = self._interceptor.pre_get_security_settings( + request, metadata + ) + pb_request = security_settings.GetSecuritySettingsRequest.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 = security_settings.SecuritySettings() + pb_resp = security_settings.SecuritySettings.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_security_settings(resp) + return resp + + class _ListSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("ListSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: security_settings.ListSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> security_settings.ListSecuritySettingsResponse: + r"""Call the list security settings method over HTTP. + + Args: + request (~.security_settings.ListSecuritySettingsRequest): + The request object. The request message for + [SecuritySettings.ListSecuritySettings][]. + + 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: + ~.security_settings.ListSecuritySettingsResponse: + The response message for + [SecuritySettings.ListSecuritySettings][]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*}/securitySettings", + }, + ] + request, metadata = self._interceptor.pre_list_security_settings( + request, metadata + ) + pb_request = security_settings.ListSecuritySettingsRequest.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 = security_settings.ListSecuritySettingsResponse() + pb_resp = security_settings.ListSecuritySettingsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_security_settings(resp) + return resp + + class _UpdateSecuritySettings(SecuritySettingsServiceRestStub): + def __hash__(self): + return hash("UpdateSecuritySettings") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_security_settings.UpdateSecuritySettingsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_security_settings.SecuritySettings: + r"""Call the update security settings method over HTTP. + + Args: + request (~.gcdc_security_settings.UpdateSecuritySettingsRequest): + The request object. The request message for + [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.UpdateSecuritySettings]. + + 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: + ~.gcdc_security_settings.SecuritySettings: + Represents the settings related to + security issues, such as data redaction + and data retention. It may take hours + for updates on the settings to propagate + to all the related components and take + effect. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{security_settings.name=projects/*/locations/*/securitySettings/*}", + "body": "security_settings", + }, + ] + request, metadata = self._interceptor.pre_update_security_settings( + request, metadata + ) + pb_request = gcdc_security_settings.UpdateSecuritySettingsRequest.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 = gcdc_security_settings.SecuritySettings() + pb_resp = gcdc_security_settings.SecuritySettings.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_security_settings(resp) + return resp + + @property + def create_security_settings( + self, + ) -> Callable[ + [gcdc_security_settings.CreateSecuritySettingsRequest], + gcdc_security_settings.SecuritySettings, + ]: + # 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._CreateSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_security_settings( + self, + ) -> Callable[[security_settings.DeleteSecuritySettingsRequest], 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._DeleteSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_security_settings( + self, + ) -> Callable[ + [security_settings.GetSecuritySettingsRequest], + security_settings.SecuritySettings, + ]: + # 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._GetSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_security_settings( + self, + ) -> Callable[ + [security_settings.ListSecuritySettingsRequest], + security_settings.ListSecuritySettingsResponse, + ]: + # 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._ListSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_security_settings( + self, + ) -> Callable[ + [gcdc_security_settings.UpdateSecuritySettingsRequest], + gcdc_security_settings.SecuritySettings, + ]: + # 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._UpdateSecuritySettings(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SecuritySettingsServiceRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SecuritySettingsServiceRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SecuritySettingsServiceRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SecuritySettingsServiceRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SecuritySettingsServiceRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SecuritySettingsServiceRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py index a00ab80f..99a73f61 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py @@ -58,6 +58,7 @@ from .transports.base import SessionEntityTypesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import SessionEntityTypesGrpcTransport from .transports.grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .transports.rest import SessionEntityTypesRestTransport class SessionEntityTypesClientMeta(type): @@ -73,6 +74,7 @@ class SessionEntityTypesClientMeta(type): ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = SessionEntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/__init__.py index 44e2a8d4..688ff207 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/__init__.py @@ -19,6 +19,8 @@ from .base import SessionEntityTypesTransport from .grpc import SessionEntityTypesGrpcTransport from .grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .rest import SessionEntityTypesRestTransport +from .rest import SessionEntityTypesRestInterceptor # Compile a registry of transports. @@ -27,9 +29,12 @@ ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = SessionEntityTypesRestTransport __all__ = ( "SessionEntityTypesTransport", "SessionEntityTypesGrpcTransport", "SessionEntityTypesGrpcAsyncIOTransport", + "SessionEntityTypesRestTransport", + "SessionEntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/rest.py new file mode 100644 index 00000000..7d7c2f4c --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/rest.py @@ -0,0 +1,1390 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import session_entity_type +from google.cloud.dialogflowcx_v3beta1.types import ( + session_entity_type as gcdc_session_entity_type, +) +from google.protobuf import empty_pb2 # type: ignore + +from .base import ( + SessionEntityTypesTransport, + 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 SessionEntityTypesRestInterceptor: + """Interceptor for SessionEntityTypes. + + 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 SessionEntityTypesRestTransport. + + .. code-block:: python + class MyCustomSessionEntityTypesInterceptor(SessionEntityTypesRestInterceptor): + def pre_create_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_session_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_session_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionEntityTypesRestTransport(interceptor=MyCustomSessionEntityTypesInterceptor()) + client = SessionEntityTypesClient(transport=transport) + + + """ + + def pre_create_session_entity_type( + self, + request: gcdc_session_entity_type.CreateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_session_entity_type.CreateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_create_session_entity_type( + self, response: gcdc_session_entity_type.SessionEntityType + ) -> gcdc_session_entity_type.SessionEntityType: + """Post-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_session_entity_type( + self, + request: session_entity_type.DeleteSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.DeleteSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def pre_get_session_entity_type( + self, + request: session_entity_type.GetSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.GetSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_session_entity_type( + self, response: session_entity_type.SessionEntityType + ) -> session_entity_type.SessionEntityType: + """Post-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_session_entity_types( + self, + request: session_entity_type.ListSessionEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.ListSessionEntityTypesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_session_entity_types( + self, response: session_entity_type.ListSessionEntityTypesResponse + ) -> session_entity_type.ListSessionEntityTypesResponse: + """Post-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_session_entity_type( + self, + request: gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_update_session_entity_type( + self, response: gcdc_session_entity_type.SessionEntityType + ) -> gcdc_session_entity_type.SessionEntityType: + """Post-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionEntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionEntityTypesRestInterceptor + + +class SessionEntityTypesRestTransport(SessionEntityTypesTransport): + """REST backend transport for SessionEntityTypes. + + Service for managing + [SessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityType]. + + 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 = "dialogflow.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[SessionEntityTypesRestInterceptor] = 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 SessionEntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("CreateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_session_entity_type.CreateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_session_entity_type.SessionEntityType: + r"""Call the create session entity + type method over HTTP. + + Args: + request (~.gcdc_session_entity_type.CreateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.CreateSessionEntityType]. + + 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: + ~.gcdc_session_entity_type.SessionEntityType: + Session entity types are referred to as **User** entity + types and are entities that are built for an individual + user such as favorites, preferences, playlists, and so + on. + + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). + + Note: session entity types apply to all queries, + regardless of the language. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_session_entity_type( + request, metadata + ) + pb_request = gcdc_session_entity_type.CreateSessionEntityTypeRequest.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 = gcdc_session_entity_type.SessionEntityType() + pb_resp = gcdc_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_session_entity_type(resp) + return resp + + class _DeleteSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("DeleteSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session_entity_type.DeleteSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete session entity + type method over HTTP. + + Args: + request (~.session_entity_type.DeleteSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.DeleteSessionEntityType]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.DeleteSessionEntityTypeRequest.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 _GetSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("GetSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session_entity_type.GetSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.SessionEntityType: + r"""Call the get session entity type method over HTTP. + + Args: + request (~.session_entity_type.GetSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.GetSessionEntityType]. + + 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: + ~.session_entity_type.SessionEntityType: + Session entity types are referred to as **User** entity + types and are entities that are built for an individual + user such as favorites, preferences, playlists, and so + on. + + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). + + Note: session entity types apply to all queries, + regardless of the language. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.GetSessionEntityTypeRequest.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 = session_entity_type.SessionEntityType() + pb_resp = session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_session_entity_type(resp) + return resp + + class _ListSessionEntityTypes(SessionEntityTypesRestStub): + def __hash__(self): + return hash("ListSessionEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session_entity_type.ListSessionEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.ListSessionEntityTypesResponse: + r"""Call the list session entity types method over HTTP. + + Args: + request (~.session_entity_type.ListSessionEntityTypesRequest): + The request object. The request message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. + + 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: + ~.session_entity_type.ListSessionEntityTypesResponse: + The response message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*/sessions/*}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_session_entity_types( + request, metadata + ) + pb_request = session_entity_type.ListSessionEntityTypesRequest.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 = session_entity_type.ListSessionEntityTypesResponse() + pb_resp = session_entity_type.ListSessionEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_session_entity_types(resp) + return resp + + class _UpdateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("UpdateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_session_entity_type.SessionEntityType: + r"""Call the update session entity + type method over HTTP. + + Args: + request (~.gcdc_session_entity_type.UpdateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.UpdateSessionEntityType]. + + 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: + ~.gcdc_session_entity_type.SessionEntityType: + Session entity types are referred to as **User** entity + types and are entities that are built for an individual + user such as favorites, preferences, playlists, and so + on. + + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). + + Note: session entity types apply to all queries, + regardless of the language. + + For more information about entity types, see the + `Dialogflow + documentation `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{session_entity_type.name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v3beta1/{session_entity_type.name=projects/*/locations/*/agents/*/environments/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_session_entity_type( + request, metadata + ) + pb_request = gcdc_session_entity_type.UpdateSessionEntityTypeRequest.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 = gcdc_session_entity_type.SessionEntityType() + pb_resp = gcdc_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_session_entity_type(resp) + return resp + + @property + def create_session_entity_type( + self, + ) -> Callable[ + [gcdc_session_entity_type.CreateSessionEntityTypeRequest], + gcdc_session_entity_type.SessionEntityType, + ]: + # 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._CreateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.DeleteSessionEntityTypeRequest], 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._DeleteSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.GetSessionEntityTypeRequest], + session_entity_type.SessionEntityType, + ]: + # 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._GetSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_session_entity_types( + self, + ) -> Callable[ + [session_entity_type.ListSessionEntityTypesRequest], + session_entity_type.ListSessionEntityTypesResponse, + ]: + # 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._ListSessionEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_session_entity_type( + self, + ) -> Callable[ + [gcdc_session_entity_type.UpdateSessionEntityTypeRequest], + gcdc_session_entity_type.SessionEntityType, + ]: + # 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._UpdateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionEntityTypesRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionEntityTypesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py index 69620e54..feff8f51 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py @@ -56,6 +56,7 @@ from .transports.base import SessionsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import SessionsGrpcTransport from .transports.grpc_asyncio import SessionsGrpcAsyncIOTransport +from .transports.rest import SessionsRestTransport class SessionsClientMeta(type): @@ -69,6 +70,7 @@ class SessionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport + _transport_registry["rest"] = SessionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/__init__.py index ce00ff37..4417beb6 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/__init__.py @@ -19,15 +19,20 @@ from .base import SessionsTransport from .grpc import SessionsGrpcTransport from .grpc_asyncio import SessionsGrpcAsyncIOTransport +from .rest import SessionsRestTransport +from .rest import SessionsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport +_transport_registry["rest"] = SessionsRestTransport __all__ = ( "SessionsTransport", "SessionsGrpcTransport", "SessionsGrpcAsyncIOTransport", + "SessionsRestTransport", + "SessionsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/rest.py new file mode 100644 index 00000000..36f1374a --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/rest.py @@ -0,0 +1,1069 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import session + +from .base import SessionsTransport, 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 SessionsRestInterceptor: + """Interceptor for Sessions. + + 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 SessionsRestTransport. + + .. code-block:: python + class MyCustomSessionsInterceptor(SessionsRestInterceptor): + def pre_detect_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_detect_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_fulfill_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_fulfill_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_match_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_match_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionsRestTransport(interceptor=MyCustomSessionsInterceptor()) + client = SessionsClient(transport=transport) + + + """ + + def pre_detect_intent( + self, request: session.DetectIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[session.DetectIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for detect_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_detect_intent( + self, response: session.DetectIntentResponse + ) -> session.DetectIntentResponse: + """Post-rpc interceptor for detect_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_fulfill_intent( + self, request: session.FulfillIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[session.FulfillIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for fulfill_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_fulfill_intent( + self, response: session.FulfillIntentResponse + ) -> session.FulfillIntentResponse: + """Post-rpc interceptor for fulfill_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_match_intent( + self, request: session.MatchIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[session.MatchIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for match_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_match_intent( + self, response: session.MatchIntentResponse + ) -> session.MatchIntentResponse: + """Post-rpc interceptor for match_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionsRestInterceptor + + +class SessionsRestTransport(SessionsTransport): + """REST backend transport for Sessions. + + A session represents an interaction with a user. You retrieve user + input and pass it to the + [DetectIntent][google.cloud.dialogflow.cx.v3beta1.Sessions.DetectIntent] + method to determine user intent and respond. + + 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 = "dialogflow.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[SessionsRestInterceptor] = 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 SessionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _DetectIntent(SessionsRestStub): + def __hash__(self): + return hash("DetectIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session.DetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session.DetectIntentResponse: + r"""Call the detect intent method over HTTP. + + Args: + request (~.session.DetectIntentRequest): + The request object. The request to detect user's intent. + 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: + ~.session.DetectIntentResponse: + The message returned from the + DetectIntent method. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{session=projects/*/locations/*/agents/*/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v3beta1/{session=projects/*/locations/*/agents/*/environments/*/sessions/*}:detectIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_detect_intent(request, metadata) + pb_request = session.DetectIntentRequest.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 = session.DetectIntentResponse() + pb_resp = session.DetectIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_detect_intent(resp) + return resp + + class _FulfillIntent(SessionsRestStub): + def __hash__(self): + return hash("FulfillIntent") + + def __call__( + self, + request: session.FulfillIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session.FulfillIntentResponse: + r"""Call the fulfill intent method over HTTP. + + Args: + request (~.session.FulfillIntentRequest): + The request object. Request of [FulfillIntent][] + 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: + ~.session.FulfillIntentResponse: + Response of [FulfillIntent][] + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{match_intent_request.session=projects/*/locations/*/agents/*/sessions/*}:fulfillIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v3beta1/{match_intent_request.session=projects/*/locations/*/agents/*/environments/*/sessions/*}:fulfillIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_fulfill_intent(request, metadata) + pb_request = session.FulfillIntentRequest.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["$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 = session.FulfillIntentResponse() + pb_resp = session.FulfillIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_fulfill_intent(resp) + return resp + + class _MatchIntent(SessionsRestStub): + def __hash__(self): + return hash("MatchIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: session.MatchIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session.MatchIntentResponse: + r"""Call the match intent method over HTTP. + + Args: + request (~.session.MatchIntentRequest): + The request object. Request of [MatchIntent][]. + 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: + ~.session.MatchIntentResponse: + Response of [MatchIntent][]. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{session=projects/*/locations/*/agents/*/sessions/*}:matchIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v3beta1/{session=projects/*/locations/*/agents/*/environments/*/sessions/*}:matchIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_match_intent(request, metadata) + pb_request = session.MatchIntentRequest.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 = session.MatchIntentResponse() + pb_resp = session.MatchIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_match_intent(resp) + return resp + + class _StreamingDetectIntent(SessionsRestStub): + def __hash__(self): + return hash("StreamingDetectIntent") + + def __call__( + self, + request: session.StreamingDetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> rest_streaming.ResponseIterator: + raise NotImplementedError( + "Method StreamingDetectIntent is not available over REST transport" + ) + + @property + def detect_intent( + self, + ) -> Callable[[session.DetectIntentRequest], session.DetectIntentResponse]: + # 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._DetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def fulfill_intent( + self, + ) -> Callable[[session.FulfillIntentRequest], session.FulfillIntentResponse]: + # 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._FulfillIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def match_intent( + self, + ) -> Callable[[session.MatchIntentRequest], session.MatchIntentResponse]: + # 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._MatchIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def streaming_detect_intent( + self, + ) -> Callable[ + [session.StreamingDetectIntentRequest], session.StreamingDetectIntentResponse + ]: + # 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._StreamingDetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py index f2b3f6be..c41dcd7e 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py @@ -58,6 +58,7 @@ from .transports.base import TestCasesTransport, DEFAULT_CLIENT_INFO from .transports.grpc import TestCasesGrpcTransport from .transports.grpc_asyncio import TestCasesGrpcAsyncIOTransport +from .transports.rest import TestCasesRestTransport class TestCasesClientMeta(type): @@ -71,6 +72,7 @@ class TestCasesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] _transport_registry["grpc"] = TestCasesGrpcTransport _transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport + _transport_registry["rest"] = TestCasesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py index 10d2c977..0b296261 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py @@ -19,15 +19,20 @@ from .base import TestCasesTransport from .grpc import TestCasesGrpcTransport from .grpc_asyncio import TestCasesGrpcAsyncIOTransport +from .rest import TestCasesRestTransport +from .rest import TestCasesRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] _transport_registry["grpc"] = TestCasesGrpcTransport _transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport +_transport_registry["rest"] = TestCasesRestTransport __all__ = ( "TestCasesTransport", "TestCasesGrpcTransport", "TestCasesGrpcAsyncIOTransport", + "TestCasesRestTransport", + "TestCasesRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/rest.py new file mode 100644 index 00000000..d3fb3b21 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/rest.py @@ -0,0 +1,2295 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import TestCasesTransport, 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 TestCasesRestInterceptor: + """Interceptor for TestCases. + + 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 TestCasesRestTransport. + + .. code-block:: python + class MyCustomTestCasesInterceptor(TestCasesRestInterceptor): + def pre_batch_delete_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_batch_run_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_run_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_calculate_coverage(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_calculate_coverage(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_export_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_test_case_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_test_case_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_test_case_results(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_test_case_results(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_test_cases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_test_cases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_run_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_run_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_test_case(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_test_case(self, response): + logging.log(f"Received response: {response}") + return response + + transport = TestCasesRestTransport(interceptor=MyCustomTestCasesInterceptor()) + client = TestCasesClient(transport=transport) + + + """ + + def pre_batch_delete_test_cases( + self, + request: test_case.BatchDeleteTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.BatchDeleteTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def pre_batch_run_test_cases( + self, + request: test_case.BatchRunTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.BatchRunTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_run_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_batch_run_test_cases( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_run_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_calculate_coverage( + self, + request: test_case.CalculateCoverageRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.CalculateCoverageRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for calculate_coverage + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_calculate_coverage( + self, response: test_case.CalculateCoverageResponse + ) -> test_case.CalculateCoverageResponse: + """Post-rpc interceptor for calculate_coverage + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_create_test_case( + self, + request: gcdc_test_case.CreateTestCaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_test_case.CreateTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_create_test_case( + self, response: gcdc_test_case.TestCase + ) -> gcdc_test_case.TestCase: + """Post-rpc interceptor for create_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_export_test_cases( + self, + request: test_case.ExportTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ExportTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_export_test_cases( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_get_test_case( + self, request: test_case.GetTestCaseRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[test_case.GetTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_test_case(self, response: test_case.TestCase) -> test_case.TestCase: + """Post-rpc interceptor for get_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_get_test_case_result( + self, + request: test_case.GetTestCaseResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.GetTestCaseResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_test_case_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_test_case_result( + self, response: test_case.TestCaseResult + ) -> test_case.TestCaseResult: + """Post-rpc interceptor for get_test_case_result + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_import_test_cases( + self, + request: test_case.ImportTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ImportTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_import_test_cases( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_test_case_results( + self, + request: test_case.ListTestCaseResultsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ListTestCaseResultsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_test_case_results + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_test_case_results( + self, response: test_case.ListTestCaseResultsResponse + ) -> test_case.ListTestCaseResultsResponse: + """Post-rpc interceptor for list_test_case_results + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_test_cases( + self, + request: test_case.ListTestCasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[test_case.ListTestCasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_test_cases + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_test_cases( + self, response: test_case.ListTestCasesResponse + ) -> test_case.ListTestCasesResponse: + """Post-rpc interceptor for list_test_cases + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_run_test_case( + self, request: test_case.RunTestCaseRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[test_case.RunTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for run_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_run_test_case( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for run_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_update_test_case( + self, + request: gcdc_test_case.UpdateTestCaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_test_case.UpdateTestCaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_test_case + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_update_test_case( + self, response: gcdc_test_case.TestCase + ) -> gcdc_test_case.TestCase: + """Post-rpc interceptor for update_test_case + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the TestCases 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TestCases server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the TestCases server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class TestCasesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: TestCasesRestInterceptor + + +class TestCasesRestTransport(TestCasesTransport): + """REST backend transport for TestCases. + + Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult]. + + 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 = "dialogflow.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[TestCasesRestInterceptor] = 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 TestCasesRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/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="v3beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _BatchDeleteTestCases(TestCasesRestStub): + def __hash__(self): + return hash("BatchDeleteTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.BatchDeleteTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the batch delete test cases method over HTTP. + + Args: + request (~.test_case.BatchDeleteTestCasesRequest): + The request object. The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchDeleteTestCases]. + + 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": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_test_cases( + request, metadata + ) + pb_request = test_case.BatchDeleteTestCasesRequest.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) + + class _BatchRunTestCases(TestCasesRestStub): + def __hash__(self): + return hash("BatchRunTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.BatchRunTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch run test cases method over HTTP. + + Args: + request (~.test_case.BatchRunTestCasesRequest): + The request object. The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + 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": "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:batchRun", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_run_test_cases( + request, metadata + ) + pb_request = test_case.BatchRunTestCasesRequest.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_batch_run_test_cases(resp) + return resp + + class _CalculateCoverage(TestCasesRestStub): + def __hash__(self): + return hash("CalculateCoverage") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "type": {}, + } + + @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: test_case.CalculateCoverageRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.CalculateCoverageResponse: + r"""Call the calculate coverage method over HTTP. + + Args: + request (~.test_case.CalculateCoverageRequest): + The request object. The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + 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: + ~.test_case.CalculateCoverageResponse: + The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{agent=projects/*/locations/*/agents/*}/testCases:calculateCoverage", + }, + ] + request, metadata = self._interceptor.pre_calculate_coverage( + request, metadata + ) + pb_request = test_case.CalculateCoverageRequest.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 = test_case.CalculateCoverageResponse() + pb_resp = test_case.CalculateCoverageResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_calculate_coverage(resp) + return resp + + class _CreateTestCase(TestCasesRestStub): + def __hash__(self): + return hash("CreateTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_test_case.CreateTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Call the create test case method over HTTP. + + Args: + request (~.gcdc_test_case.CreateTestCaseRequest): + The request object. The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase]. + + 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: + ~.gcdc_test_case.TestCase: + Represents a test case. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases", + "body": "test_case", + }, + ] + request, metadata = self._interceptor.pre_create_test_case( + request, metadata + ) + pb_request = gcdc_test_case.CreateTestCaseRequest.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 = gcdc_test_case.TestCase() + pb_resp = gcdc_test_case.TestCase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_test_case(resp) + return resp + + class _ExportTestCases(TestCasesRestStub): + def __hash__(self): + return hash("ExportTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ExportTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export test cases method over HTTP. + + Args: + request (~.test_case.ExportTestCasesRequest): + The request object. The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + 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": "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_test_cases( + request, metadata + ) + pb_request = test_case.ExportTestCasesRequest.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_test_cases(resp) + return resp + + class _GetTestCase(TestCasesRestStub): + def __hash__(self): + return hash("GetTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.GetTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCase: + r"""Call the get test case method over HTTP. + + Args: + request (~.test_case.GetTestCaseRequest): + The request object. The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCase]. + + 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: + ~.test_case.TestCase: + Represents a test case. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*}", + }, + ] + request, metadata = self._interceptor.pre_get_test_case(request, metadata) + pb_request = test_case.GetTestCaseRequest.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 = test_case.TestCase() + pb_resp = test_case.TestCase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_test_case(resp) + return resp + + class _GetTestCaseResult(TestCasesRestStub): + def __hash__(self): + return hash("GetTestCaseResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.GetTestCaseResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCaseResult: + r"""Call the get test case result method over HTTP. + + Args: + request (~.test_case.GetTestCaseResultRequest): + The request object. The request message for + [TestCases.GetTestCaseResult][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCaseResult]. + + 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: + ~.test_case.TestCaseResult: + Represents a result from running a + test case in an agent environment. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*/results/*}", + }, + ] + request, metadata = self._interceptor.pre_get_test_case_result( + request, metadata + ) + pb_request = test_case.GetTestCaseResultRequest.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 = test_case.TestCaseResult() + pb_resp = test_case.TestCaseResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_test_case_result(resp) + return resp + + class _ImportTestCases(TestCasesRestStub): + def __hash__(self): + return hash("ImportTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ImportTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import test cases method over HTTP. + + Args: + request (~.test_case.ImportTestCasesRequest): + The request object. The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + 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": "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_test_cases( + request, metadata + ) + pb_request = test_case.ImportTestCasesRequest.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_import_test_cases(resp) + return resp + + class _ListTestCaseResults(TestCasesRestStub): + def __hash__(self): + return hash("ListTestCaseResults") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ListTestCaseResultsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.ListTestCaseResultsResponse: + r"""Call the list test case results method over HTTP. + + Args: + request (~.test_case.ListTestCaseResultsRequest): + The request object. The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + + 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: + ~.test_case.ListTestCaseResultsResponse: + The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/testCases/*}/results", + }, + ] + request, metadata = self._interceptor.pre_list_test_case_results( + request, metadata + ) + pb_request = test_case.ListTestCaseResultsRequest.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 = test_case.ListTestCaseResultsResponse() + pb_resp = test_case.ListTestCaseResultsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_test_case_results(resp) + return resp + + class _ListTestCases(TestCasesRestStub): + def __hash__(self): + return hash("ListTestCases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.ListTestCasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.ListTestCasesResponse: + r"""Call the list test cases method over HTTP. + + Args: + request (~.test_case.ListTestCasesRequest): + The request object. The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + + 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: + ~.test_case.ListTestCasesResponse: + The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases", + }, + ] + request, metadata = self._interceptor.pre_list_test_cases(request, metadata) + pb_request = test_case.ListTestCasesRequest.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 = test_case.ListTestCasesResponse() + pb_resp = test_case.ListTestCasesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_test_cases(resp) + return resp + + class _RunTestCase(TestCasesRestStub): + def __hash__(self): + return hash("RunTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: test_case.RunTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the run test case method over HTTP. + + Args: + request (~.test_case.RunTestCaseRequest): + The request object. The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*}:run", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_run_test_case(request, metadata) + pb_request = test_case.RunTestCaseRequest.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_run_test_case(resp) + return resp + + class _UpdateTestCase(TestCasesRestStub): + def __hash__(self): + return hash("UpdateTestCase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_test_case.UpdateTestCaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Call the update test case method over HTTP. + + Args: + request (~.gcdc_test_case.UpdateTestCaseRequest): + The request object. The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.UpdateTestCase]. + + 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: + ~.gcdc_test_case.TestCase: + Represents a test case. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{test_case.name=projects/*/locations/*/agents/*/testCases/*}", + "body": "test_case", + }, + ] + request, metadata = self._interceptor.pre_update_test_case( + request, metadata + ) + pb_request = gcdc_test_case.UpdateTestCaseRequest.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 = gcdc_test_case.TestCase() + pb_resp = gcdc_test_case.TestCase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_test_case(resp) + return resp + + @property + def batch_delete_test_cases( + self, + ) -> Callable[[test_case.BatchDeleteTestCasesRequest], 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._BatchDeleteTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_run_test_cases( + self, + ) -> Callable[[test_case.BatchRunTestCasesRequest], 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._BatchRunTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def calculate_coverage( + self, + ) -> Callable[ + [test_case.CalculateCoverageRequest], test_case.CalculateCoverageResponse + ]: + # 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._CalculateCoverage(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_test_case( + self, + ) -> Callable[[gcdc_test_case.CreateTestCaseRequest], gcdc_test_case.TestCase]: + # 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._CreateTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_test_cases( + self, + ) -> Callable[[test_case.ExportTestCasesRequest], 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._ExportTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_test_case( + self, + ) -> Callable[[test_case.GetTestCaseRequest], test_case.TestCase]: + # 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._GetTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_test_case_result( + self, + ) -> Callable[[test_case.GetTestCaseResultRequest], test_case.TestCaseResult]: + # 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._GetTestCaseResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_test_cases( + self, + ) -> Callable[[test_case.ImportTestCasesRequest], 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._ImportTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_test_case_results( + self, + ) -> Callable[ + [test_case.ListTestCaseResultsRequest], test_case.ListTestCaseResultsResponse + ]: + # 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._ListTestCaseResults(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_test_cases( + self, + ) -> Callable[[test_case.ListTestCasesRequest], test_case.ListTestCasesResponse]: + # 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._ListTestCases(self._session, self._host, self._interceptor) # type: ignore + + @property + def run_test_case( + self, + ) -> Callable[[test_case.RunTestCaseRequest], 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._RunTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_test_case( + self, + ) -> Callable[[gcdc_test_case.UpdateTestCaseRequest], gcdc_test_case.TestCase]: + # 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._UpdateTestCase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(TestCasesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(TestCasesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(TestCasesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(TestCasesRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(TestCasesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("TestCasesRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py index 6cd5d6a9..6fb63bd4 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py @@ -58,6 +58,7 @@ from .transports.base import TransitionRouteGroupsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import TransitionRouteGroupsGrpcTransport from .transports.grpc_asyncio import TransitionRouteGroupsGrpcAsyncIOTransport +from .transports.rest import TransitionRouteGroupsRestTransport class TransitionRouteGroupsClientMeta(type): @@ -73,6 +74,7 @@ class TransitionRouteGroupsClientMeta(type): ) # type: Dict[str, Type[TransitionRouteGroupsTransport]] _transport_registry["grpc"] = TransitionRouteGroupsGrpcTransport _transport_registry["grpc_asyncio"] = TransitionRouteGroupsGrpcAsyncIOTransport + _transport_registry["rest"] = TransitionRouteGroupsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/__init__.py index ed445782..a9ee37b8 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/__init__.py @@ -19,6 +19,8 @@ from .base import TransitionRouteGroupsTransport from .grpc import TransitionRouteGroupsGrpcTransport from .grpc_asyncio import TransitionRouteGroupsGrpcAsyncIOTransport +from .rest import TransitionRouteGroupsRestTransport +from .rest import TransitionRouteGroupsRestInterceptor # Compile a registry of transports. @@ -27,9 +29,12 @@ ) # type: Dict[str, Type[TransitionRouteGroupsTransport]] _transport_registry["grpc"] = TransitionRouteGroupsGrpcTransport _transport_registry["grpc_asyncio"] = TransitionRouteGroupsGrpcAsyncIOTransport +_transport_registry["rest"] = TransitionRouteGroupsRestTransport __all__ = ( "TransitionRouteGroupsTransport", "TransitionRouteGroupsGrpcTransport", "TransitionRouteGroupsGrpcAsyncIOTransport", + "TransitionRouteGroupsRestTransport", + "TransitionRouteGroupsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/rest.py new file mode 100644 index 00000000..126deb54 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/rest.py @@ -0,0 +1,1343 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import transition_route_group +from google.cloud.dialogflowcx_v3beta1.types import ( + transition_route_group as gcdc_transition_route_group, +) +from google.protobuf import empty_pb2 # type: ignore + +from .base import ( + TransitionRouteGroupsTransport, + 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 TransitionRouteGroupsRestInterceptor: + """Interceptor for TransitionRouteGroups. + + 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 TransitionRouteGroupsRestTransport. + + .. code-block:: python + class MyCustomTransitionRouteGroupsInterceptor(TransitionRouteGroupsRestInterceptor): + def pre_create_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_transition_route_group(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_transition_route_group(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_transition_route_groups(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_transition_route_groups(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_transition_route_group(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_transition_route_group(self, response): + logging.log(f"Received response: {response}") + return response + + transport = TransitionRouteGroupsRestTransport(interceptor=MyCustomTransitionRouteGroupsInterceptor()) + client = TransitionRouteGroupsClient(transport=transport) + + + """ + + def pre_create_transition_route_group( + self, + request: gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_create_transition_route_group( + self, response: gcdc_transition_route_group.TransitionRouteGroup + ) -> gcdc_transition_route_group.TransitionRouteGroup: + """Post-rpc interceptor for create_transition_route_group + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_delete_transition_route_group( + self, + request: transition_route_group.DeleteTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + transition_route_group.DeleteTransitionRouteGroupRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for delete_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def pre_get_transition_route_group( + self, + request: transition_route_group.GetTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + transition_route_group.GetTransitionRouteGroupRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_get_transition_route_group( + self, response: transition_route_group.TransitionRouteGroup + ) -> transition_route_group.TransitionRouteGroup: + """Post-rpc interceptor for get_transition_route_group + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_list_transition_route_groups( + self, + request: transition_route_group.ListTransitionRouteGroupsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + transition_route_group.ListTransitionRouteGroupsRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for list_transition_route_groups + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_list_transition_route_groups( + self, response: transition_route_group.ListTransitionRouteGroupsResponse + ) -> transition_route_group.ListTransitionRouteGroupsResponse: + """Post-rpc interceptor for list_transition_route_groups + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_update_transition_route_group( + self, + request: gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_transition_route_group + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_update_transition_route_group( + self, response: gcdc_transition_route_group.TransitionRouteGroup + ) -> gcdc_transition_route_group.TransitionRouteGroup: + """Post-rpc interceptor for update_transition_route_group + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the TransitionRouteGroups server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the TransitionRouteGroups server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class TransitionRouteGroupsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: TransitionRouteGroupsRestInterceptor + + +class TransitionRouteGroupsRestTransport(TransitionRouteGroupsTransport): + """REST backend transport for TransitionRouteGroups. + + Service for managing + [TransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. + + 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 = "dialogflow.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[TransitionRouteGroupsRestInterceptor] = 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 TransitionRouteGroupsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("CreateTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_transition_route_group.TransitionRouteGroup: + r"""Call the create transition route + group method over HTTP. + + Args: + request (~.gcdc_transition_route_group.CreateTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.CreateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.CreateTransitionRouteGroup]. + + 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: + ~.gcdc_transition_route_group.TransitionRouteGroup: + An TransitionRouteGroup represents a group of + [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups", + "body": "transition_route_group", + }, + ] + request, metadata = self._interceptor.pre_create_transition_route_group( + request, metadata + ) + pb_request = ( + gcdc_transition_route_group.CreateTransitionRouteGroupRequest.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 = gcdc_transition_route_group.TransitionRouteGroup() + pb_resp = gcdc_transition_route_group.TransitionRouteGroup.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_transition_route_group(resp) + return resp + + class _DeleteTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("DeleteTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: transition_route_group.DeleteTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete transition route + group method over HTTP. + + Args: + request (~.transition_route_group.DeleteTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.DeleteTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.DeleteTransitionRouteGroup]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_transition_route_group( + request, metadata + ) + pb_request = transition_route_group.DeleteTransitionRouteGroupRequest.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 _GetTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("GetTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: transition_route_group.GetTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> transition_route_group.TransitionRouteGroup: + r"""Call the get transition route + group method over HTTP. + + Args: + request (~.transition_route_group.GetTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.GetTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.GetTransitionRouteGroup]. + + 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: + ~.transition_route_group.TransitionRouteGroup: + An TransitionRouteGroup represents a group of + [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}", + }, + ] + request, metadata = self._interceptor.pre_get_transition_route_group( + request, metadata + ) + pb_request = transition_route_group.GetTransitionRouteGroupRequest.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 = transition_route_group.TransitionRouteGroup() + pb_resp = transition_route_group.TransitionRouteGroup.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_transition_route_group(resp) + return resp + + class _ListTransitionRouteGroups(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("ListTransitionRouteGroups") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: transition_route_group.ListTransitionRouteGroupsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> transition_route_group.ListTransitionRouteGroupsResponse: + r"""Call the list transition route + groups method over HTTP. + + Args: + request (~.transition_route_group.ListTransitionRouteGroupsRequest): + The request object. The request message for + [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. + + 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: + ~.transition_route_group.ListTransitionRouteGroupsResponse: + The response message for + [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups", + }, + ] + request, metadata = self._interceptor.pre_list_transition_route_groups( + request, metadata + ) + pb_request = transition_route_group.ListTransitionRouteGroupsRequest.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 = transition_route_group.ListTransitionRouteGroupsResponse() + pb_resp = transition_route_group.ListTransitionRouteGroupsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_transition_route_groups(resp) + return resp + + class _UpdateTransitionRouteGroup(TransitionRouteGroupsRestStub): + def __hash__(self): + return hash("UpdateTransitionRouteGroup") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_transition_route_group.TransitionRouteGroup: + r"""Call the update transition route + group method over HTTP. + + Args: + request (~.gcdc_transition_route_group.UpdateTransitionRouteGroupRequest): + The request object. The request message for + [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.UpdateTransitionRouteGroup]. + + 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: + ~.gcdc_transition_route_group.TransitionRouteGroup: + An TransitionRouteGroup represents a group of + [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{transition_route_group.name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}", + "body": "transition_route_group", + }, + ] + request, metadata = self._interceptor.pre_update_transition_route_group( + request, metadata + ) + pb_request = ( + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest.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 = gcdc_transition_route_group.TransitionRouteGroup() + pb_resp = gcdc_transition_route_group.TransitionRouteGroup.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_transition_route_group(resp) + return resp + + @property + def create_transition_route_group( + self, + ) -> Callable[ + [gcdc_transition_route_group.CreateTransitionRouteGroupRequest], + gcdc_transition_route_group.TransitionRouteGroup, + ]: + # 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._CreateTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_transition_route_group( + self, + ) -> Callable[ + [transition_route_group.DeleteTransitionRouteGroupRequest], 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._DeleteTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_transition_route_group( + self, + ) -> Callable[ + [transition_route_group.GetTransitionRouteGroupRequest], + transition_route_group.TransitionRouteGroup, + ]: + # 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._GetTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_transition_route_groups( + self, + ) -> Callable[ + [transition_route_group.ListTransitionRouteGroupsRequest], + transition_route_group.ListTransitionRouteGroupsResponse, + ]: + # 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._ListTransitionRouteGroups(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_transition_route_group( + self, + ) -> Callable[ + [gcdc_transition_route_group.UpdateTransitionRouteGroupRequest], + gcdc_transition_route_group.TransitionRouteGroup, + ]: + # 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._UpdateTransitionRouteGroup(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(TransitionRouteGroupsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(TransitionRouteGroupsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(TransitionRouteGroupsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(TransitionRouteGroupsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(TransitionRouteGroupsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("TransitionRouteGroupsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/client.py b/google/cloud/dialogflowcx_v3beta1/services/versions/client.py index 826fe724..624cff68 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/client.py @@ -61,6 +61,7 @@ from .transports.base import VersionsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import VersionsGrpcTransport from .transports.grpc_asyncio import VersionsGrpcAsyncIOTransport +from .transports.rest import VersionsRestTransport class VersionsClientMeta(type): @@ -74,6 +75,7 @@ class VersionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport + _transport_registry["rest"] = VersionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/__init__.py index ab80b3b5..780f6ec5 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/__init__.py @@ -19,15 +19,20 @@ from .base import VersionsTransport from .grpc import VersionsGrpcTransport from .grpc_asyncio import VersionsGrpcAsyncIOTransport +from .rest import VersionsRestTransport +from .rest import VersionsRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport +_transport_registry["rest"] = VersionsRestTransport __all__ = ( "VersionsTransport", "VersionsGrpcTransport", "VersionsGrpcAsyncIOTransport", + "VersionsRestTransport", + "VersionsRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/rest.py new file mode 100644 index 00000000..b53fc8c0 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/rest.py @@ -0,0 +1,1598 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import version +from google.cloud.dialogflowcx_v3beta1.types import version as gcdc_version +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from .base import VersionsTransport, 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 VersionsRestInterceptor: + """Interceptor for Versions. + + 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 VersionsRestTransport. + + .. code-block:: python + class MyCustomVersionsInterceptor(VersionsRestInterceptor): + def pre_compare_versions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_compare_versions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_versions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_versions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_load_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_load_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_version(self, response): + logging.log(f"Received response: {response}") + return response + + transport = VersionsRestTransport(interceptor=MyCustomVersionsInterceptor()) + client = VersionsClient(transport=transport) + + + """ + + def pre_compare_versions( + self, + request: version.CompareVersionsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[version.CompareVersionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for compare_versions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_compare_versions( + self, response: version.CompareVersionsResponse + ) -> version.CompareVersionsResponse: + """Post-rpc interceptor for compare_versions + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_create_version( + self, + request: gcdc_version.CreateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_version.CreateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_create_version( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_delete_version( + self, request: version.DeleteVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.DeleteVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def pre_get_version( + self, request: version.GetVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.GetVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_version(self, response: version.Version) -> version.Version: + """Post-rpc interceptor for get_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_versions( + self, request: version.ListVersionsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.ListVersionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_versions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_versions( + self, response: version.ListVersionsResponse + ) -> version.ListVersionsResponse: + """Post-rpc interceptor for list_versions + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_load_version( + self, request: version.LoadVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.LoadVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for load_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_load_version( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for load_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_update_version( + self, + request: gcdc_version.UpdateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_version.UpdateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_update_version( + self, response: gcdc_version.Version + ) -> gcdc_version.Version: + """Post-rpc interceptor for update_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class VersionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: VersionsRestInterceptor + + +class VersionsRestTransport(VersionsTransport): + """REST backend transport for Versions. + + Service for managing + [Versions][google.cloud.dialogflow.cx.v3beta1.Version]. + + 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 = "dialogflow.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[VersionsRestInterceptor] = 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 VersionsRestInterceptor() + 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.CancelOperation": [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/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="v3beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CompareVersions(VersionsRestStub): + def __hash__(self): + return hash("CompareVersions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.CompareVersionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.CompareVersionsResponse: + r"""Call the compare versions method over HTTP. + + Args: + request (~.version.CompareVersionsRequest): + The request object. The request message for + [Versions.CompareVersions][google.cloud.dialogflow.cx.v3beta1.Versions.CompareVersions]. + + 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: + ~.version.CompareVersionsResponse: + The response message for + [Versions.CompareVersions][google.cloud.dialogflow.cx.v3beta1.Versions.CompareVersions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{base_version=projects/*/locations/*/agents/*/flows/*/versions/*}:compareVersions", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_compare_versions( + request, metadata + ) + pb_request = version.CompareVersionsRequest.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 = version.CompareVersionsResponse() + pb_resp = version.CompareVersionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_compare_versions(resp) + return resp + + class _CreateVersion(VersionsRestStub): + def __hash__(self): + return hash("CreateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_version.CreateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create version method over HTTP. + + Args: + request (~.gcdc_version.CreateVersionRequest): + The request object. The request message for + [Versions.CreateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.CreateVersion]. + + 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": "/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/versions", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_create_version(request, metadata) + pb_request = gcdc_version.CreateVersionRequest.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_create_version(resp) + return resp + + class _DeleteVersion(VersionsRestStub): + def __hash__(self): + return hash("DeleteVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.DeleteVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete version method over HTTP. + + Args: + request (~.version.DeleteVersionRequest): + The request object. The request message for + [Versions.DeleteVersion][google.cloud.dialogflow.cx.v3beta1.Versions.DeleteVersion]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_version(request, metadata) + pb_request = version.DeleteVersionRequest.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 _GetVersion(VersionsRestStub): + def __hash__(self): + return hash("GetVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.GetVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.Version: + r"""Call the get version method over HTTP. + + Args: + request (~.version.GetVersionRequest): + The request object. The request message for + [Versions.GetVersion][google.cloud.dialogflow.cx.v3beta1.Versions.GetVersion]. + + 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: + ~.version.Version: + Represents a version of a flow. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_get_version(request, metadata) + pb_request = version.GetVersionRequest.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 = version.Version() + pb_resp = version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_version(resp) + return resp + + class _ListVersions(VersionsRestStub): + def __hash__(self): + return hash("ListVersions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.ListVersionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.ListVersionsResponse: + r"""Call the list versions method over HTTP. + + Args: + request (~.version.ListVersionsRequest): + The request object. The request message for + [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. + + 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: + ~.version.ListVersionsResponse: + The response message for + [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/versions", + }, + ] + request, metadata = self._interceptor.pre_list_versions(request, metadata) + pb_request = version.ListVersionsRequest.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 = version.ListVersionsResponse() + pb_resp = version.ListVersionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_versions(resp) + return resp + + class _LoadVersion(VersionsRestStub): + def __hash__(self): + return hash("LoadVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: version.LoadVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the load version method over HTTP. + + Args: + request (~.version.LoadVersionRequest): + The request object. The request message for + [Versions.LoadVersion][google.cloud.dialogflow.cx.v3beta1.Versions.LoadVersion]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/versions/*}:load", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_load_version(request, metadata) + pb_request = version.LoadVersionRequest.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_load_version(resp) + return resp + + class _UpdateVersion(VersionsRestStub): + def __hash__(self): + return hash("UpdateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "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: gcdc_version.UpdateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_version.Version: + r"""Call the update version method over HTTP. + + Args: + request (~.gcdc_version.UpdateVersionRequest): + The request object. The request message for + [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.UpdateVersion]. + + 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: + ~.gcdc_version.Version: + Represents a version of a flow. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{version.name=projects/*/locations/*/agents/*/flows/*/versions/*}", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_update_version(request, metadata) + pb_request = gcdc_version.UpdateVersionRequest.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 = gcdc_version.Version() + pb_resp = gcdc_version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_version(resp) + return resp + + @property + def compare_versions( + self, + ) -> Callable[[version.CompareVersionsRequest], version.CompareVersionsResponse]: + # 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._CompareVersions(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_version( + self, + ) -> Callable[[gcdc_version.CreateVersionRequest], 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._CreateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_version( + self, + ) -> Callable[[version.DeleteVersionRequest], 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._DeleteVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_version(self) -> Callable[[version.GetVersionRequest], version.Version]: + # 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._GetVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_versions( + self, + ) -> Callable[[version.ListVersionsRequest], version.ListVersionsResponse]: + # 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._ListVersions(self._session, self._host, self._interceptor) # type: ignore + + @property + def load_version( + self, + ) -> Callable[[version.LoadVersionRequest], 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._LoadVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_version( + self, + ) -> Callable[[gcdc_version.UpdateVersionRequest], gcdc_version.Version]: + # 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._UpdateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(VersionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(VersionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(VersionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(VersionsRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(VersionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("VersionsRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py index 0e57fba6..ff926482 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py @@ -56,6 +56,7 @@ from .transports.base import WebhooksTransport, DEFAULT_CLIENT_INFO from .transports.grpc import WebhooksGrpcTransport from .transports.grpc_asyncio import WebhooksGrpcAsyncIOTransport +from .transports.rest import WebhooksRestTransport class WebhooksClientMeta(type): @@ -69,6 +70,7 @@ class WebhooksClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[WebhooksTransport]] _transport_registry["grpc"] = WebhooksGrpcTransport _transport_registry["grpc_asyncio"] = WebhooksGrpcAsyncIOTransport + _transport_registry["rest"] = WebhooksRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/__init__.py index 2beebd10..bd4c8fb7 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/__init__.py @@ -19,15 +19,20 @@ from .base import WebhooksTransport from .grpc import WebhooksGrpcTransport from .grpc_asyncio import WebhooksGrpcAsyncIOTransport +from .rest import WebhooksRestTransport +from .rest import WebhooksRestInterceptor # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[WebhooksTransport]] _transport_registry["grpc"] = WebhooksGrpcTransport _transport_registry["grpc_asyncio"] = WebhooksGrpcAsyncIOTransport +_transport_registry["rest"] = WebhooksRestTransport __all__ = ( "WebhooksTransport", "WebhooksGrpcTransport", "WebhooksGrpcAsyncIOTransport", + "WebhooksRestTransport", + "WebhooksRestInterceptor", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/rest.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/rest.py new file mode 100644 index 00000000..232407bf --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/rest.py @@ -0,0 +1,1280 @@ +# -*- 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.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from requests import __version__ as requests_version +import dataclasses +import re +from typing import Any, 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.dialogflowcx_v3beta1.types import webhook +from google.cloud.dialogflowcx_v3beta1.types import webhook as gcdc_webhook +from google.protobuf import empty_pb2 # type: ignore + +from .base import WebhooksTransport, 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 WebhooksRestInterceptor: + """Interceptor for Webhooks. + + 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 WebhooksRestTransport. + + .. code-block:: python + class MyCustomWebhooksInterceptor(WebhooksRestInterceptor): + def pre_create_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_webhook(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_webhook(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_webhooks(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_webhooks(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_webhook(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_webhook(self, response): + logging.log(f"Received response: {response}") + return response + + transport = WebhooksRestTransport(interceptor=MyCustomWebhooksInterceptor()) + client = WebhooksClient(transport=transport) + + + """ + + def pre_create_webhook( + self, + request: gcdc_webhook.CreateWebhookRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_webhook.CreateWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_create_webhook( + self, response: gcdc_webhook.Webhook + ) -> gcdc_webhook.Webhook: + """Post-rpc interceptor for create_webhook + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_delete_webhook( + self, request: webhook.DeleteWebhookRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[webhook.DeleteWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def pre_get_webhook( + self, request: webhook.GetWebhookRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[webhook.GetWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_get_webhook(self, response: webhook.Webhook) -> webhook.Webhook: + """Post-rpc interceptor for get_webhook + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_list_webhooks( + self, request: webhook.ListWebhooksRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[webhook.ListWebhooksRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_webhooks + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_list_webhooks( + self, response: webhook.ListWebhooksResponse + ) -> webhook.ListWebhooksResponse: + """Post-rpc interceptor for list_webhooks + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_update_webhook( + self, + request: gcdc_webhook.UpdateWebhookRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcdc_webhook.UpdateWebhookRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_webhook + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_update_webhook( + self, response: gcdc_webhook.Webhook + ) -> gcdc_webhook.Webhook: + """Post-rpc interceptor for update_webhook + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Webhooks 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]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Webhooks server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Webhooks server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class WebhooksRestStub: + _session: AuthorizedSession + _host: str + _interceptor: WebhooksRestInterceptor + + +class WebhooksRestTransport(WebhooksTransport): + """REST backend transport for Webhooks. + + Service for managing + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook]. + + 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 = "dialogflow.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[WebhooksRestInterceptor] = 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 WebhooksRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateWebhook(WebhooksRestStub): + def __hash__(self): + return hash("CreateWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_webhook.CreateWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_webhook.Webhook: + r"""Call the create webhook method over HTTP. + + Args: + request (~.gcdc_webhook.CreateWebhookRequest): + The request object. The request message for + [Webhooks.CreateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.CreateWebhook]. + + 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: + ~.gcdc_webhook.Webhook: + Webhooks host the developer's + business logic. During a session, + webhooks allow the developer to use the + data extracted by Dialogflow's natural + language processing to generate dynamic + responses, validate collected data, or + trigger actions on the backend. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/webhooks", + "body": "webhook", + }, + ] + request, metadata = self._interceptor.pre_create_webhook(request, metadata) + pb_request = gcdc_webhook.CreateWebhookRequest.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 = gcdc_webhook.Webhook() + pb_resp = gcdc_webhook.Webhook.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_webhook(resp) + return resp + + class _DeleteWebhook(WebhooksRestStub): + def __hash__(self): + return hash("DeleteWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: webhook.DeleteWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete webhook method over HTTP. + + Args: + request (~.webhook.DeleteWebhookRequest): + The request object. The request message for + [Webhooks.DeleteWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.DeleteWebhook]. + + 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": "/v3beta1/{name=projects/*/locations/*/agents/*/webhooks/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_webhook(request, metadata) + pb_request = webhook.DeleteWebhookRequest.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 _GetWebhook(WebhooksRestStub): + def __hash__(self): + return hash("GetWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: webhook.GetWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> webhook.Webhook: + r"""Call the get webhook method over HTTP. + + Args: + request (~.webhook.GetWebhookRequest): + The request object. The request message for + [Webhooks.GetWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.GetWebhook]. + + 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: + ~.webhook.Webhook: + Webhooks host the developer's + business logic. During a session, + webhooks allow the developer to use the + data extracted by Dialogflow's natural + language processing to generate dynamic + responses, validate collected data, or + trigger actions on the backend. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/agents/*/webhooks/*}", + }, + ] + request, metadata = self._interceptor.pre_get_webhook(request, metadata) + pb_request = webhook.GetWebhookRequest.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 = webhook.Webhook() + pb_resp = webhook.Webhook.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_webhook(resp) + return resp + + class _ListWebhooks(WebhooksRestStub): + def __hash__(self): + return hash("ListWebhooks") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: webhook.ListWebhooksRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> webhook.ListWebhooksResponse: + r"""Call the list webhooks method over HTTP. + + Args: + request (~.webhook.ListWebhooksRequest): + The request object. The request message for + [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. + + 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: + ~.webhook.ListWebhooksResponse: + The response message for + [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{parent=projects/*/locations/*/agents/*}/webhooks", + }, + ] + request, metadata = self._interceptor.pre_list_webhooks(request, metadata) + pb_request = webhook.ListWebhooksRequest.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 = webhook.ListWebhooksResponse() + pb_resp = webhook.ListWebhooksResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_webhooks(resp) + return resp + + class _UpdateWebhook(WebhooksRestStub): + def __hash__(self): + return hash("UpdateWebhook") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @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: gcdc_webhook.UpdateWebhookRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_webhook.Webhook: + r"""Call the update webhook method over HTTP. + + Args: + request (~.gcdc_webhook.UpdateWebhookRequest): + The request object. The request message for + [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.UpdateWebhook]. + + 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: + ~.gcdc_webhook.Webhook: + Webhooks host the developer's + business logic. During a session, + webhooks allow the developer to use the + data extracted by Dialogflow's natural + language processing to generate dynamic + responses, validate collected data, or + trigger actions on the backend. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v3beta1/{webhook.name=projects/*/locations/*/agents/*/webhooks/*}", + "body": "webhook", + }, + ] + request, metadata = self._interceptor.pre_update_webhook(request, metadata) + pb_request = gcdc_webhook.UpdateWebhookRequest.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 = gcdc_webhook.Webhook() + pb_resp = gcdc_webhook.Webhook.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_webhook(resp) + return resp + + @property + def create_webhook( + self, + ) -> Callable[[gcdc_webhook.CreateWebhookRequest], gcdc_webhook.Webhook]: + # 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._CreateWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_webhook( + self, + ) -> Callable[[webhook.DeleteWebhookRequest], 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._DeleteWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_webhook(self) -> Callable[[webhook.GetWebhookRequest], webhook.Webhook]: + # 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._GetWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_webhooks( + self, + ) -> Callable[[webhook.ListWebhooksRequest], webhook.ListWebhooksResponse]: + # 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._ListWebhooks(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_webhook( + self, + ) -> Callable[[gcdc_webhook.UpdateWebhookRequest], gcdc_webhook.Webhook]: + # 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._UpdateWebhook(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(WebhooksRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation 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: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(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 = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(WebhooksRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations 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: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(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 = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(WebhooksRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation 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. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v3beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_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) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(WebhooksRestStub): + 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": "/v3beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*/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 list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(WebhooksRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations 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.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v3beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v3beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(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.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("WebhooksRestTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/types/__init__.py b/google/cloud/dialogflowcx_v3beta1/types/__init__.py index fe4a75ea..6f53c3e8 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/types/__init__.py @@ -37,6 +37,7 @@ OutputAudioConfig, SpeechWordInfo, SynthesizeSpeechConfig, + TextToSpeechSettings, VoiceSelectionParams, AudioEncoding, OutputAudioEncoding, @@ -120,6 +121,9 @@ from .fulfillment import ( Fulfillment, ) +from .gcs import ( + GcsDestination, +) from .intent import ( CreateIntentRequest, DeleteIntentRequest, @@ -280,6 +284,7 @@ "OutputAudioConfig", "SpeechWordInfo", "SynthesizeSpeechConfig", + "TextToSpeechSettings", "VoiceSelectionParams", "AudioEncoding", "OutputAudioEncoding", @@ -348,6 +353,7 @@ "UpdateFlowRequest", "ValidateFlowRequest", "Fulfillment", + "GcsDestination", "CreateIntentRequest", "DeleteIntentRequest", "GetIntentRequest", diff --git a/google/cloud/dialogflowcx_v3beta1/types/advanced_settings.py b/google/cloud/dialogflowcx_v3beta1/types/advanced_settings.py index 03921ec2..2b1c3403 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/advanced_settings.py +++ b/google/cloud/dialogflowcx_v3beta1/types/advanced_settings.py @@ -13,10 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore +from google.cloud.dialogflowcx_v3beta1.types import gcs + __protobuf__ = proto.module( package="google.cloud.dialogflow.cx.v3beta1", @@ -41,6 +45,13 @@ class AdvancedSettings(proto.Message): Hierarchy: Agent->Flow->Page->Fulfillment/Parameter. Attributes: + audio_export_gcs_destination (google.cloud.dialogflowcx_v3beta1.types.GcsDestination): + If present, incoming audio is exported by + Dialogflow to the configured Google Cloud + Storage destination. Exposed at the following + levels: + - Agent level + - Flow level logging_settings (google.cloud.dialogflowcx_v3beta1.types.AdvancedSettings.LoggingSettings): Settings for logging. Settings for Dialogflow History, Contact Center @@ -70,6 +81,11 @@ class LoggingSettings(proto.Message): number=3, ) + audio_export_gcs_destination: gcs.GcsDestination = proto.Field( + proto.MESSAGE, + number=2, + message=gcs.GcsDestination, + ) logging_settings: LoggingSettings = proto.Field( proto.MESSAGE, number=6, diff --git a/google/cloud/dialogflowcx_v3beta1/types/agent.py b/google/cloud/dialogflowcx_v3beta1/types/agent.py index c4ce4a89..579022f4 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/agent.py +++ b/google/cloud/dialogflowcx_v3beta1/types/agent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -20,6 +22,7 @@ from google.cloud.dialogflowcx_v3beta1.types import ( advanced_settings as gcdc_advanced_settings, ) +from google.cloud.dialogflowcx_v3beta1.types import audio_config from google.cloud.dialogflowcx_v3beta1.types import flow from google.protobuf import field_mask_pb2 # type: ignore @@ -139,6 +142,10 @@ class Agent(proto.Message): agent. The settings exposed at the lower level overrides the settings exposed at the higher level. + text_to_speech_settings (google.cloud.dialogflowcx_v3beta1.types.TextToSpeechSettings): + Settings on instructing the speech + synthesizer on how to generate the output audio + content. """ name: str = proto.Field( @@ -199,6 +206,11 @@ class Agent(proto.Message): number=22, message=gcdc_advanced_settings.AdvancedSettings, ) + text_to_speech_settings: audio_config.TextToSpeechSettings = proto.Field( + proto.MESSAGE, + number=31, + message=audio_config.TextToSpeechSettings, + ) class ListAgentsRequest(proto.Message): diff --git a/google/cloud/dialogflowcx_v3beta1/types/audio_config.py b/google/cloud/dialogflowcx_v3beta1/types/audio_config.py index 91e4c183..83d630fd 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/audio_config.py +++ b/google/cloud/dialogflowcx_v3beta1/types/audio_config.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -32,6 +34,7 @@ "VoiceSelectionParams", "SynthesizeSpeechConfig", "OutputAudioConfig", + "TextToSpeechSettings", }, ) @@ -472,4 +475,25 @@ class OutputAudioConfig(proto.Message): ) +class TextToSpeechSettings(proto.Message): + r"""Settings related to speech generating. + + Attributes: + synthesize_speech_configs (MutableMapping[str, google.cloud.dialogflowcx_v3beta1.types.SynthesizeSpeechConfig]): + Configuration of how speech should be + synthesized, mapping from language + (https://dialogflow.com/docs/reference/language) + to SynthesizeSpeechConfig. + """ + + synthesize_speech_configs: MutableMapping[ + str, "SynthesizeSpeechConfig" + ] = proto.MapField( + proto.STRING, + proto.MESSAGE, + number=1, + message="SynthesizeSpeechConfig", + ) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3beta1/types/changelog.py b/google/cloud/dialogflowcx_v3beta1/types/changelog.py index a5f861b2..6703a532 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/changelog.py +++ b/google/cloud/dialogflowcx_v3beta1/types/changelog.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/deployment.py b/google/cloud/dialogflowcx_v3beta1/types/deployment.py index 579e2307..734e767e 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/deployment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/deployment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/entity_type.py b/google/cloud/dialogflowcx_v3beta1/types/entity_type.py index 95bd34f1..dd253539 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/entity_type.py +++ b/google/cloud/dialogflowcx_v3beta1/types/entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/environment.py b/google/cloud/dialogflowcx_v3beta1/types/environment.py index 23bc22a5..b0a8865f 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/environment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/environment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore @@ -73,10 +75,10 @@ class Environment(proto.Message): characters. If exceeded, the request is rejected. version_configs (MutableSequence[google.cloud.dialogflowcx_v3beta1.types.Environment.VersionConfig]): - Required. A list of configurations for flow versions. You - should include version configs for all flows that are - reachable from [``Start Flow``][Agent.start_flow] in the - agent. Otherwise, an error will be returned. + A list of configurations for flow versions. You should + include version configs for all flows that are reachable + from [``Start Flow``][Agent.start_flow] in the agent. + Otherwise, an error will be returned. update_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Update time of this environment. test_cases_config (google.cloud.dialogflowcx_v3beta1.types.Environment.TestCasesConfig): diff --git a/google/cloud/dialogflowcx_v3beta1/types/experiment.py b/google/cloud/dialogflowcx_v3beta1/types/experiment.py index 289a75e0..8de9c173 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/experiment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/experiment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/flow.py b/google/cloud/dialogflowcx_v3beta1/types/flow.py index 47d16b27..16039ff4 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/flow.py +++ b/google/cloud/dialogflowcx_v3beta1/types/flow.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py b/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py index a893cada..3f2c88d9 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/gcs.py b/google/cloud/dialogflowcx_v3beta1/types/gcs.py new file mode 100644 index 00000000..54e0e48e --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/types/gcs.py @@ -0,0 +1,51 @@ +# -*- 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 __future__ import annotations + +from typing import MutableMapping, MutableSequence + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.dialogflow.cx.v3beta1", + manifest={ + "GcsDestination", + }, +) + + +class GcsDestination(proto.Message): + r"""Google Cloud Storage location for a Dialogflow operation that + writes or exports objects (e.g. exported agent or transcripts) + outside of Dialogflow. + + Attributes: + uri (str): + Required. The Google Cloud Storage URI for + the exported objects. A URI is of the form: + gs://bucket/object-name-or-prefix + Whether a full object name, or just a prefix, + its usage depends on the Dialogflow operation. + """ + + uri: str = proto.Field( + proto.STRING, + number=1, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3beta1/types/intent.py b/google/cloud/dialogflowcx_v3beta1/types/intent.py index 1d26309e..806eeab5 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/intent.py +++ b/google/cloud/dialogflowcx_v3beta1/types/intent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/page.py b/google/cloud/dialogflowcx_v3beta1/types/page.py index 46959cd7..e8ea16bd 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/page.py +++ b/google/cloud/dialogflowcx_v3beta1/types/page.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/response_message.py b/google/cloud/dialogflowcx_v3beta1/types/response_message.py index 346818b4..22e497b2 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/response_message.py +++ b/google/cloud/dialogflowcx_v3beta1/types/response_message.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/security_settings.py b/google/cloud/dialogflowcx_v3beta1/types/security_settings.py index 2ed93e8f..889ac75a 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/security_settings.py +++ b/google/cloud/dialogflowcx_v3beta1/types/security_settings.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/session.py b/google/cloud/dialogflowcx_v3beta1/types/session.py index 5017d9ba..e0025e9c 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/session.py +++ b/google/cloud/dialogflowcx_v3beta1/types/session.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py b/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py index 05eab442..58d9fdde 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py +++ b/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/test_case.py b/google/cloud/dialogflowcx_v3beta1/types/test_case.py index cf9d1d42..e24a1259 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/test_case.py +++ b/google/cloud/dialogflowcx_v3beta1/types/test_case.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py b/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py index 5c702091..6dcf22bc 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py +++ b/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/validation_message.py b/google/cloud/dialogflowcx_v3beta1/types/validation_message.py index e57443b8..153db63e 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/validation_message.py +++ b/google/cloud/dialogflowcx_v3beta1/types/validation_message.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/version.py b/google/cloud/dialogflowcx_v3beta1/types/version.py index 6b2732b5..df529e24 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/version.py +++ b/google/cloud/dialogflowcx_v3beta1/types/version.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflowcx_v3beta1/types/webhook.py b/google/cloud/dialogflowcx_v3beta1/types/webhook.py index af782376..c6230740 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/webhook.py +++ b/google/cloud/dialogflowcx_v3beta1/types/webhook.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_async.py b/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_async.py index 74fb0652..25c075eb 100644 --- a/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_async.py +++ b/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_async.py @@ -41,7 +41,6 @@ async def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.CreateEnvironmentRequest( parent="parent_value", diff --git a/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_sync.py b/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_sync.py index 1fdd6ab1..0df85233 100644 --- a/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_sync.py +++ b/samples/generated_samples/dialogflow_v3_generated_environments_create_environment_sync.py @@ -41,7 +41,6 @@ def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.CreateEnvironmentRequest( parent="parent_value", diff --git a/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_async.py b/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_async.py index 9f321f7e..ac75ae15 100644 --- a/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_async.py +++ b/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_async.py @@ -41,7 +41,6 @@ async def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.UpdateEnvironmentRequest( environment=environment, diff --git a/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_sync.py b/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_sync.py index 5ae00fb1..e5f61a84 100644 --- a/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_sync.py +++ b/samples/generated_samples/dialogflow_v3_generated_environments_update_environment_sync.py @@ -41,7 +41,6 @@ def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3.UpdateEnvironmentRequest( environment=environment, diff --git a/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_async.py b/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_async.py index aa1e90a8..308d8803 100644 --- a/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_async.py +++ b/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_async.py @@ -41,7 +41,6 @@ async def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.CreateEnvironmentRequest( parent="parent_value", diff --git a/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_sync.py b/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_sync.py index 52a738e5..4463c470 100644 --- a/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_sync.py +++ b/samples/generated_samples/dialogflow_v3beta1_generated_environments_create_environment_sync.py @@ -41,7 +41,6 @@ def sample_create_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.CreateEnvironmentRequest( parent="parent_value", diff --git a/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_async.py b/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_async.py index dfc8e8e2..57fefda8 100644 --- a/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_async.py +++ b/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_async.py @@ -41,7 +41,6 @@ async def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.UpdateEnvironmentRequest( environment=environment, diff --git a/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_sync.py b/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_sync.py index f89dd86a..6cbc9325 100644 --- a/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_sync.py +++ b/samples/generated_samples/dialogflow_v3beta1_generated_environments_update_environment_sync.py @@ -41,7 +41,6 @@ def sample_update_environment(): # Initialize request argument(s) environment = dialogflowcx_v3beta1.Environment() environment.display_name = "display_name_value" - environment.version_configs.version = "version_value" request = dialogflowcx_v3beta1.UpdateEnvironmentRequest( environment=environment, diff --git a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3.json b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3.json index ac7adaf3..7b8b2aa7 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dialogflow-cx", - "version": "1.18.0" + "version": "1.19.0" }, "snippets": [ { @@ -2958,12 +2958,12 @@ "regionTag": "dialogflow_v3_generated_Environments_CreateEnvironment_async", "segments": [ { - "end": 60, + "end": 59, "start": 27, "type": "FULL" }, { - "end": 60, + "end": 59, "start": 27, "type": "SHORT" }, @@ -2973,18 +2973,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 50, + "end": 49, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 57, - "start": 51, + "end": 56, + "start": 50, "type": "REQUEST_EXECUTION" }, { - "end": 61, - "start": 58, + "end": 60, + "start": 57, "type": "RESPONSE_HANDLING" } ], @@ -3042,12 +3042,12 @@ "regionTag": "dialogflow_v3_generated_Environments_CreateEnvironment_sync", "segments": [ { - "end": 60, + "end": 59, "start": 27, "type": "FULL" }, { - "end": 60, + "end": 59, "start": 27, "type": "SHORT" }, @@ -3057,18 +3057,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 50, + "end": 49, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 57, - "start": 51, + "end": 56, + "start": 50, "type": "REQUEST_EXECUTION" }, { - "end": 61, - "start": 58, + "end": 60, + "start": 57, "type": "RESPONSE_HANDLING" } ], @@ -4232,12 +4232,12 @@ "regionTag": "dialogflow_v3_generated_Environments_UpdateEnvironment_async", "segments": [ { - "end": 59, + "end": 58, "start": 27, "type": "FULL" }, { - "end": 59, + "end": 58, "start": 27, "type": "SHORT" }, @@ -4247,18 +4247,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 49, + "end": 48, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 56, - "start": 50, + "end": 55, + "start": 49, "type": "REQUEST_EXECUTION" }, { - "end": 60, - "start": 57, + "end": 59, + "start": 56, "type": "RESPONSE_HANDLING" } ], @@ -4316,12 +4316,12 @@ "regionTag": "dialogflow_v3_generated_Environments_UpdateEnvironment_sync", "segments": [ { - "end": 59, + "end": 58, "start": 27, "type": "FULL" }, { - "end": 59, + "end": 58, "start": 27, "type": "SHORT" }, @@ -4331,18 +4331,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 49, + "end": 48, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 56, - "start": 50, + "end": 55, + "start": 49, "type": "REQUEST_EXECUTION" }, { - "end": 60, - "start": 57, + "end": 59, + "start": 56, "type": "RESPONSE_HANDLING" } ], diff --git a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3beta1.json index d0ead9ce..568546a7 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.cx.v3beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dialogflow-cx", - "version": "1.18.0" + "version": "1.19.0" }, "snippets": [ { @@ -2958,12 +2958,12 @@ "regionTag": "dialogflow_v3beta1_generated_Environments_CreateEnvironment_async", "segments": [ { - "end": 60, + "end": 59, "start": 27, "type": "FULL" }, { - "end": 60, + "end": 59, "start": 27, "type": "SHORT" }, @@ -2973,18 +2973,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 50, + "end": 49, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 57, - "start": 51, + "end": 56, + "start": 50, "type": "REQUEST_EXECUTION" }, { - "end": 61, - "start": 58, + "end": 60, + "start": 57, "type": "RESPONSE_HANDLING" } ], @@ -3042,12 +3042,12 @@ "regionTag": "dialogflow_v3beta1_generated_Environments_CreateEnvironment_sync", "segments": [ { - "end": 60, + "end": 59, "start": 27, "type": "FULL" }, { - "end": 60, + "end": 59, "start": 27, "type": "SHORT" }, @@ -3057,18 +3057,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 50, + "end": 49, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 57, - "start": 51, + "end": 56, + "start": 50, "type": "REQUEST_EXECUTION" }, { - "end": 61, - "start": 58, + "end": 60, + "start": 57, "type": "RESPONSE_HANDLING" } ], @@ -4232,12 +4232,12 @@ "regionTag": "dialogflow_v3beta1_generated_Environments_UpdateEnvironment_async", "segments": [ { - "end": 59, + "end": 58, "start": 27, "type": "FULL" }, { - "end": 59, + "end": 58, "start": 27, "type": "SHORT" }, @@ -4247,18 +4247,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 49, + "end": 48, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 56, - "start": 50, + "end": 55, + "start": 49, "type": "REQUEST_EXECUTION" }, { - "end": 60, - "start": 57, + "end": 59, + "start": 56, "type": "RESPONSE_HANDLING" } ], @@ -4316,12 +4316,12 @@ "regionTag": "dialogflow_v3beta1_generated_Environments_UpdateEnvironment_sync", "segments": [ { - "end": 59, + "end": 58, "start": 27, "type": "FULL" }, { - "end": 59, + "end": 58, "start": 27, "type": "SHORT" }, @@ -4331,18 +4331,18 @@ "type": "CLIENT_INITIALIZATION" }, { - "end": 49, + "end": 48, "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 56, - "start": 50, + "end": 55, + "start": 49, "type": "REQUEST_EXECUTION" }, { - "end": 60, - "start": 57, + "end": 59, + "start": 56, "type": "RESPONSE_HANDLING" } ], diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 390c05c3..ba3cb8c1 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,3 +1,3 @@ -google-cloud-dialogflow-cx==1.17.1 -Flask==2.2.2 +google-cloud-dialogflow-cx==1.18.0 +Flask==2.2.3 python-dateutil==2.8.2 diff --git a/scripts/fixup_dialogflowcx_v3_keywords.py b/scripts/fixup_dialogflowcx_v3_keywords.py index 24a0ece5..a86e407c 100644 --- a/scripts/fixup_dialogflowcx_v3_keywords.py +++ b/scripts/fixup_dialogflowcx_v3_keywords.py @@ -113,7 +113,7 @@ class dialogflowcxCallTransformer(cst.CSTTransformer): 'list_webhooks': ('parent', 'page_size', 'page_token', ), 'load_version': ('name', 'allow_override_agent_resources', ), 'lookup_environment_history': ('name', 'page_size', 'page_token', ), - 'match_intent': ('session', 'query_input', 'query_params', ), + 'match_intent': ('session', 'query_input', 'query_params', 'persist_parameter_changes', ), 'restore_agent': ('name', 'agent_uri', 'agent_content', 'restore_option', ), 'run_continuous_test': ('environment', ), 'run_test_case': ('name', 'environment', ), diff --git a/setup.py b/setup.py index c26496f6..1aec33f1 100644 --- a/setup.py +++ b/setup.py @@ -57,9 +57,7 @@ if package.startswith("google") ] -namespaces = ["google"] -if "google.cloud" in packages: - namespaces.append("google.cloud") +namespaces = ["google", "google.cloud"] setuptools.setup( name=name, diff --git a/tests/unit/gapic/dialogflowcx_v3/test_agents.py b/tests/unit/gapic/dialogflowcx_v3/test_agents.py index f08ef1ea..acd949ca 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_agents.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_agents.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 @@ -48,7 +55,9 @@ from google.cloud.dialogflowcx_v3.types import advanced_settings from google.cloud.dialogflowcx_v3.types import agent from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3.types import audio_config from google.cloud.dialogflowcx_v3.types import flow +from google.cloud.dialogflowcx_v3.types import gcs from google.cloud.location import locations_pb2 from google.longrunning import operations_pb2 from google.oauth2 import service_account @@ -101,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_info(client_class, transport_name): @@ -114,7 +124,11 @@ def test_agents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -122,6 +136,7 @@ def test_agents_client_from_service_account_info(client_class, transport_name): [ (transports.AgentsGrpcTransport, "grpc"), (transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -145,6 +160,7 @@ def test_agents_client_service_account_always_use_jwt(transport_class, transport [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_file(client_class, transport_name): @@ -165,13 +181,18 @@ def test_agents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_agents_client_get_transport_class(): transport = AgentsClient.get_transport_class() available_transports = [ transports.AgentsGrpcTransport, + transports.AgentsRestTransport, ] assert transport in available_transports @@ -184,6 +205,7 @@ def test_agents_client_get_transport_class(): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -323,6 +345,8 @@ def test_agents_client_client_options(client_class, transport_class, transport_n "grpc_asyncio", "false", ), + (AgentsClient, transports.AgentsRestTransport, "rest", "true"), + (AgentsClient, transports.AgentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -508,6 +532,7 @@ def test_agents_client_get_mtls_endpoint_and_cert_source(client_class): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_client_options_scopes( @@ -543,6 +568,7 @@ def test_agents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AgentsClient, transports.AgentsRestTransport, "rest", None), ], ) def test_agents_client_client_options_credentials_file( @@ -2811,258 +2837,2690 @@ async def test_get_agent_validation_result_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.AgentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + agent.ListAgentsRequest, + dict, + ], +) +def test_list_agents_rest(request_type): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = AgentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AgentsClient( - 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 = agent.ListAgentsResponse( + next_page_token="next_page_token_value", ) - # 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 = AgentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.ListAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_agents(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAgentsPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - client = AgentsClient(transport=transport) - assert client.transport is transport +def test_list_agents_rest_required_fields(request_type=agent.ListAgentsRequest): + transport_class = transports.AgentsRestTransport -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + 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, + ) ) - channel = transport.grpc_channel - assert channel - transport = transports.AgentsGrpcAsyncIOTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - channel = transport.grpc_channel - assert channel + # verify fields with default values are dropped + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_agents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], -) -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() + # verify required fields with default values are now present + jsonified_request["parent"] = "parent_value" -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = AgentsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_agents._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", + ) ) - assert transport.kind == transport_name + 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 = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.ListAgentsResponse() + # 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 = agent.ListAgentsResponse.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_agents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_agents_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.AgentsGrpcTransport, + + unset_fields = transport.list_agents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_agents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_agents_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_list_agents" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_list_agents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ListAgentsRequest.pb(agent.ListAgentsRequest()) + 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 = agent.ListAgentsResponse.to_json( + agent.ListAgentsResponse() ) + request = agent.ListAgentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.ListAgentsResponse() -def test_agents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.agents.transports.AgentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_agents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_agents", - "get_agent", - "create_agent", - "update_agent", - "delete_agent", - "export_agent", - "restore_agent", - "validate_agent", - "get_agent_validation_result", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + pre.assert_called_once() + post.assert_called_once() - with pytest.raises(NotImplementedError): - transport.close() - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client +def test_list_agents_rest_bad_request( + transport: str = "rest", request_type=agent.ListAgentsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/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_agents(request) -def test_agents_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.dialogflowcx_v3.services.agents.transports.AgentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AgentsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) +def test_list_agents_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) -def test_agents_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.dialogflowcx_v3.services.agents.transports.AgentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AgentsTransport() - adc.assert_called_once() + # 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 = agent.ListAgentsResponse() + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} -def test_agents_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) - AgentsClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, + # 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 = agent.ListAgentsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], -) -def test_agents_transport_auth_adc(transport_class): - # If credentials and host are not provided, the transport class should use - # ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class(quota_project_id="octopus", scopes=["1", "2"]) - adc.assert_called_once_with( - scopes=["1", "2"], - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + client.list_agents(**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/v3/{parent=projects/*/locations/*}/agents" % client.transport._host, + args[1], ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], +def test_list_agents_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agents( + agent.ListAgentsRequest(), + parent="parent_value", + ) + + +def test_list_agents_rest_pager(transport: str = "rest"): + client = AgentsClient( + 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 = ( + agent.ListAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + agent.Agent(), + ], + next_page_token="abc", + ), + agent.ListAgentsResponse( + agents=[], + next_page_token="def", + ), + agent.ListAgentsResponse( + agents=[ + agent.Agent(), + ], + next_page_token="ghi", + ), + agent.ListAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(agent.ListAgentsResponse.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": "projects/sample1/locations/sample2"} + + pager = client.list_agents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, agent.Agent) for i in results) + + pages = list(client.list_agents(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", + [ + agent.GetAgentRequest, + dict, + ], +) +def test_get_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = agent.Agent( + name="name_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + start_flow="start_flow_value", + security_settings="security_settings_value", + enable_stackdriver_logging=True, + enable_spell_correction=True, + locked=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.Agent.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_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.Agent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True + assert response.enable_spell_correction is True + assert response.locked is True + + +def test_get_agent_rest_required_fields(request_type=agent.GetAgentRequest): + transport_class = transports.AgentsRestTransport + + 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_agent._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_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.Agent() + # 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 = agent.Agent.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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_get_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetAgentRequest.pb(agent.GetAgentRequest()) + 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 = agent.Agent.to_json(agent.Agent()) + + request = agent.GetAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.Agent() + + client.get_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_agent_rest_bad_request( + transport: str = "rest", request_type=agent.GetAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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_agent(request) + + +def test_get_agent_rest_flattened(): + client = AgentsClient( + 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 = agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/locations/sample2/agents/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 = agent.Agent.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_agent(**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/v3/{name=projects/*/locations/*/agents/*}" % client.transport._host, + args[1], + ) + + +def test_get_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + agent.GetAgentRequest(), + name="name_value", + ) + + +def test_get_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_agent.CreateAgentRequest, + dict, + ], +) +def test_create_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["agent"] = { + "name": "name_value", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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 = gcdc_agent.Agent( + name="name_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + start_flow="start_flow_value", + security_settings="security_settings_value", + enable_stackdriver_logging=True, + enable_spell_correction=True, + locked=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_agent.Agent.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_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_agent.Agent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True + assert response.enable_spell_correction is True + assert response.locked is True + + +def test_create_agent_rest_required_fields(request_type=gcdc_agent.CreateAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).create_agent._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() + ).create_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_agent.Agent() + # 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 = gcdc_agent.Agent.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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_agent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "agent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_create_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_create_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_agent.CreateAgentRequest.pb(gcdc_agent.CreateAgentRequest()) + 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 = gcdc_agent.Agent.to_json(gcdc_agent.Agent()) + + request = gcdc_agent.CreateAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_agent.Agent() + + client.create_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_agent_rest_bad_request( + transport: str = "rest", request_type=gcdc_agent.CreateAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["agent"] = { + "name": "name_value", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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_agent(request) + + +def test_create_agent_rest_flattened(): + client = AgentsClient( + 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 = gcdc_agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + agent=gcdc_agent.Agent(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 = gcdc_agent.Agent.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_agent(**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/v3/{parent=projects/*/locations/*}/agents" % client.transport._host, + args[1], + ) + + +def test_create_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + gcdc_agent.CreateAgentRequest(), + parent="parent_value", + agent=gcdc_agent.Agent(name="name_value"), + ) + + +def test_create_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_agent.UpdateAgentRequest, + dict, + ], +) +def test_update_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "agent": {"name": "projects/sample1/locations/sample2/agents/sample3"} + } + request_init["agent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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 = gcdc_agent.Agent( + name="name_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + start_flow="start_flow_value", + security_settings="security_settings_value", + enable_stackdriver_logging=True, + enable_spell_correction=True, + locked=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_agent.Agent.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_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_agent.Agent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True + assert response.enable_spell_correction is True + assert response.locked is True + + +def test_update_agent_rest_required_fields(request_type=gcdc_agent.UpdateAgentRequest): + transport_class = transports.AgentsRestTransport + + 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_agent._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_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_agent.Agent() + # 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 = gcdc_agent.Agent.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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("agent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_update_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_update_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_agent.UpdateAgentRequest.pb(gcdc_agent.UpdateAgentRequest()) + 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 = gcdc_agent.Agent.to_json(gcdc_agent.Agent()) + + request = gcdc_agent.UpdateAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_agent.Agent() + + client.update_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_agent_rest_bad_request( + transport: str = "rest", request_type=gcdc_agent.UpdateAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "agent": {"name": "projects/sample1/locations/sample2/agents/sample3"} + } + request_init["agent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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_agent(request) + + +def test_update_agent_rest_flattened(): + client = AgentsClient( + 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 = gcdc_agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = { + "agent": {"name": "projects/sample1/locations/sample2/agents/sample3"} + } + + # get truthy value for each flattened field + mock_args = dict( + agent=gcdc_agent.Agent(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 = gcdc_agent.Agent.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_agent(**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/v3/{agent.name=projects/*/locations/*/agents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + gcdc_agent.UpdateAgentRequest(), + agent=gcdc_agent.Agent(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.DeleteAgentRequest, + dict, + ], +) +def test_delete_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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_agent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_agent_rest_required_fields(request_type=agent.DeleteAgentRequest): + transport_class = transports.AgentsRestTransport + + 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_agent._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_agent._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 = AgentsClient( + 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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "pre_delete_agent" + ) as pre: + pre.assert_not_called() + pb_message = agent.DeleteAgentRequest.pb(agent.DeleteAgentRequest()) + 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 = agent.DeleteAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_agent_rest_bad_request( + transport: str = "rest", request_type=agent.DeleteAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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_agent(request) + + +def test_delete_agent_rest_flattened(): + client = AgentsClient( + 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": "projects/sample1/locations/sample2/agents/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_agent(**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/v3/{name=projects/*/locations/*/agents/*}" % client.transport._host, + args[1], + ) + + +def test_delete_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + agent.DeleteAgentRequest(), + name="name_value", + ) + + +def test_delete_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ExportAgentRequest, + dict, + ], +) +def test_export_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = 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.export_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_agent_rest_required_fields(request_type=agent.ExportAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).export_agent._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() + ).export_agent._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 = AgentsClient( + 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.export_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_export_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_export_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ExportAgentRequest.pb(agent.ExportAgentRequest()) + 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 = agent.ExportAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ExportAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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.export_agent(request) + + +def test_export_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.RestoreAgentRequest, + dict, + ], +) +def test_restore_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = 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.restore_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_restore_agent_rest_required_fields(request_type=agent.RestoreAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).restore_agent._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() + ).restore_agent._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 = AgentsClient( + 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.restore_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_restore_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.restore_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_restore_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_restore_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_restore_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.RestoreAgentRequest.pb(agent.RestoreAgentRequest()) + 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 = agent.RestoreAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.restore_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_restore_agent_rest_bad_request( + transport: str = "rest", request_type=agent.RestoreAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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.restore_agent(request) + + +def test_restore_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ValidateAgentRequest, + dict, + ], +) +def test_validate_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = agent.AgentValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.AgentValidationResult.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.validate_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + assert response.name == "name_value" + + +def test_validate_agent_rest_required_fields(request_type=agent.ValidateAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).validate_agent._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() + ).validate_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.AgentValidationResult() + # 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 = agent.AgentValidationResult.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.validate_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_validate_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.validate_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_validate_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_validate_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_validate_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ValidateAgentRequest.pb(agent.ValidateAgentRequest()) + 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 = agent.AgentValidationResult.to_json( + agent.AgentValidationResult() + ) + + request = agent.ValidateAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.AgentValidationResult() + + client.validate_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_validate_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ValidateAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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.validate_agent(request) + + +def test_validate_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.GetAgentValidationResultRequest, + dict, + ], +) +def test_get_agent_validation_result_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/validationResult" + } + 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 = agent.AgentValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.AgentValidationResult.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_agent_validation_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + assert response.name == "name_value" + + +def test_get_agent_validation_result_rest_required_fields( + request_type=agent.GetAgentValidationResultRequest, +): + transport_class = transports.AgentsRestTransport + + 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_agent_validation_result._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_agent_validation_result._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.AgentValidationResult() + # 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 = agent.AgentValidationResult.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_agent_validation_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_agent_validation_result_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_agent_validation_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_agent_validation_result_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_get_agent_validation_result" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_agent_validation_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetAgentValidationResultRequest.pb( + agent.GetAgentValidationResultRequest() + ) + 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 = agent.AgentValidationResult.to_json( + agent.AgentValidationResult() + ) + + request = agent.GetAgentValidationResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.AgentValidationResult() + + client.get_agent_validation_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_agent_validation_result_rest_bad_request( + transport: str = "rest", request_type=agent.GetAgentValidationResultRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/validationResult" + } + 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_agent_validation_result(request) + + +def test_get_agent_validation_result_rest_flattened(): + client = AgentsClient( + 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 = agent.AgentValidationResult() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/validationResult" + } + + # 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 = agent.AgentValidationResult.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_agent_validation_result(**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/v3/{name=projects/*/locations/*/agents/*/validationResult}" + % client.transport._host, + args[1], + ) + + +def test_get_agent_validation_result_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent_validation_result( + agent.GetAgentValidationResultRequest(), + name="name_value", + ) + + +def test_get_agent_validation_result_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AgentsClient( + 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 = AgentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AgentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AgentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, + ], +) +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 = AgentsClient.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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AgentsGrpcTransport, + ) + + +def test_agents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_agents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.agents.transports.AgentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_agents", + "get_agent", + "create_agent", + "update_agent", + "delete_agent", + "export_agent", + "restore_agent", + "validate_agent", + "get_agent_validation_result", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_agents_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.dialogflowcx_v3.services.agents.transports.AgentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AgentsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_agents_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.dialogflowcx_v3.services.agents.transports.AgentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AgentsTransport() + adc.assert_called_once() + + +def test_agents_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) + AgentsClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + ], +) +def test_agents_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, + ], ) def test_agents_transport_auth_gdch_credentials(transport_class): host = "https://language.com" @@ -3159,11 +5617,40 @@ def test_agents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_agents_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.AgentsRestTransport( + 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_agents_rest_lro_client(): + client = AgentsClient( + 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_agents_host_no_port(transport_name): @@ -3174,7 +5661,11 @@ def test_agents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3182,6 +5673,7 @@ def test_agents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_agents_host_with_port(transport_name): @@ -3192,7 +5684,57 @@ def test_agents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_agents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AgentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AgentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_agents._session + session2 = client2.transport.list_agents._session + assert session1 != session2 + session1 = client1.transport.get_agent._session + session2 = client2.transport.get_agent._session + assert session1 != session2 + session1 = client1.transport.create_agent._session + session2 = client2.transport.create_agent._session + assert session1 != session2 + session1 = client1.transport.update_agent._session + session2 = client2.transport.update_agent._session + assert session1 != session2 + session1 = client1.transport.delete_agent._session + session2 = client2.transport.delete_agent._session + assert session1 != session2 + session1 = client1.transport.export_agent._session + session2 = client2.transport.export_agent._session + assert session1 != session2 + session1 = client1.transport.restore_agent._session + session2 = client2.transport.restore_agent._session + assert session1 != session2 + session1 = client1.transport.validate_agent._session + session2 = client2.transport.validate_agent._session + assert session1 != session2 + session1 = client1.transport.get_agent_validation_result._session + session2 = client2.transport.get_agent_validation_result._session + assert session1 != session2 def test_agents_grpc_transport_channel(): @@ -3654,6 +6196,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4371,6 +7199,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4388,6 +7217,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_changelogs.py b/tests/unit/gapic/dialogflowcx_v3/test_changelogs.py index a056b25e..dbfe6e1d 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_changelogs.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_changelogs.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 @@ -95,6 +102,7 @@ def test__get_default_mtls_endpoint(): [ (ChangelogsClient, "grpc"), (ChangelogsAsyncClient, "grpc_asyncio"), + (ChangelogsClient, "rest"), ], ) def test_changelogs_client_from_service_account_info(client_class, transport_name): @@ -108,7 +116,11 @@ def test_changelogs_client_from_service_account_info(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +128,7 @@ def test_changelogs_client_from_service_account_info(client_class, transport_nam [ (transports.ChangelogsGrpcTransport, "grpc"), (transports.ChangelogsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ChangelogsRestTransport, "rest"), ], ) def test_changelogs_client_service_account_always_use_jwt( @@ -141,6 +154,7 @@ def test_changelogs_client_service_account_always_use_jwt( [ (ChangelogsClient, "grpc"), (ChangelogsAsyncClient, "grpc_asyncio"), + (ChangelogsClient, "rest"), ], ) def test_changelogs_client_from_service_account_file(client_class, transport_name): @@ -161,13 +175,18 @@ def test_changelogs_client_from_service_account_file(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_changelogs_client_get_transport_class(): transport = ChangelogsClient.get_transport_class() available_transports = [ transports.ChangelogsGrpcTransport, + transports.ChangelogsRestTransport, ] assert transport in available_transports @@ -184,6 +203,7 @@ def test_changelogs_client_get_transport_class(): transports.ChangelogsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +347,8 @@ def test_changelogs_client_client_options( "grpc_asyncio", "false", ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest", "true"), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -520,6 +542,7 @@ def test_changelogs_client_get_mtls_endpoint_and_cert_source(client_class): transports.ChangelogsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest"), ], ) def test_changelogs_client_client_options_scopes( @@ -555,6 +578,7 @@ def test_changelogs_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest", None), ], ) def test_changelogs_client_client_options_credentials_file( @@ -1331,6 +1355,624 @@ async def test_get_changelog_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + changelog.ListChangelogsRequest, + dict, + ], +) +def test_list_changelogs_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = changelog.ListChangelogsResponse( + 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 = changelog.ListChangelogsResponse.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_changelogs(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListChangelogsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_changelogs_rest_required_fields( + request_type=changelog.ListChangelogsRequest, +): + transport_class = transports.ChangelogsRestTransport + + 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_changelogs._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_changelogs._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 = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = changelog.ListChangelogsResponse() + # 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 = changelog.ListChangelogsResponse.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_changelogs(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_changelogs_rest_unset_required_fields(): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_changelogs._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_changelogs_rest_interceptors(null_interceptor): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ChangelogsRestInterceptor(), + ) + client = ChangelogsClient(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.ChangelogsRestInterceptor, "post_list_changelogs" + ) as post, mock.patch.object( + transports.ChangelogsRestInterceptor, "pre_list_changelogs" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = changelog.ListChangelogsRequest.pb( + changelog.ListChangelogsRequest() + ) + 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 = changelog.ListChangelogsResponse.to_json( + changelog.ListChangelogsResponse() + ) + + request = changelog.ListChangelogsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = changelog.ListChangelogsResponse() + + client.list_changelogs( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_changelogs_rest_bad_request( + transport: str = "rest", request_type=changelog.ListChangelogsRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.list_changelogs(request) + + +def test_list_changelogs_rest_flattened(): + client = ChangelogsClient( + 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 = changelog.ListChangelogsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = changelog.ListChangelogsResponse.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_changelogs(**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/v3/{parent=projects/*/locations/*/agents/*}/changelogs" + % client.transport._host, + args[1], + ) + + +def test_list_changelogs_rest_flattened_error(transport: str = "rest"): + client = ChangelogsClient( + 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_changelogs( + changelog.ListChangelogsRequest(), + parent="parent_value", + ) + + +def test_list_changelogs_rest_pager(transport: str = "rest"): + client = ChangelogsClient( + 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 = ( + changelog.ListChangelogsResponse( + changelogs=[ + changelog.Changelog(), + changelog.Changelog(), + changelog.Changelog(), + ], + next_page_token="abc", + ), + changelog.ListChangelogsResponse( + changelogs=[], + next_page_token="def", + ), + changelog.ListChangelogsResponse( + changelogs=[ + changelog.Changelog(), + ], + next_page_token="ghi", + ), + changelog.ListChangelogsResponse( + changelogs=[ + changelog.Changelog(), + changelog.Changelog(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(changelog.ListChangelogsResponse.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": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_changelogs(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, changelog.Changelog) for i in results) + + pages = list(client.list_changelogs(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", + [ + changelog.GetChangelogRequest, + dict, + ], +) +def test_get_changelog_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/changelogs/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 = changelog.Changelog( + name="name_value", + user_email="user_email_value", + display_name="display_name_value", + action="action_value", + type_="type__value", + resource="resource_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = changelog.Changelog.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_changelog(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, changelog.Changelog) + assert response.name == "name_value" + assert response.user_email == "user_email_value" + assert response.display_name == "display_name_value" + assert response.action == "action_value" + assert response.type_ == "type__value" + assert response.resource == "resource_value" + + +def test_get_changelog_rest_required_fields(request_type=changelog.GetChangelogRequest): + transport_class = transports.ChangelogsRestTransport + + 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_changelog._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_changelog._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 = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = changelog.Changelog() + # 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 = changelog.Changelog.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_changelog(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_changelog_rest_unset_required_fields(): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_changelog._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_changelog_rest_interceptors(null_interceptor): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ChangelogsRestInterceptor(), + ) + client = ChangelogsClient(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.ChangelogsRestInterceptor, "post_get_changelog" + ) as post, mock.patch.object( + transports.ChangelogsRestInterceptor, "pre_get_changelog" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = changelog.GetChangelogRequest.pb(changelog.GetChangelogRequest()) + 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 = changelog.Changelog.to_json(changelog.Changelog()) + + request = changelog.GetChangelogRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = changelog.Changelog() + + client.get_changelog( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_changelog_rest_bad_request( + transport: str = "rest", request_type=changelog.GetChangelogRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/changelogs/sample4" + } + 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_changelog(request) + + +def test_get_changelog_rest_flattened(): + client = ChangelogsClient( + 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 = changelog.Changelog() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/changelogs/sample4" + } + + # 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 = changelog.Changelog.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_changelog(**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/v3/{name=projects/*/locations/*/agents/*/changelogs/*}" + % client.transport._host, + args[1], + ) + + +def test_get_changelog_rest_flattened_error(transport: str = "rest"): + client = ChangelogsClient( + 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_changelog( + changelog.GetChangelogRequest(), + name="name_value", + ) + + +def test_get_changelog_rest_error(): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.ChangelogsGrpcTransport( @@ -1412,6 +2054,7 @@ def test_transport_get_channel(): [ transports.ChangelogsGrpcTransport, transports.ChangelogsGrpcAsyncIOTransport, + transports.ChangelogsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1426,6 +2069,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1570,6 +2214,7 @@ def test_changelogs_transport_auth_adc(transport_class): [ transports.ChangelogsGrpcTransport, transports.ChangelogsGrpcAsyncIOTransport, + transports.ChangelogsRestTransport, ], ) def test_changelogs_transport_auth_gdch_credentials(transport_class): @@ -1667,11 +2312,23 @@ def test_changelogs_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_changelogs_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.ChangelogsRestTransport( + 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_changelogs_host_no_port(transport_name): @@ -1682,7 +2339,11 @@ def test_changelogs_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1690,6 +2351,7 @@ def test_changelogs_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_changelogs_host_with_port(transport_name): @@ -1700,7 +2362,36 @@ def test_changelogs_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_changelogs_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ChangelogsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ChangelogsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_changelogs._session + session2 = client2.transport.list_changelogs._session + assert session1 != session2 + session1 = client1.transport.get_changelog._session + session2 = client2.transport.get_changelog._session + assert session1 != session2 def test_changelogs_grpc_transport_channel(): @@ -1990,6 +2681,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ChangelogsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2707,6 +3684,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2724,6 +3702,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_deployments.py b/tests/unit/gapic/dialogflowcx_v3/test_deployments.py index e37b778a..e666a063 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_deployments.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_deployments.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 @@ -95,6 +102,7 @@ def test__get_default_mtls_endpoint(): [ (DeploymentsClient, "grpc"), (DeploymentsAsyncClient, "grpc_asyncio"), + (DeploymentsClient, "rest"), ], ) def test_deployments_client_from_service_account_info(client_class, transport_name): @@ -108,7 +116,11 @@ def test_deployments_client_from_service_account_info(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +128,7 @@ def test_deployments_client_from_service_account_info(client_class, transport_na [ (transports.DeploymentsGrpcTransport, "grpc"), (transports.DeploymentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.DeploymentsRestTransport, "rest"), ], ) def test_deployments_client_service_account_always_use_jwt( @@ -141,6 +154,7 @@ def test_deployments_client_service_account_always_use_jwt( [ (DeploymentsClient, "grpc"), (DeploymentsAsyncClient, "grpc_asyncio"), + (DeploymentsClient, "rest"), ], ) def test_deployments_client_from_service_account_file(client_class, transport_name): @@ -161,13 +175,18 @@ def test_deployments_client_from_service_account_file(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_deployments_client_get_transport_class(): transport = DeploymentsClient.get_transport_class() available_transports = [ transports.DeploymentsGrpcTransport, + transports.DeploymentsRestTransport, ] assert transport in available_transports @@ -184,6 +203,7 @@ def test_deployments_client_get_transport_class(): transports.DeploymentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +347,8 @@ def test_deployments_client_client_options( "grpc_asyncio", "false", ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest", "true"), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -520,6 +542,7 @@ def test_deployments_client_get_mtls_endpoint_and_cert_source(client_class): transports.DeploymentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest"), ], ) def test_deployments_client_client_options_scopes( @@ -555,6 +578,7 @@ def test_deployments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest", None), ], ) def test_deployments_client_client_options_credentials_file( @@ -1323,6 +1347,632 @@ async def test_get_deployment_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + deployment.ListDeploymentsRequest, + dict, + ], +) +def test_list_deployments_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/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 = deployment.ListDeploymentsResponse( + 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 = deployment.ListDeploymentsResponse.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_deployments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListDeploymentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_deployments_rest_required_fields( + request_type=deployment.ListDeploymentsRequest, +): + transport_class = transports.DeploymentsRestTransport + + 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_deployments._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_deployments._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", + ) + ) + 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 = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = deployment.ListDeploymentsResponse() + # 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 = deployment.ListDeploymentsResponse.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_deployments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_deployments_rest_unset_required_fields(): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_deployments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_deployments_rest_interceptors(null_interceptor): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.DeploymentsRestInterceptor(), + ) + client = DeploymentsClient(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.DeploymentsRestInterceptor, "post_list_deployments" + ) as post, mock.patch.object( + transports.DeploymentsRestInterceptor, "pre_list_deployments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = deployment.ListDeploymentsRequest.pb( + deployment.ListDeploymentsRequest() + ) + 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 = deployment.ListDeploymentsResponse.to_json( + deployment.ListDeploymentsResponse() + ) + + request = deployment.ListDeploymentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = deployment.ListDeploymentsResponse() + + client.list_deployments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_deployments_rest_bad_request( + transport: str = "rest", request_type=deployment.ListDeploymentsRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_deployments(request) + + +def test_list_deployments_rest_flattened(): + client = DeploymentsClient( + 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 = deployment.ListDeploymentsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = deployment.ListDeploymentsResponse.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_deployments(**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/v3/{parent=projects/*/locations/*/agents/*/environments/*}/deployments" + % client.transport._host, + args[1], + ) + + +def test_list_deployments_rest_flattened_error(transport: str = "rest"): + client = DeploymentsClient( + 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_deployments( + deployment.ListDeploymentsRequest(), + parent="parent_value", + ) + + +def test_list_deployments_rest_pager(transport: str = "rest"): + client = DeploymentsClient( + 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 = ( + deployment.ListDeploymentsResponse( + deployments=[ + deployment.Deployment(), + deployment.Deployment(), + deployment.Deployment(), + ], + next_page_token="abc", + ), + deployment.ListDeploymentsResponse( + deployments=[], + next_page_token="def", + ), + deployment.ListDeploymentsResponse( + deployments=[ + deployment.Deployment(), + ], + next_page_token="ghi", + ), + deployment.ListDeploymentsResponse( + deployments=[ + deployment.Deployment(), + deployment.Deployment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + deployment.ListDeploymentsResponse.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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + pager = client.list_deployments(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, deployment.Deployment) for i in results) + + pages = list(client.list_deployments(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", + [ + deployment.GetDeploymentRequest, + dict, + ], +) +def test_get_deployment_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/deployments/sample5" + } + 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 = deployment.Deployment( + name="name_value", + flow_version="flow_version_value", + state=deployment.Deployment.State.RUNNING, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = deployment.Deployment.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_deployment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, deployment.Deployment) + assert response.name == "name_value" + assert response.flow_version == "flow_version_value" + assert response.state == deployment.Deployment.State.RUNNING + + +def test_get_deployment_rest_required_fields( + request_type=deployment.GetDeploymentRequest, +): + transport_class = transports.DeploymentsRestTransport + + 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_deployment._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_deployment._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 = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = deployment.Deployment() + # 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 = deployment.Deployment.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_deployment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_deployment_rest_unset_required_fields(): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_deployment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_deployment_rest_interceptors(null_interceptor): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.DeploymentsRestInterceptor(), + ) + client = DeploymentsClient(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.DeploymentsRestInterceptor, "post_get_deployment" + ) as post, mock.patch.object( + transports.DeploymentsRestInterceptor, "pre_get_deployment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = deployment.GetDeploymentRequest.pb( + deployment.GetDeploymentRequest() + ) + 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 = deployment.Deployment.to_json( + deployment.Deployment() + ) + + request = deployment.GetDeploymentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = deployment.Deployment() + + client.get_deployment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_deployment_rest_bad_request( + transport: str = "rest", request_type=deployment.GetDeploymentRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/deployments/sample5" + } + 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_deployment(request) + + +def test_get_deployment_rest_flattened(): + client = DeploymentsClient( + 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 = deployment.Deployment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/deployments/sample5" + } + + # 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 = deployment.Deployment.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_deployment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*/deployments/*}" + % client.transport._host, + args[1], + ) + + +def test_get_deployment_rest_flattened_error(transport: str = "rest"): + client = DeploymentsClient( + 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_deployment( + deployment.GetDeploymentRequest(), + name="name_value", + ) + + +def test_get_deployment_rest_error(): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.DeploymentsGrpcTransport( @@ -1404,6 +2054,7 @@ def test_transport_get_channel(): [ transports.DeploymentsGrpcTransport, transports.DeploymentsGrpcAsyncIOTransport, + transports.DeploymentsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1418,6 +2069,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1562,6 +2214,7 @@ def test_deployments_transport_auth_adc(transport_class): [ transports.DeploymentsGrpcTransport, transports.DeploymentsGrpcAsyncIOTransport, + transports.DeploymentsRestTransport, ], ) def test_deployments_transport_auth_gdch_credentials(transport_class): @@ -1659,11 +2312,23 @@ def test_deployments_grpc_transport_client_cert_source_for_mtls(transport_class) ) +def test_deployments_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.DeploymentsRestTransport( + 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_deployments_host_no_port(transport_name): @@ -1674,7 +2339,11 @@ def test_deployments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1682,6 +2351,7 @@ def test_deployments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_deployments_host_with_port(transport_name): @@ -1692,7 +2362,36 @@ def test_deployments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_deployments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = DeploymentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = DeploymentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_deployments._session + session2 = client2.transport.list_deployments._session + assert session1 != session2 + session1 = client1.transport.get_deployment._session + session2 = client2.transport.get_deployment._session + assert session1 != session2 def test_deployments_grpc_transport_channel(): @@ -2087,6 +2786,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = DeploymentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2804,6 +3789,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2821,6 +3807,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py b/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py index 2ccb579c..292c5229 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_entity_types.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 @@ -96,6 +103,7 @@ def test__get_default_mtls_endpoint(): [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_info(client_class, transport_name): @@ -109,7 +117,11 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -117,6 +129,7 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n [ (transports.EntityTypesGrpcTransport, "grpc"), (transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_service_account_always_use_jwt( @@ -142,6 +155,7 @@ def test_entity_types_client_service_account_always_use_jwt( [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_file(client_class, transport_name): @@ -162,13 +176,18 @@ def test_entity_types_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_entity_types_client_get_transport_class(): transport = EntityTypesClient.get_transport_class() available_transports = [ transports.EntityTypesGrpcTransport, + transports.EntityTypesRestTransport, ] assert transport in available_transports @@ -185,6 +204,7 @@ def test_entity_types_client_get_transport_class(): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -328,6 +348,8 @@ def test_entity_types_client_client_options( "grpc_asyncio", "false", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "true"), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -521,6 +543,7 @@ def test_entity_types_client_get_mtls_endpoint_and_cert_source(client_class): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_client_options_scopes( @@ -556,6 +579,7 @@ def test_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", None), ], ) def test_entity_types_client_client_options_credentials_file( @@ -2164,211 +2188,1753 @@ async def test_delete_entity_type_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + entity_type.ListEntityTypesRequest, + dict, + ], +) +def test_list_entity_types_rest(request_type): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EntityTypesClient( - 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 = entity_type.ListEntityTypesResponse( + next_page_token="next_page_token_value", ) - # 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 = EntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_entity_types(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEntityTypesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_entity_types_rest_required_fields( + request_type=entity_type.ListEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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, + ) ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_entity_types._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_entity_types._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EntityTypesClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse() + # 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 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = entity_type.ListEntityTypesResponse.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_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.EntityTypesGrpcAsyncIOTransport( + unset_fields = transport.list_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_list_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_list_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.ListEntityTypesRequest.pb( + entity_type.ListEntityTypesRequest() + ) + 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 = entity_type.ListEntityTypesResponse.to_json( + entity_type.ListEntityTypesResponse() + ) + request = entity_type.ListEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.ListEntityTypesResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.EntityTypesGrpcTransport, - transports.EntityTypesGrpcAsyncIOTransport, - ], -) -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() + client.list_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = EntityTypesClient.get_transport_class(transport_name)( + +def test_list_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.ListEntityTypesRequest +): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # 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_entity_types(request) + + +def test_list_entity_types_rest_flattened(): client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.EntityTypesGrpcTransport, + 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 = entity_type.ListEntityTypesResponse() -def test_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = entity_type.ListEntityTypesResponse.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_entity_types_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.entity_types.transports.EntityTypesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.EntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_entity_types(**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/v3/{parent=projects/*/locations/*/agents/*}/entityTypes" + % client.transport._host, + args[1], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_entity_types", - "get_entity_type", - "create_entity_type", - "update_entity_type", - "delete_entity_type", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + +def test_list_entity_types_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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() + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_entity_types( + entity_type.ListEntityTypesRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_entity_types_rest_pager(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_entity_types_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.dialogflowcx_v3.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.EntityTypesTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", + # 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 = ( + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + entity_type.EntityType(), + ], + next_page_token="abc", + ), + entity_type.ListEntityTypesResponse( + entity_types=[], + next_page_token="def", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + ], + next_page_token="ghi", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple( + entity_type.ListEntityTypesResponse.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 -def test_entity_types_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.dialogflowcx_v3.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.EntityTypesTransport() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + pager = client.list_entity_types(request=sample_request) -def test_entity_types_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) - EntityTypesClient() - adc.assert_called_once_with( + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, entity_type.EntityType) for i in results) + + pages = list(client.list_entity_types(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", + [ + entity_type.GetEntityTypeRequest, + dict, + ], +) +def test_get_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/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 = entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + redact=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.EntityType.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_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + assert response.redact is True + + +def test_get_entity_type_rest_required_fields( + request_type=entity_type.GetEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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_entity_type._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_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType() + # 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 = entity_type.EntityType.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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_get_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_get_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.GetEntityTypeRequest.pb( + entity_type.GetEntityTypeRequest() + ) + 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 = entity_type.EntityType.to_json( + entity_type.EntityType() + ) + + request = entity_type.GetEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.EntityType() + + client.get_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.GetEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + 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_entity_type(request) + + +def test_get_entity_type_rest_flattened(): + client = EntityTypesClient( + 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 = entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + + # 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 = entity_type.EntityType.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_entity_type(**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/v3/{name=projects/*/locations/*/agents/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_get_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + entity_type.GetEntityTypeRequest(), + name="name_value", + ) + + +def test_get_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_entity_type.CreateEntityTypeRequest, + dict, + ], +) +def test_create_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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 = gcdc_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + redact=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_entity_type.EntityType.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_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcdc_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + assert response.redact is True + + +def test_create_entity_type_rest_required_fields( + request_type=gcdc_entity_type.CreateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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() + ).create_entity_type._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() + ).create_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_entity_type.EntityType() + # 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 = gcdc_entity_type.EntityType.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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "entityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_create_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_create_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_entity_type.CreateEntityTypeRequest.pb( + gcdc_entity_type.CreateEntityTypeRequest() + ) + 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 = gcdc_entity_type.EntityType.to_json( + gcdc_entity_type.EntityType() + ) + + request = gcdc_entity_type.CreateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_entity_type.EntityType() + + client.create_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcdc_entity_type.CreateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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_entity_type(request) + + +def test_create_entity_type_rest_flattened(): + client = EntityTypesClient( + 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 = gcdc_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_type=gcdc_entity_type.EntityType(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 = gcdc_entity_type.EntityType.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_entity_type(**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/v3/{parent=projects/*/locations/*/agents/*}/entityTypes" + % client.transport._host, + args[1], + ) + + +def test_create_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + gcdc_entity_type.CreateEntityTypeRequest(), + parent="parent_value", + entity_type=gcdc_entity_type.EntityType(name="name_value"), + ) + + +def test_create_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_entity_type.UpdateEntityTypeRequest, + dict, + ], +) +def test_update_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + } + request_init["entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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 = gcdc_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + redact=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_entity_type.EntityType.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_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcdc_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + assert response.redact is True + + +def test_update_entity_type_rest_required_fields( + request_type=gcdc_entity_type.UpdateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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_entity_type._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_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_entity_type.EntityType() + # 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 = gcdc_entity_type.EntityType.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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("entityType",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_update_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_update_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_entity_type.UpdateEntityTypeRequest.pb( + gcdc_entity_type.UpdateEntityTypeRequest() + ) + 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 = gcdc_entity_type.EntityType.to_json( + gcdc_entity_type.EntityType() + ) + + request = gcdc_entity_type.UpdateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_entity_type.EntityType() + + client.update_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcdc_entity_type.UpdateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + } + request_init["entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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_entity_type(request) + + +def test_update_entity_type_rest_flattened(): + client = EntityTypesClient( + 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 = gcdc_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + entity_type=gcdc_entity_type.EntityType(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 = gcdc_entity_type.EntityType.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_entity_type(**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/v3/{entity_type.name=projects/*/locations/*/agents/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + gcdc_entity_type.UpdateEntityTypeRequest(), + entity_type=gcdc_entity_type.EntityType(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.DeleteEntityTypeRequest, + dict, + ], +) +def test_delete_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/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 = 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_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_entity_type_rest_required_fields( + request_type=entity_type.DeleteEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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_entity_type._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_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = EntityTypesClient( + 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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "pre_delete_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = entity_type.DeleteEntityTypeRequest.pb( + entity_type.DeleteEntityTypeRequest() + ) + 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 = entity_type.DeleteEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.DeleteEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + 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_entity_type(request) + + +def test_delete_entity_type_rest_flattened(): + client = EntityTypesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + + # 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_entity_type(**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/v3/{name=projects/*/locations/*/agents/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + entity_type.DeleteEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EntityTypesClient( + 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 = EntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EntityTypesGrpcTransport, + transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, + ], +) +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 = EntityTypesClient.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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EntityTypesGrpcTransport, + ) + + +def test_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_entity_types_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.entity_types.transports.EntityTypesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.EntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_entity_types", + "get_entity_type", + "create_entity_type", + "update_entity_type", + "delete_entity_type", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_entity_types_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.dialogflowcx_v3.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.EntityTypesTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_entity_types_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.dialogflowcx_v3.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.EntityTypesTransport() + adc.assert_called_once() + + +def test_entity_types_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) + EntityTypesClient() + adc.assert_called_once_with( scopes=None, default_scopes=( "https://www.googleapis.com/auth/cloud-platform", @@ -2406,6 +3972,7 @@ def test_entity_types_transport_auth_adc(transport_class): [ transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, ], ) def test_entity_types_transport_auth_gdch_credentials(transport_class): @@ -2503,11 +4070,23 @@ def test_entity_types_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_entity_types_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.EntityTypesRestTransport( + 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_entity_types_host_no_port(transport_name): @@ -2518,7 +4097,11 @@ def test_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2526,6 +4109,7 @@ def test_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_entity_types_host_with_port(transport_name): @@ -2536,7 +4120,45 @@ def test_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_entity_types._session + session2 = client2.transport.list_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_entity_type._session + session2 = client2.transport.get_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_entity_type._session + session2 = client2.transport.create_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_entity_type._session + session2 = client2.transport.update_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_entity_type._session + session2 = client2.transport.delete_entity_type._session + assert session1 != session2 def test_entity_types_grpc_transport_channel(): @@ -2826,6 +4448,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3543,6 +5451,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3560,6 +5469,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_environments.py b/tests/unit/gapic/dialogflowcx_v3/test_environments.py index 040f0286..a185b741 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_environments.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_environments.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 @@ -104,6 +111,7 @@ def test__get_default_mtls_endpoint(): [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_info(client_class, transport_name): @@ -117,7 +125,11 @@ def test_environments_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -125,6 +137,7 @@ def test_environments_client_from_service_account_info(client_class, transport_n [ (transports.EnvironmentsGrpcTransport, "grpc"), (transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_service_account_always_use_jwt( @@ -150,6 +163,7 @@ def test_environments_client_service_account_always_use_jwt( [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_file(client_class, transport_name): @@ -170,13 +184,18 @@ def test_environments_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_environments_client_get_transport_class(): transport = EnvironmentsClient.get_transport_class() available_transports = [ transports.EnvironmentsGrpcTransport, + transports.EnvironmentsRestTransport, ] assert transport in available_transports @@ -193,6 +212,7 @@ def test_environments_client_get_transport_class(): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -336,6 +356,8 @@ def test_environments_client_client_options( "grpc_asyncio", "false", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "true"), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -529,6 +551,7 @@ def test_environments_client_get_mtls_endpoint_and_cert_source(client_class): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_client_options_scopes( @@ -569,6 +592,7 @@ def test_environments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", None), ], ) def test_environments_client_client_options_credentials_file( @@ -3284,141 +3308,2859 @@ async def test_deploy_flow_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EnvironmentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + environment.ListEnvironmentsRequest, + dict, + ], +) +def test_list_environments_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = environment.ListEnvironmentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.ListEnvironmentsResponse.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_environments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEnvironmentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_environments_rest_required_fields( + request_type=environment.ListEnvironmentsRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environments._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_environments._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", + ) + ) + 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 = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse() + # 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 = environment.ListEnvironmentsResponse.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_environments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_environments_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_environments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_environments_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options=options, - transport=transport, + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_list_environments" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_list_environments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.ListEnvironmentsRequest.pb( + environment.ListEnvironmentsRequest() + ) + 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 = environment.ListEnvironmentsResponse.to_json( + environment.ListEnvironmentsResponse() ) - # 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 = EnvironmentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = environment.ListEnvironmentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.ListEnvironmentsResponse() + + client.list_environments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_environments_rest_bad_request( + transport: str = "rest", request_type=environment.ListEnvironmentsRequest +): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # 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_environments(request) + + +def test_list_environments_rest_flattened(): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EnvironmentsClient(transport=transport) - assert client.transport is 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 = environment.ListEnvironmentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = environment.ListEnvironmentsResponse.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_environments(**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/v3/{parent=projects/*/locations/*/agents/*}/environments" + % client.transport._host, + args[1], + ) + + +def test_list_environments_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.EnvironmentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_environments( + environment.ListEnvironmentsRequest(), + parent="parent_value", + ) + + +def test_list_environments_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + environment.Environment(), + ], + next_page_token="abc", + ), + environment.ListEnvironmentsResponse( + environments=[], + next_page_token="def", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + ], + next_page_token="ghi", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.ListEnvironmentsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.EnvironmentsGrpcTransport, - transports.EnvironmentsGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_environments(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.Environment) for i in results) + + pages = list(client.list_environments(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + environment.GetEnvironmentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = EnvironmentsClient.get_transport_class(transport_name)( +def test_get_environment_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/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 = environment.Environment( + name="name_value", + display_name="display_name_value", + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.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_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + + +def test_get_environment_rest_required_fields( + request_type=environment.GetEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environment._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_environment._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" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.EnvironmentsGrpcTransport, + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # 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 = environment.Environment.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_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_environments_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_get_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_get_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.GetEnvironmentRequest.pb( + environment.GetEnvironmentRequest() + ) + 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 = environment.Environment.to_json( + environment.Environment() ) + request = environment.GetEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() -def test_environments_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.environments.transports.EnvironmentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.get_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly + pre.assert_called_once() + post.assert_called_once() + + +def test_get_environment_rest_bad_request( + transport: str = "rest", request_type=environment.GetEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_environment(request) + + +def test_get_environment_rest_flattened(): + client = EnvironmentsClient( + 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 = environment.Environment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = environment.Environment.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_environment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*}" + % client.transport._host, + args[1], + ) + + +def test_get_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + environment.GetEnvironmentRequest(), + name="name_value", + ) + + +def test_get_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_environment.CreateEnvironmentRequest, + dict, + ], +) +def test_create_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["environment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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.create_environment(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_environment_rest_required_fields( + request_type=gcdc_environment.CreateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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() + ).create_environment._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() + ).create_environment._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 = EnvironmentsClient( + 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.create_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "environment", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_create_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_create_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_environment.CreateEnvironmentRequest.pb( + gcdc_environment.CreateEnvironmentRequest() + ) + 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 = gcdc_environment.CreateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_environment_rest_bad_request( + transport: str = "rest", request_type=gcdc_environment.CreateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["environment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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_environment(request) + + +def test_create_environment_rest_flattened(): + client = EnvironmentsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + environment=gcdc_environment.Environment(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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_environment(**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/v3/{parent=projects/*/locations/*/agents/*}/environments" + % client.transport._host, + args[1], + ) + + +def test_create_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + gcdc_environment.CreateEnvironmentRequest(), + parent="parent_value", + environment=gcdc_environment.Environment(name="name_value"), + ) + + +def test_create_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_environment.UpdateEnvironmentRequest, + dict, + ], +) +def test_update_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + } + request_init["environment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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.update_environment(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_update_environment_rest_required_fields( + request_type=gcdc_environment.UpdateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environment._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_environment._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 = EnvironmentsClient( + 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": "patch", + "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.update_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "environment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_update_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_update_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_environment.UpdateEnvironmentRequest.pb( + gcdc_environment.UpdateEnvironmentRequest() + ) + 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 = gcdc_environment.UpdateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.update_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_environment_rest_bad_request( + transport: str = "rest", request_type=gcdc_environment.UpdateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + } + request_init["environment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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_environment(request) + + +def test_update_environment_rest_flattened(): + client = EnvironmentsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "environment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + environment=gcdc_environment.Environment(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 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_environment(**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/v3/{environment.name=projects/*/locations/*/agents/*/environments/*}" + % client.transport._host, + args[1], + ) + + +def test_update_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + gcdc_environment.UpdateEnvironmentRequest(), + environment=gcdc_environment.Environment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.DeleteEnvironmentRequest, + dict, + ], +) +def test_delete_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/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 = 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_environment(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_environment_rest_required_fields( + request_type=environment.DeleteEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environment._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_environment._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 = EnvironmentsClient( + 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_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "pre_delete_environment" + ) as pre: + pre.assert_not_called() + pb_message = environment.DeleteEnvironmentRequest.pb( + environment.DeleteEnvironmentRequest() + ) + 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 = environment.DeleteEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_environment_rest_bad_request( + transport: str = "rest", request_type=environment.DeleteEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_environment(request) + + +def test_delete_environment_rest_flattened(): + client = EnvironmentsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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_environment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + environment.DeleteEnvironmentRequest(), + name="name_value", + ) + + +def test_delete_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.LookupEnvironmentHistoryRequest, + dict, + ], +) +def test_lookup_environment_history_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/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 = environment.LookupEnvironmentHistoryResponse( + 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 = environment.LookupEnvironmentHistoryResponse.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.lookup_environment_history(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.LookupEnvironmentHistoryPager) + assert response.next_page_token == "next_page_token_value" + + +def test_lookup_environment_history_rest_required_fields( + request_type=environment.LookupEnvironmentHistoryRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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() + ).lookup_environment_history._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() + ).lookup_environment_history._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", + ) + ) + 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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.LookupEnvironmentHistoryResponse() + # 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 = environment.LookupEnvironmentHistoryResponse.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.lookup_environment_history(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_lookup_environment_history_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.lookup_environment_history._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("name",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_lookup_environment_history_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_lookup_environment_history" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_lookup_environment_history" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.LookupEnvironmentHistoryRequest.pb( + environment.LookupEnvironmentHistoryRequest() + ) + 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 = ( + environment.LookupEnvironmentHistoryResponse.to_json( + environment.LookupEnvironmentHistoryResponse() + ) + ) + + request = environment.LookupEnvironmentHistoryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.LookupEnvironmentHistoryResponse() + + client.lookup_environment_history( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_lookup_environment_history_rest_bad_request( + transport: str = "rest", request_type=environment.LookupEnvironmentHistoryRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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.lookup_environment_history(request) + + +def test_lookup_environment_history_rest_flattened(): + client = EnvironmentsClient( + 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 = environment.LookupEnvironmentHistoryResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = environment.LookupEnvironmentHistoryResponse.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.lookup_environment_history(**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/v3/{name=projects/*/locations/*/agents/*/environments/*}:lookupEnvironmentHistory" + % client.transport._host, + args[1], + ) + + +def test_lookup_environment_history_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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.lookup_environment_history( + environment.LookupEnvironmentHistoryRequest(), + name="name_value", + ) + + +def test_lookup_environment_history_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( + 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 = ( + environment.LookupEnvironmentHistoryResponse( + environments=[ + environment.Environment(), + environment.Environment(), + environment.Environment(), + ], + next_page_token="abc", + ), + environment.LookupEnvironmentHistoryResponse( + environments=[], + next_page_token="def", + ), + environment.LookupEnvironmentHistoryResponse( + environments=[ + environment.Environment(), + ], + next_page_token="ghi", + ), + environment.LookupEnvironmentHistoryResponse( + environments=[ + environment.Environment(), + environment.Environment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.LookupEnvironmentHistoryResponse.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 = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + pager = client.lookup_environment_history(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.Environment) for i in results) + + pages = list(client.lookup_environment_history(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", + [ + environment.RunContinuousTestRequest, + dict, + ], +) +def test_run_continuous_test_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/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(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.run_continuous_test(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_run_continuous_test_rest_required_fields( + request_type=environment.RunContinuousTestRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["environment"] = "" + 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() + ).run_continuous_test._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["environment"] = "environment_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).run_continuous_test._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "environment" in jsonified_request + assert jsonified_request["environment"] == "environment_value" + + client = EnvironmentsClient( + 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.run_continuous_test(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_run_continuous_test_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.run_continuous_test._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("environment",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_run_continuous_test_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_run_continuous_test" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_run_continuous_test" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.RunContinuousTestRequest.pb( + environment.RunContinuousTestRequest() + ) + 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 = environment.RunContinuousTestRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.run_continuous_test( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_run_continuous_test_rest_bad_request( + transport: str = "rest", request_type=environment.RunContinuousTestRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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.run_continuous_test(request) + + +def test_run_continuous_test_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.ListContinuousTestResultsRequest, + dict, + ], +) +def test_list_continuous_test_results_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/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 = environment.ListContinuousTestResultsResponse( + 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 = environment.ListContinuousTestResultsResponse.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_continuous_test_results(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListContinuousTestResultsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_continuous_test_results_rest_required_fields( + request_type=environment.ListContinuousTestResultsRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_continuous_test_results._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_continuous_test_results._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", + ) + ) + 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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.ListContinuousTestResultsResponse() + # 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 = environment.ListContinuousTestResultsResponse.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_continuous_test_results(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_continuous_test_results_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_continuous_test_results._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_continuous_test_results_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_list_continuous_test_results" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_list_continuous_test_results" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.ListContinuousTestResultsRequest.pb( + environment.ListContinuousTestResultsRequest() + ) + 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 = ( + environment.ListContinuousTestResultsResponse.to_json( + environment.ListContinuousTestResultsResponse() + ) + ) + + request = environment.ListContinuousTestResultsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.ListContinuousTestResultsResponse() + + client.list_continuous_test_results( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_continuous_test_results_rest_bad_request( + transport: str = "rest", request_type=environment.ListContinuousTestResultsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_continuous_test_results(request) + + +def test_list_continuous_test_results_rest_flattened(): + client = EnvironmentsClient( + 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 = environment.ListContinuousTestResultsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = environment.ListContinuousTestResultsResponse.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_continuous_test_results(**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/v3/{parent=projects/*/locations/*/agents/*/environments/*}/continuousTestResults" + % client.transport._host, + args[1], + ) + + +def test_list_continuous_test_results_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_continuous_test_results( + environment.ListContinuousTestResultsRequest(), + parent="parent_value", + ) + + +def test_list_continuous_test_results_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( + 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 = ( + environment.ListContinuousTestResultsResponse( + continuous_test_results=[ + environment.ContinuousTestResult(), + environment.ContinuousTestResult(), + environment.ContinuousTestResult(), + ], + next_page_token="abc", + ), + environment.ListContinuousTestResultsResponse( + continuous_test_results=[], + next_page_token="def", + ), + environment.ListContinuousTestResultsResponse( + continuous_test_results=[ + environment.ContinuousTestResult(), + ], + next_page_token="ghi", + ), + environment.ListContinuousTestResultsResponse( + continuous_test_results=[ + environment.ContinuousTestResult(), + environment.ContinuousTestResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.ListContinuousTestResultsResponse.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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + pager = client.list_continuous_test_results(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.ContinuousTestResult) for i in results) + + pages = list(client.list_continuous_test_results(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", + [ + environment.DeployFlowRequest, + dict, + ], +) +def test_deploy_flow_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/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(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.deploy_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_deploy_flow_rest_required_fields(request_type=environment.DeployFlowRequest): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["environment"] = "" + request_init["flow_version"] = "" + 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() + ).deploy_flow._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["environment"] = "environment_value" + jsonified_request["flowVersion"] = "flow_version_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).deploy_flow._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "environment" in jsonified_request + assert jsonified_request["environment"] == "environment_value" + assert "flowVersion" in jsonified_request + assert jsonified_request["flowVersion"] == "flow_version_value" + + client = EnvironmentsClient( + 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.deploy_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_deploy_flow_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.deploy_flow._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "environment", + "flowVersion", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_deploy_flow_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_deploy_flow" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_deploy_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.DeployFlowRequest.pb(environment.DeployFlowRequest()) + 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 = environment.DeployFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.deploy_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_deploy_flow_rest_bad_request( + transport: str = "rest", request_type=environment.DeployFlowRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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.deploy_flow(request) + + +def test_deploy_flow_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EnvironmentsClient( + 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 = EnvironmentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EnvironmentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EnvironmentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EnvironmentsGrpcTransport, + transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, + ], +) +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 = EnvironmentsClient.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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EnvironmentsGrpcTransport, + ) + + +def test_environments_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_environments_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.environments.transports.EnvironmentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly # raise NotImplementedError. methods = ( "list_environments", @@ -3535,6 +6277,7 @@ def test_environments_transport_auth_adc(transport_class): [ transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, ], ) def test_environments_transport_auth_gdch_credentials(transport_class): @@ -3632,11 +6375,40 @@ def test_environments_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_environments_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.EnvironmentsRestTransport( + 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_environments_rest_lro_client(): + client = EnvironmentsClient( + 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_environments_host_no_port(transport_name): @@ -3647,7 +6419,11 @@ def test_environments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3655,6 +6431,7 @@ def test_environments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_environments_host_with_port(transport_name): @@ -3665,7 +6442,57 @@ def test_environments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_environments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EnvironmentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EnvironmentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_environments._session + session2 = client2.transport.list_environments._session + assert session1 != session2 + session1 = client1.transport.get_environment._session + session2 = client2.transport.get_environment._session + assert session1 != session2 + session1 = client1.transport.create_environment._session + session2 = client2.transport.create_environment._session + assert session1 != session2 + session1 = client1.transport.update_environment._session + session2 = client2.transport.update_environment._session + assert session1 != session2 + session1 = client1.transport.delete_environment._session + session2 = client2.transport.delete_environment._session + assert session1 != session2 + session1 = client1.transport.lookup_environment_history._session + session2 = client2.transport.lookup_environment_history._session + assert session1 != session2 + session1 = client1.transport.run_continuous_test._session + session2 = client2.transport.run_continuous_test._session + assert session1 != session2 + session1 = client1.transport.list_continuous_test_results._session + session2 = client2.transport.list_continuous_test_results._session + assert session1 != session2 + session1 = client1.transport.deploy_flow._session + session2 = client2.transport.deploy_flow._session + assert session1 != session2 def test_environments_grpc_transport_channel(): @@ -4176,6 +7003,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4893,6 +8006,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4910,6 +8024,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_experiments.py b/tests/unit/gapic/dialogflowcx_v3/test_experiments.py index a8d2cbf5..c31364ae 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_experiments.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_experiments.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 @@ -98,6 +105,7 @@ def test__get_default_mtls_endpoint(): [ (ExperimentsClient, "grpc"), (ExperimentsAsyncClient, "grpc_asyncio"), + (ExperimentsClient, "rest"), ], ) def test_experiments_client_from_service_account_info(client_class, transport_name): @@ -111,7 +119,11 @@ def test_experiments_client_from_service_account_info(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -119,6 +131,7 @@ def test_experiments_client_from_service_account_info(client_class, transport_na [ (transports.ExperimentsGrpcTransport, "grpc"), (transports.ExperimentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ExperimentsRestTransport, "rest"), ], ) def test_experiments_client_service_account_always_use_jwt( @@ -144,6 +157,7 @@ def test_experiments_client_service_account_always_use_jwt( [ (ExperimentsClient, "grpc"), (ExperimentsAsyncClient, "grpc_asyncio"), + (ExperimentsClient, "rest"), ], ) def test_experiments_client_from_service_account_file(client_class, transport_name): @@ -164,13 +178,18 @@ def test_experiments_client_from_service_account_file(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_experiments_client_get_transport_class(): transport = ExperimentsClient.get_transport_class() available_transports = [ transports.ExperimentsGrpcTransport, + transports.ExperimentsRestTransport, ] assert transport in available_transports @@ -187,6 +206,7 @@ def test_experiments_client_get_transport_class(): transports.ExperimentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -330,6 +350,8 @@ def test_experiments_client_client_options( "grpc_asyncio", "false", ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest", "true"), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -523,6 +545,7 @@ def test_experiments_client_get_mtls_endpoint_and_cert_source(client_class): transports.ExperimentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest"), ], ) def test_experiments_client_client_options_scopes( @@ -558,6 +581,7 @@ def test_experiments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest", None), ], ) def test_experiments_client_client_options_credentials_file( @@ -2610,209 +2634,2511 @@ async def test_stop_experiment_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ExperimentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + experiment.ListExperimentsRequest, + dict, + ], +) +def test_list_experiments_rest(request_type): + client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ExperimentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ExperimentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ExperimentsClient( - 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 = experiment.ListExperimentsResponse( + next_page_token="next_page_token_value", ) - # 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 = ExperimentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.ListExperimentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_experiments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListExperimentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_experiments_rest_required_fields( + request_type=experiment.ListExperimentsRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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, + ) ) - with pytest.raises(ValueError): - client = ExperimentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_experiments._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_experiments._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", ) + ) + 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_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ExperimentsGrpcTransport( + client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = ExperimentsClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.ListExperimentsResponse() + # 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 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = experiment.ListExperimentsResponse.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_experiments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_experiments_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.ExperimentsGrpcAsyncIOTransport( + unset_fields = transport.list_experiments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_experiments_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_list_experiments" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_list_experiments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.ListExperimentsRequest.pb( + experiment.ListExperimentsRequest() + ) + 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 = experiment.ListExperimentsResponse.to_json( + experiment.ListExperimentsResponse() + ) + request = experiment.ListExperimentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.ListExperimentsResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.ExperimentsGrpcTransport, - transports.ExperimentsGrpcAsyncIOTransport, - ], -) -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() + client.list_experiments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = ExperimentsClient.get_transport_class(transport_name)( + +def test_list_experiments_rest_bad_request( + transport: str = "rest", request_type=experiment.ListExperimentsRequest +): + client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # 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_experiments(request) + + +def test_list_experiments_rest_flattened(): client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ExperimentsGrpcTransport, + 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 = experiment.ListExperimentsResponse() -def test_experiments_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ExperimentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = experiment.ListExperimentsResponse.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_experiments_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.experiments.transports.ExperimentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ExperimentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_experiments(**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/v3/{parent=projects/*/locations/*/agents/*/environments/*}/experiments" + % client.transport._host, + args[1], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_experiments", - "get_experiment", - "create_experiment", - "update_experiment", - "delete_experiment", - "start_experiment", - "stop_experiment", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + +def test_list_experiments_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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() + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_experiments( + experiment.ListExperimentsRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_experiments_rest_pager(transport: str = "rest"): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_experiments_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.dialogflowcx_v3.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.ExperimentsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", + # 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 = ( + experiment.ListExperimentsResponse( + experiments=[ + experiment.Experiment(), + experiment.Experiment(), + experiment.Experiment(), + ], + next_page_token="abc", + ), + experiment.ListExperimentsResponse( + experiments=[], + next_page_token="def", + ), + experiment.ListExperimentsResponse( + experiments=[ + experiment.Experiment(), + ], + next_page_token="ghi", + ), + experiment.ListExperimentsResponse( + experiments=[ + experiment.Experiment(), + experiment.Experiment(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple( + experiment.ListExperimentsResponse.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 -def test_experiments_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.dialogflowcx_v3.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.ExperimentsTransport() - adc.assert_called_once() + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + pager = client.list_experiments(request=sample_request) -def test_experiments_auth_adc(): - # If no credentials are provided, we should use ADC credentials. + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, experiment.Experiment) for i in results) + + pages = list(client.list_experiments(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", + [ + experiment.GetExperimentRequest, + dict, + ], +) +def test_get_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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 = experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.Experiment.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_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_get_experiment_rest_required_fields( + request_type=experiment.GetExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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_experiment._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_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.Experiment() + # 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 = experiment.Experiment.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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_get_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_get_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.GetExperimentRequest.pb( + experiment.GetExperimentRequest() + ) + 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 = experiment.Experiment.to_json( + experiment.Experiment() + ) + + request = experiment.GetExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.Experiment() + + client.get_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.GetExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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_experiment(request) + + +def test_get_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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 = experiment.Experiment.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_experiment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}" + % client.transport._host, + args[1], + ) + + +def test_get_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + experiment.GetExperimentRequest(), + name="name_value", + ) + + +def test_get_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_experiment.CreateExperimentRequest, + dict, + ], +) +def test_create_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request_init["experiment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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 = gcdc_experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=gcdc_experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_experiment.Experiment.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_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == gcdc_experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_create_experiment_rest_required_fields( + request_type=gcdc_experiment.CreateExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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() + ).create_experiment._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() + ).create_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_experiment.Experiment() + # 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 = gcdc_experiment.Experiment.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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_experiment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "experiment", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_create_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_create_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_experiment.CreateExperimentRequest.pb( + gcdc_experiment.CreateExperimentRequest() + ) + 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 = gcdc_experiment.Experiment.to_json( + gcdc_experiment.Experiment() + ) + + request = gcdc_experiment.CreateExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_experiment.Experiment() + + client.create_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_experiment_rest_bad_request( + transport: str = "rest", request_type=gcdc_experiment.CreateExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request_init["experiment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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_experiment(request) + + +def test_create_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = gcdc_experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + experiment=gcdc_experiment.Experiment(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 = gcdc_experiment.Experiment.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_experiment(**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/v3/{parent=projects/*/locations/*/agents/*/environments/*}/experiments" + % client.transport._host, + args[1], + ) + + +def test_create_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + gcdc_experiment.CreateExperimentRequest(), + parent="parent_value", + experiment=gcdc_experiment.Experiment(name="name_value"), + ) + + +def test_create_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_experiment.UpdateExperimentRequest, + dict, + ], +) +def test_update_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "experiment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + } + request_init["experiment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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 = gcdc_experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=gcdc_experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_experiment.Experiment.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_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == gcdc_experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_update_experiment_rest_required_fields( + request_type=gcdc_experiment.UpdateExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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_experiment._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_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_experiment.Experiment() + # 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 = gcdc_experiment.Experiment.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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_experiment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "experiment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_update_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_update_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_experiment.UpdateExperimentRequest.pb( + gcdc_experiment.UpdateExperimentRequest() + ) + 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 = gcdc_experiment.Experiment.to_json( + gcdc_experiment.Experiment() + ) + + request = gcdc_experiment.UpdateExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_experiment.Experiment() + + client.update_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_experiment_rest_bad_request( + transport: str = "rest", request_type=gcdc_experiment.UpdateExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "experiment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + } + request_init["experiment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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_experiment(request) + + +def test_update_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = gcdc_experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "experiment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + experiment=gcdc_experiment.Experiment(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 = gcdc_experiment.Experiment.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_experiment(**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/v3/{experiment.name=projects/*/locations/*/agents/*/environments/*/experiments/*}" + % client.transport._host, + args[1], + ) + + +def test_update_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + gcdc_experiment.UpdateExperimentRequest(), + experiment=gcdc_experiment.Experiment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + experiment.DeleteExperimentRequest, + dict, + ], +) +def test_delete_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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_experiment(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_experiment_rest_required_fields( + request_type=experiment.DeleteExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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_experiment._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_experiment._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 = ExperimentsClient( + 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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "pre_delete_experiment" + ) as pre: + pre.assert_not_called() + pb_message = experiment.DeleteExperimentRequest.pb( + experiment.DeleteExperimentRequest() + ) + 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 = experiment.DeleteExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.DeleteExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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_experiment(request) + + +def test_delete_experiment_rest_flattened(): + client = ExperimentsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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_experiment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + experiment.DeleteExperimentRequest(), + name="name_value", + ) + + +def test_delete_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + experiment.StartExperimentRequest, + dict, + ], +) +def test_start_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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 = experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.Experiment.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.start_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_start_experiment_rest_required_fields( + request_type=experiment.StartExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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() + ).start_experiment._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() + ).start_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.Experiment() + # 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 = experiment.Experiment.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.start_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_start_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.start_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_start_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_start_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_start_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.StartExperimentRequest.pb( + experiment.StartExperimentRequest() + ) + 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 = experiment.Experiment.to_json( + experiment.Experiment() + ) + + request = experiment.StartExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.Experiment() + + client.start_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_start_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.StartExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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.start_experiment(request) + + +def test_start_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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 = experiment.Experiment.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.start_experiment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:start" + % client.transport._host, + args[1], + ) + + +def test_start_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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.start_experiment( + experiment.StartExperimentRequest(), + name="name_value", + ) + + +def test_start_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + experiment.StopExperimentRequest, + dict, + ], +) +def test_stop_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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 = experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.Experiment.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.stop_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_stop_experiment_rest_required_fields( + request_type=experiment.StopExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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() + ).stop_experiment._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() + ).stop_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.Experiment() + # 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 = experiment.Experiment.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.stop_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_stop_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.stop_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_stop_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_stop_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_stop_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.StopExperimentRequest.pb( + experiment.StopExperimentRequest() + ) + 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 = experiment.Experiment.to_json( + experiment.Experiment() + ) + + request = experiment.StopExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.Experiment() + + client.stop_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_stop_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.StopExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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.stop_experiment(request) + + +def test_stop_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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 = experiment.Experiment.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.stop_experiment(**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/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:stop" + % client.transport._host, + args[1], + ) + + +def test_stop_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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.stop_experiment( + experiment.StopExperimentRequest(), + name="name_value", + ) + + +def test_stop_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExperimentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ExperimentsClient( + 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 = ExperimentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExperimentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ExperimentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ExperimentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ExperimentsGrpcTransport, + transports.ExperimentsGrpcAsyncIOTransport, + transports.ExperimentsRestTransport, + ], +) +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 = ExperimentsClient.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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ExperimentsGrpcTransport, + ) + + +def test_experiments_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ExperimentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_experiments_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.experiments.transports.ExperimentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ExperimentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_experiments", + "get_experiment", + "create_experiment", + "update_experiment", + "delete_experiment", + "start_experiment", + "stop_experiment", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_experiments_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.dialogflowcx_v3.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ExperimentsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_experiments_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.dialogflowcx_v3.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ExperimentsTransport() + adc.assert_called_once() + + +def test_experiments_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) ExperimentsClient() @@ -2854,6 +5180,7 @@ def test_experiments_transport_auth_adc(transport_class): [ transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport, + transports.ExperimentsRestTransport, ], ) def test_experiments_transport_auth_gdch_credentials(transport_class): @@ -2951,11 +5278,23 @@ def test_experiments_grpc_transport_client_cert_source_for_mtls(transport_class) ) +def test_experiments_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.ExperimentsRestTransport( + 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_experiments_host_no_port(transport_name): @@ -2966,7 +5305,11 @@ def test_experiments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2974,6 +5317,7 @@ def test_experiments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_experiments_host_with_port(transport_name): @@ -2984,7 +5328,51 @@ def test_experiments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_experiments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ExperimentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ExperimentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_experiments._session + session2 = client2.transport.list_experiments._session + assert session1 != session2 + session1 = client1.transport.get_experiment._session + session2 = client2.transport.get_experiment._session + assert session1 != session2 + session1 = client1.transport.create_experiment._session + session2 = client2.transport.create_experiment._session + assert session1 != session2 + session1 = client1.transport.update_experiment._session + session2 = client2.transport.update_experiment._session + assert session1 != session2 + session1 = client1.transport.delete_experiment._session + session2 = client2.transport.delete_experiment._session + assert session1 != session2 + session1 = client1.transport.start_experiment._session + session2 = client2.transport.start_experiment._session + assert session1 != session2 + session1 = client1.transport.stop_experiment._session + session2 = client2.transport.stop_experiment._session + assert session1 != session2 def test_experiments_grpc_transport_channel(): @@ -3311,6 +5699,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4028,6 +6702,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4045,6 +6720,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_flows.py b/tests/unit/gapic/dialogflowcx_v3/test_flows.py index b9d7753b..3d8ae30b 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_flows.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_flows.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 @@ -104,6 +111,7 @@ def test__get_default_mtls_endpoint(): [ (FlowsClient, "grpc"), (FlowsAsyncClient, "grpc_asyncio"), + (FlowsClient, "rest"), ], ) def test_flows_client_from_service_account_info(client_class, transport_name): @@ -117,7 +125,11 @@ def test_flows_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -125,6 +137,7 @@ def test_flows_client_from_service_account_info(client_class, transport_name): [ (transports.FlowsGrpcTransport, "grpc"), (transports.FlowsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.FlowsRestTransport, "rest"), ], ) def test_flows_client_service_account_always_use_jwt(transport_class, transport_name): @@ -148,6 +161,7 @@ def test_flows_client_service_account_always_use_jwt(transport_class, transport_ [ (FlowsClient, "grpc"), (FlowsAsyncClient, "grpc_asyncio"), + (FlowsClient, "rest"), ], ) def test_flows_client_from_service_account_file(client_class, transport_name): @@ -168,13 +182,18 @@ def test_flows_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_flows_client_get_transport_class(): transport = FlowsClient.get_transport_class() available_transports = [ transports.FlowsGrpcTransport, + transports.FlowsRestTransport, ] assert transport in available_transports @@ -187,6 +206,7 @@ def test_flows_client_get_transport_class(): [ (FlowsClient, transports.FlowsGrpcTransport, "grpc"), (FlowsAsyncClient, transports.FlowsGrpcAsyncIOTransport, "grpc_asyncio"), + (FlowsClient, transports.FlowsRestTransport, "rest"), ], ) @mock.patch.object( @@ -326,6 +346,8 @@ def test_flows_client_client_options(client_class, transport_class, transport_na "grpc_asyncio", "false", ), + (FlowsClient, transports.FlowsRestTransport, "rest", "true"), + (FlowsClient, transports.FlowsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -511,6 +533,7 @@ def test_flows_client_get_mtls_endpoint_and_cert_source(client_class): [ (FlowsClient, transports.FlowsGrpcTransport, "grpc"), (FlowsAsyncClient, transports.FlowsGrpcAsyncIOTransport, "grpc_asyncio"), + (FlowsClient, transports.FlowsRestTransport, "rest"), ], ) def test_flows_client_client_options_scopes( @@ -546,6 +569,7 @@ def test_flows_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (FlowsClient, transports.FlowsRestTransport, "rest", None), ], ) def test_flows_client_client_options_credentials_file( @@ -2944,209 +2968,3187 @@ async def test_export_flow_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.FlowsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcdc_flow.CreateFlowRequest, + dict, + ], +) +def test_create_flow_rest(request_type): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = FlowsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["flow"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + 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 = gcdc_flow.Flow( + name="name_value", + display_name="display_name_value", + description="description_value", + transition_route_groups=["transition_route_groups_value"], ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.FlowsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = FlowsClient( - 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 = gcdc_flow.Flow.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_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_flow.Flow) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_create_flow_rest_required_fields(request_type=gcdc_flow.CreateFlowRequest): + transport_class = transports.FlowsRestTransport + + 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 an api_key and a transport instance. - transport = transports.FlowsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_flow._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() + ).create_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_flow.Flow() + # 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 = gcdc_flow.Flow.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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = FlowsClient( - 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 = FlowsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_flow._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "flow", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.FlowsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), ) - with pytest.raises(ValueError): - client = FlowsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = FlowsClient(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.FlowsRestInterceptor, "post_create_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_create_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_flow.CreateFlowRequest.pb(gcdc_flow.CreateFlowRequest()) + 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 = gcdc_flow.Flow.to_json(gcdc_flow.Flow()) + + request = gcdc_flow.CreateFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_flow.Flow() + + client.create_flow( + 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.FlowsGrpcTransport( + +def test_create_flow_rest_bad_request( + transport: str = "rest", request_type=gcdc_flow.CreateFlowRequest +): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = FlowsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["flow"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.FlowsGrpcTransport( + # 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_flow(request) + + +def test_create_flow_rest_flattened(): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.FlowsGrpcAsyncIOTransport( + # 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 = gcdc_flow.Flow() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + flow=gcdc_flow.Flow(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 = gcdc_flow.Flow.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_flow(**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/v3/{parent=projects/*/locations/*/agents/*}/flows" + % client.transport._host, + args[1], + ) + + +def test_create_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( 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_flow( + gcdc_flow.CreateFlowRequest(), + parent="parent_value", + flow=gcdc_flow.Flow(name="name_value"), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.FlowsGrpcTransport, - transports.FlowsGrpcAsyncIOTransport, - ], -) -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_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + flow.DeleteFlowRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = FlowsClient.get_transport_class(transport_name)( +def test_delete_flow_rest(request_type): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = FlowsClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.FlowsGrpcTransport, - ) + # 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 = "" -def test_flows_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.FlowsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_flow(request) + # Establish that the response is the type that we expect. + assert response is None -def test_flows_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.flows.transports.FlowsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.FlowsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_flow", - "delete_flow", - "list_flows", - "get_flow", - "update_flow", - "train_flow", - "validate_flow", - "get_flow_validation_result", - "import_flow", - "export_flow", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", +def test_delete_flow_rest_required_fields(request_type=flow.DeleteFlowRequest): + transport_class = transports.FlowsRestTransport + + 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, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_flow._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # verify required fields with default values are now present + jsonified_request["name"] = "name_value" -def test_flows_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.dialogflowcx_v3.services.flows.transports.FlowsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.FlowsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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" -def test_flows_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.dialogflowcx_v3.services.flows.transports.FlowsTransport._prep_wrapped_messages" - ) as Transport: + client = FlowsClient( + 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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "pre_delete_flow" + ) as pre: + pre.assert_not_called() + pb_message = flow.DeleteFlowRequest.pb(flow.DeleteFlowRequest()) + 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 = flow.DeleteFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_flow_rest_bad_request( + transport: str = "rest", request_type=flow.DeleteFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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_flow(request) + + +def test_delete_flow_rest_flattened(): + client = FlowsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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_flow(**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/v3/{name=projects/*/locations/*/agents/*/flows/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow( + flow.DeleteFlowRequest(), + name="name_value", + ) + + +def test_delete_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ListFlowsRequest, + dict, + ], +) +def test_list_flows_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = flow.ListFlowsResponse( + 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 = flow.ListFlowsResponse.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_flows(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListFlowsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_flows_rest_required_fields(request_type=flow.ListFlowsRequest): + transport_class = transports.FlowsRestTransport + + 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_flows._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_flows._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.ListFlowsResponse() + # 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 = flow.ListFlowsResponse.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_flows(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_flows_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_flows._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_flows_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_list_flows" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_list_flows" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ListFlowsRequest.pb(flow.ListFlowsRequest()) + 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 = flow.ListFlowsResponse.to_json( + flow.ListFlowsResponse() + ) + + request = flow.ListFlowsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.ListFlowsResponse() + + client.list_flows( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_flows_rest_bad_request( + transport: str = "rest", request_type=flow.ListFlowsRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.list_flows(request) + + +def test_list_flows_rest_flattened(): + client = FlowsClient( + 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 = flow.ListFlowsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = flow.ListFlowsResponse.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_flows(**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/v3/{parent=projects/*/locations/*/agents/*}/flows" + % client.transport._host, + args[1], + ) + + +def test_list_flows_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flows( + flow.ListFlowsRequest(), + parent="parent_value", + ) + + +def test_list_flows_rest_pager(transport: str = "rest"): + client = FlowsClient( + 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 = ( + flow.ListFlowsResponse( + flows=[ + flow.Flow(), + flow.Flow(), + flow.Flow(), + ], + next_page_token="abc", + ), + flow.ListFlowsResponse( + flows=[], + next_page_token="def", + ), + flow.ListFlowsResponse( + flows=[ + flow.Flow(), + ], + next_page_token="ghi", + ), + flow.ListFlowsResponse( + flows=[ + flow.Flow(), + flow.Flow(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(flow.ListFlowsResponse.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": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_flows(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, flow.Flow) for i in results) + + pages = list(client.list_flows(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", + [ + flow.GetFlowRequest, + dict, + ], +) +def test_get_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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 = flow.Flow( + name="name_value", + display_name="display_name_value", + description="description_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = flow.Flow.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_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.Flow) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_get_flow_rest_required_fields(request_type=flow.GetFlowRequest): + transport_class = transports.FlowsRestTransport + + 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_flow._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_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.Flow() + # 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 = flow.Flow.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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_get_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_get_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.GetFlowRequest.pb(flow.GetFlowRequest()) + 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 = flow.Flow.to_json(flow.Flow()) + + request = flow.GetFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.Flow() + + client.get_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_flow_rest_bad_request( + transport: str = "rest", request_type=flow.GetFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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_flow(request) + + +def test_get_flow_rest_flattened(): + client = FlowsClient( + 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 = flow.Flow() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = flow.Flow.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_flow(**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/v3/{name=projects/*/locations/*/agents/*/flows/*}" + % client.transport._host, + args[1], + ) + + +def test_get_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow( + flow.GetFlowRequest(), + name="name_value", + ) + + +def test_get_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_flow.UpdateFlowRequest, + dict, + ], +) +def test_update_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "flow": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + } + request_init["flow"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + 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 = gcdc_flow.Flow( + name="name_value", + display_name="display_name_value", + description="description_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_flow.Flow.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_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_flow.Flow) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_update_flow_rest_required_fields(request_type=gcdc_flow.UpdateFlowRequest): + transport_class = transports.FlowsRestTransport + + 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_flow._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_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_flow.Flow() + # 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 = gcdc_flow.Flow.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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_flow._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("flow",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_update_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_update_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_flow.UpdateFlowRequest.pb(gcdc_flow.UpdateFlowRequest()) + 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 = gcdc_flow.Flow.to_json(gcdc_flow.Flow()) + + request = gcdc_flow.UpdateFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_flow.Flow() + + client.update_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_flow_rest_bad_request( + transport: str = "rest", request_type=gcdc_flow.UpdateFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "flow": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + } + request_init["flow"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + 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_flow(request) + + +def test_update_flow_rest_flattened(): + client = FlowsClient( + 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 = gcdc_flow.Flow() + + # get arguments that satisfy an http rule for this method + sample_request = { + "flow": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + flow=gcdc_flow.Flow(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 = gcdc_flow.Flow.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_flow(**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/v3/{flow.name=projects/*/locations/*/agents/*/flows/*}" + % client.transport._host, + args[1], + ) + + +def test_update_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow( + gcdc_flow.UpdateFlowRequest(), + flow=gcdc_flow.Flow(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.TrainFlowRequest, + dict, + ], +) +def test_train_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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(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.train_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_train_flow_rest_required_fields(request_type=flow.TrainFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).train_flow._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() + ).train_flow._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 = FlowsClient( + 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.train_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_train_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.train_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_train_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_train_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_train_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.TrainFlowRequest.pb(flow.TrainFlowRequest()) + 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 = flow.TrainFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.train_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_train_flow_rest_bad_request( + transport: str = "rest", request_type=flow.TrainFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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.train_flow(request) + + +def test_train_flow_rest_flattened(): + client = FlowsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.train_flow(**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/v3/{name=projects/*/locations/*/agents/*/flows/*}:train" + % client.transport._host, + args[1], + ) + + +def test_train_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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.train_flow( + flow.TrainFlowRequest(), + name="name_value", + ) + + +def test_train_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ValidateFlowRequest, + dict, + ], +) +def test_validate_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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 = flow.FlowValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = flow.FlowValidationResult.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.validate_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + assert response.name == "name_value" + + +def test_validate_flow_rest_required_fields(request_type=flow.ValidateFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).validate_flow._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() + ).validate_flow._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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.FlowValidationResult() + # 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 = flow.FlowValidationResult.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.validate_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_validate_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.validate_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_validate_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_validate_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_validate_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ValidateFlowRequest.pb(flow.ValidateFlowRequest()) + 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 = flow.FlowValidationResult.to_json( + flow.FlowValidationResult() + ) + + request = flow.ValidateFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.FlowValidationResult() + + client.validate_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_validate_flow_rest_bad_request( + transport: str = "rest", request_type=flow.ValidateFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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.validate_flow(request) + + +def test_validate_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.GetFlowValidationResultRequest, + dict, + ], +) +def test_get_flow_validation_result_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/validationResult" + } + 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 = flow.FlowValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = flow.FlowValidationResult.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_flow_validation_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + assert response.name == "name_value" + + +def test_get_flow_validation_result_rest_required_fields( + request_type=flow.GetFlowValidationResultRequest, +): + transport_class = transports.FlowsRestTransport + + 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_flow_validation_result._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_flow_validation_result._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.FlowValidationResult() + # 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 = flow.FlowValidationResult.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_flow_validation_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_flow_validation_result_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_flow_validation_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_flow_validation_result_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_get_flow_validation_result" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_get_flow_validation_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.GetFlowValidationResultRequest.pb( + flow.GetFlowValidationResultRequest() + ) + 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 = flow.FlowValidationResult.to_json( + flow.FlowValidationResult() + ) + + request = flow.GetFlowValidationResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.FlowValidationResult() + + client.get_flow_validation_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_flow_validation_result_rest_bad_request( + transport: str = "rest", request_type=flow.GetFlowValidationResultRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/validationResult" + } + 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_flow_validation_result(request) + + +def test_get_flow_validation_result_rest_flattened(): + client = FlowsClient( + 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 = flow.FlowValidationResult() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/validationResult" + } + + # 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 = flow.FlowValidationResult.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_flow_validation_result(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/validationResult}" + % client.transport._host, + args[1], + ) + + +def test_get_flow_validation_result_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow_validation_result( + flow.GetFlowValidationResultRequest(), + name="name_value", + ) + + +def test_get_flow_validation_result_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ImportFlowRequest, + dict, + ], +) +def test_import_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.import_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_flow_rest_required_fields(request_type=flow.ImportFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).import_flow._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() + ).import_flow._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 = FlowsClient( + 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.import_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_import_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_import_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ImportFlowRequest.pb(flow.ImportFlowRequest()) + 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 = flow.ImportFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_flow_rest_bad_request( + transport: str = "rest", request_type=flow.ImportFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.import_flow(request) + + +def test_import_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ExportFlowRequest, + dict, + ], +) +def test_export_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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(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.export_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_flow_rest_required_fields(request_type=flow.ExportFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).export_flow._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() + ).export_flow._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 = FlowsClient( + 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.export_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_export_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_export_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ExportFlowRequest.pb(flow.ExportFlowRequest()) + 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 = flow.ExportFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_flow_rest_bad_request( + transport: str = "rest", request_type=flow.ExportFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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.export_flow(request) + + +def test_export_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = FlowsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = FlowsClient( + 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 = FlowsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = FlowsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = FlowsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.FlowsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.FlowsGrpcTransport, + transports.FlowsGrpcAsyncIOTransport, + transports.FlowsRestTransport, + ], +) +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 = FlowsClient.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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.FlowsGrpcTransport, + ) + + +def test_flows_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.FlowsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_flows_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.flows.transports.FlowsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.FlowsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_flow", + "delete_flow", + "list_flows", + "get_flow", + "update_flow", + "train_flow", + "validate_flow", + "get_flow_validation_result", + "import_flow", + "export_flow", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_flows_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.dialogflowcx_v3.services.flows.transports.FlowsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.FlowsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_flows_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.dialogflowcx_v3.services.flows.transports.FlowsTransport._prep_wrapped_messages" + ) as Transport: Transport.return_value = None adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.FlowsTransport() @@ -3196,6 +6198,7 @@ def test_flows_transport_auth_adc(transport_class): [ transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport, + transports.FlowsRestTransport, ], ) def test_flows_transport_auth_gdch_credentials(transport_class): @@ -3293,11 +6296,40 @@ def test_flows_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_flows_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.FlowsRestTransport( + 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_flows_rest_lro_client(): + client = FlowsClient( + 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_flows_host_no_port(transport_name): @@ -3308,7 +6340,11 @@ def test_flows_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3316,6 +6352,7 @@ def test_flows_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_flows_host_with_port(transport_name): @@ -3326,7 +6363,60 @@ def test_flows_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_flows_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = FlowsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = FlowsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_flow._session + session2 = client2.transport.create_flow._session + assert session1 != session2 + session1 = client1.transport.delete_flow._session + session2 = client2.transport.delete_flow._session + assert session1 != session2 + session1 = client1.transport.list_flows._session + session2 = client2.transport.list_flows._session + assert session1 != session2 + session1 = client1.transport.get_flow._session + session2 = client2.transport.get_flow._session + assert session1 != session2 + session1 = client1.transport.update_flow._session + session2 = client2.transport.update_flow._session + assert session1 != session2 + session1 = client1.transport.train_flow._session + session2 = client2.transport.train_flow._session + assert session1 != session2 + session1 = client1.transport.validate_flow._session + session2 = client2.transport.validate_flow._session + assert session1 != session2 + session1 = client1.transport.get_flow_validation_result._session + session2 = client2.transport.get_flow_validation_result._session + assert session1 != session2 + session1 = client1.transport.import_flow._session + session2 = client2.transport.import_flow._session + assert session1 != session2 + session1 = client1.transport.export_flow._session + session2 = client2.transport.export_flow._session + assert session1 != session2 def test_flows_grpc_transport_channel(): @@ -3801,6 +6891,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4518,6 +7894,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4535,6 +7912,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_intents.py b/tests/unit/gapic/dialogflowcx_v3/test_intents.py index e56d39c5..6b70c3c9 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_intents.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_intents.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 @@ -93,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_info(client_class, transport_name): @@ -106,7 +114,11 @@ def test_intents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -114,6 +126,7 @@ def test_intents_client_from_service_account_info(client_class, transport_name): [ (transports.IntentsGrpcTransport, "grpc"), (transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -137,6 +150,7 @@ def test_intents_client_service_account_always_use_jwt(transport_class, transpor [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_file(client_class, transport_name): @@ -157,13 +171,18 @@ def test_intents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_intents_client_get_transport_class(): transport = IntentsClient.get_transport_class() available_transports = [ transports.IntentsGrpcTransport, + transports.IntentsRestTransport, ] assert transport in available_transports @@ -176,6 +195,7 @@ def test_intents_client_get_transport_class(): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -315,6 +335,8 @@ def test_intents_client_client_options(client_class, transport_class, transport_ "grpc_asyncio", "false", ), + (IntentsClient, transports.IntentsRestTransport, "rest", "true"), + (IntentsClient, transports.IntentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -500,6 +522,7 @@ def test_intents_client_get_mtls_endpoint_and_cert_source(client_class): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_client_options_scopes( @@ -535,6 +558,7 @@ def test_intents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (IntentsClient, transports.IntentsRestTransport, "rest", None), ], ) def test_intents_client_client_options_credentials_file( @@ -2035,141 +2059,1682 @@ async def test_delete_intent_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.IntentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + intent.ListIntentsRequest, + dict, + ], +) +def test_list_intents_rest(request_type): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = IntentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = intent.ListIntentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.IntentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.ListIntentsResponse.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_intents(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListIntentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_intents_rest_required_fields(request_type=intent.ListIntentsRequest): + transport_class = transports.IntentsRestTransport + + 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_intents._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_intents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + "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 = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse() + # 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 = intent.ListIntentsResponse.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_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_intents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.IntentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = IntentsClient( - client_options=options, - transport=transport, + client = IntentsClient(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.IntentsRestInterceptor, "post_list_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_list_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.ListIntentsRequest.pb(intent.ListIntentsRequest()) + 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 = intent.ListIntentsResponse.to_json( + intent.ListIntentsResponse() ) - # 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 = IntentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = intent.ListIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.ListIntentsResponse() + + client.list_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.IntentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_intents_rest_bad_request( + transport: str = "rest", request_type=intent.ListIntentsRequest +): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( + # 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_intents(request) + + +def test_list_intents_rest_flattened(): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = IntentsClient(transport=transport) - assert client.transport is 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 = intent.ListIntentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = intent.ListIntentsResponse.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_intents(**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/v3/{parent=projects/*/locations/*/agents/*}/intents" + % client.transport._host, + args[1], + ) + + +def test_list_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.IntentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_intents( + intent.ListIntentsRequest(), + parent="parent_value", + ) + + +def test_list_intents_rest_pager(transport: str = "rest"): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + intent.Intent(), + ], + next_page_token="abc", + ), + intent.ListIntentsResponse( + intents=[], + next_page_token="def", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + ], + next_page_token="ghi", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(intent.ListIntentsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_intents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, intent.Intent) for i in results) + + pages = list(client.list_intents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + intent.GetIntentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = IntentsClient.get_transport_class(transport_name)( +def test_get_intent_rest(request_type): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/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 = intent.Intent( + name="name_value", + display_name="display_name_value", + priority=898, + is_fallback=True, + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.Intent.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_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.priority == 898 + assert response.is_fallback is True + assert response.description == "description_value" + + +def test_get_intent_rest_required_fields(request_type=intent.GetIntentRequest): + transport_class = transports.IntentsRestTransport + + 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_intent._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_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.IntentsGrpcTransport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.Intent() + # 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 = intent.Intent.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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_intent._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) -def test_intents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "post_get_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_get_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.GetIntentRequest.pb(intent.GetIntentRequest()) + 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 = intent.Intent.to_json(intent.Intent()) + + request = intent.GetIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.Intent() -def test_intents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.intents.transports.IntentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.get_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly + pre.assert_called_once() + post.assert_called_once() + + +def test_get_intent_rest_bad_request( + transport: str = "rest", request_type=intent.GetIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + 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_intent(request) + + +def test_get_intent_rest_flattened(): + client = IntentsClient( + 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 = intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + + # 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 = intent.Intent.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_intent(**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/v3/{name=projects/*/locations/*/agents/*/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_get_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + intent.GetIntentRequest(), + name="name_value", + ) + + +def test_get_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_intent.CreateIntentRequest, + dict, + ], +) +def test_create_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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 = gcdc_intent.Intent( + name="name_value", + display_name="display_name_value", + priority=898, + is_fallback=True, + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_intent.Intent.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_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.priority == 898 + assert response.is_fallback is True + assert response.description == "description_value" + + +def test_create_intent_rest_required_fields( + request_type=gcdc_intent.CreateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + 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() + ).create_intent._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() + ).create_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_intent.Intent() + # 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 = gcdc_intent.Intent.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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "intent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "post_create_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_create_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_intent.CreateIntentRequest.pb( + gcdc_intent.CreateIntentRequest() + ) + 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 = gcdc_intent.Intent.to_json(gcdc_intent.Intent()) + + request = gcdc_intent.CreateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_intent.Intent() + + client.create_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_intent_rest_bad_request( + transport: str = "rest", request_type=gcdc_intent.CreateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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_intent(request) + + +def test_create_intent_rest_flattened(): + client = IntentsClient( + 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 = gcdc_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + intent=gcdc_intent.Intent(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 = gcdc_intent.Intent.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_intent(**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/v3/{parent=projects/*/locations/*/agents/*}/intents" + % client.transport._host, + args[1], + ) + + +def test_create_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + gcdc_intent.CreateIntentRequest(), + parent="parent_value", + intent=gcdc_intent.Intent(name="name_value"), + ) + + +def test_create_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_intent.UpdateIntentRequest, + dict, + ], +) +def test_update_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "intent": { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + } + request_init["intent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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 = gcdc_intent.Intent( + name="name_value", + display_name="display_name_value", + priority=898, + is_fallback=True, + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_intent.Intent.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_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.priority == 898 + assert response.is_fallback is True + assert response.description == "description_value" + + +def test_update_intent_rest_required_fields( + request_type=gcdc_intent.UpdateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + 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_intent._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_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_intent.Intent() + # 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 = gcdc_intent.Intent.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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("intent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "post_update_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_update_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_intent.UpdateIntentRequest.pb( + gcdc_intent.UpdateIntentRequest() + ) + 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 = gcdc_intent.Intent.to_json(gcdc_intent.Intent()) + + request = gcdc_intent.UpdateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_intent.Intent() + + client.update_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_intent_rest_bad_request( + transport: str = "rest", request_type=gcdc_intent.UpdateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "intent": { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + } + request_init["intent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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_intent(request) + + +def test_update_intent_rest_flattened(): + client = IntentsClient( + 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 = gcdc_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = { + "intent": { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + intent=gcdc_intent.Intent(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 = gcdc_intent.Intent.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_intent(**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/v3/{intent.name=projects/*/locations/*/agents/*/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + gcdc_intent.UpdateIntentRequest(), + intent=gcdc_intent.Intent(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.DeleteIntentRequest, + dict, + ], +) +def test_delete_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/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 = 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_intent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_intent_rest_required_fields(request_type=intent.DeleteIntentRequest): + transport_class = transports.IntentsRestTransport + + 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_intent._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_intent._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 = IntentsClient( + 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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_intent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "pre_delete_intent" + ) as pre: + pre.assert_not_called() + pb_message = intent.DeleteIntentRequest.pb(intent.DeleteIntentRequest()) + 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 = intent.DeleteIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_intent_rest_bad_request( + transport: str = "rest", request_type=intent.DeleteIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + 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_intent(request) + + +def test_delete_intent_rest_flattened(): + client = IntentsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + + # 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_intent(**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/v3/{name=projects/*/locations/*/agents/*/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + intent.DeleteIntentRequest(), + name="name_value", + ) + + +def test_delete_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = IntentsClient( + 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 = IntentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = IntentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.IntentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, + ], +) +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 = IntentsClient.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 = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.IntentsGrpcTransport, + ) + + +def test_intents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_intents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.intents.transports.IntentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly # raise NotImplementedError. methods = ( "list_intents", @@ -2277,6 +3842,7 @@ def test_intents_transport_auth_adc(transport_class): [ transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, ], ) def test_intents_transport_auth_gdch_credentials(transport_class): @@ -2374,11 +3940,23 @@ def test_intents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_intents_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.IntentsRestTransport( + 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_intents_host_no_port(transport_name): @@ -2389,7 +3967,11 @@ def test_intents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2397,6 +3979,7 @@ def test_intents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_intents_host_with_port(transport_name): @@ -2407,7 +3990,45 @@ def test_intents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_intents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = IntentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = IntentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_intents._session + session2 = client2.transport.list_intents._session + assert session1 != session2 + session1 = client1.transport.get_intent._session + session2 = client2.transport.get_intent._session + assert session1 != session2 + session1 = client1.transport.create_intent._session + session2 = client2.transport.create_intent._session + assert session1 != session2 + session1 = client1.transport.update_intent._session + session2 = client2.transport.update_intent._session + assert session1 != session2 + session1 = client1.transport.delete_intent._session + session2 = client2.transport.delete_intent._session + assert session1 != session2 def test_intents_grpc_transport_channel(): @@ -2726,6 +4347,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3443,6 +5350,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3460,6 +5368,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_pages.py b/tests/unit/gapic/dialogflowcx_v3/test_pages.py index fd078c44..5c2b3c28 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_pages.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_pages.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 @@ -96,6 +103,7 @@ def test__get_default_mtls_endpoint(): [ (PagesClient, "grpc"), (PagesAsyncClient, "grpc_asyncio"), + (PagesClient, "rest"), ], ) def test_pages_client_from_service_account_info(client_class, transport_name): @@ -109,7 +117,11 @@ def test_pages_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -117,6 +129,7 @@ def test_pages_client_from_service_account_info(client_class, transport_name): [ (transports.PagesGrpcTransport, "grpc"), (transports.PagesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.PagesRestTransport, "rest"), ], ) def test_pages_client_service_account_always_use_jwt(transport_class, transport_name): @@ -140,6 +153,7 @@ def test_pages_client_service_account_always_use_jwt(transport_class, transport_ [ (PagesClient, "grpc"), (PagesAsyncClient, "grpc_asyncio"), + (PagesClient, "rest"), ], ) def test_pages_client_from_service_account_file(client_class, transport_name): @@ -160,13 +174,18 @@ def test_pages_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_pages_client_get_transport_class(): transport = PagesClient.get_transport_class() available_transports = [ transports.PagesGrpcTransport, + transports.PagesRestTransport, ] assert transport in available_transports @@ -179,6 +198,7 @@ def test_pages_client_get_transport_class(): [ (PagesClient, transports.PagesGrpcTransport, "grpc"), (PagesAsyncClient, transports.PagesGrpcAsyncIOTransport, "grpc_asyncio"), + (PagesClient, transports.PagesRestTransport, "rest"), ], ) @mock.patch.object( @@ -318,6 +338,8 @@ def test_pages_client_client_options(client_class, transport_class, transport_na "grpc_asyncio", "false", ), + (PagesClient, transports.PagesRestTransport, "rest", "true"), + (PagesClient, transports.PagesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -503,6 +525,7 @@ def test_pages_client_get_mtls_endpoint_and_cert_source(client_class): [ (PagesClient, transports.PagesGrpcTransport, "grpc"), (PagesAsyncClient, transports.PagesGrpcAsyncIOTransport, "grpc_asyncio"), + (PagesClient, transports.PagesRestTransport, "rest"), ], ) def test_pages_client_client_options_scopes( @@ -538,6 +561,7 @@ def test_pages_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (PagesClient, transports.PagesRestTransport, "rest", None), ], ) def test_pages_client_client_options_credentials_file( @@ -2014,168 +2038,2023 @@ async def test_delete_page_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.PagesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + page.ListPagesRequest, + dict, + ], +) +def test_list_pages_rest(request_type): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = PagesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/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 = page.ListPagesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.PagesGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = page.ListPagesResponse.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_pages(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListPagesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_pages_rest_required_fields(request_type=page.ListPagesRequest): + transport_class = transports.PagesRestTransport + + 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_pages._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_pages._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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 = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = PagesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = page.ListPagesResponse() + # 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 = page.ListPagesResponse.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_pages(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_pages_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_pages._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.PagesGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_pages_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = PagesClient( - client_options=options, - transport=transport, + client = PagesClient(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.PagesRestInterceptor, "post_list_pages" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_list_pages" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = page.ListPagesRequest.pb(page.ListPagesRequest()) + 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 = page.ListPagesResponse.to_json( + page.ListPagesResponse() ) - # 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 = PagesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = page.ListPagesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = page.ListPagesResponse() + + client.list_pages( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.PagesGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_pages_rest_bad_request( + transport: str = "rest", request_type=page.ListPagesRequest +): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = PagesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.PagesGrpcTransport( + # 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_pages(request) + + +def test_list_pages_rest_flattened(): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = PagesClient(transport=transport) - assert client.transport is 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 = page.ListPagesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.PagesGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = page.ListPagesResponse.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_pages(**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/v3/{parent=projects/*/locations/*/agents/*/flows/*}/pages" + % client.transport._host, + args[1], + ) + + +def test_list_pages_rest_flattened_error(transport: str = "rest"): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.PagesGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_pages( + page.ListPagesRequest(), + parent="parent_value", + ) + + +def test_list_pages_rest_pager(transport: str = "rest"): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + page.ListPagesResponse( + pages=[ + page.Page(), + page.Page(), + page.Page(), + ], + next_page_token="abc", + ), + page.ListPagesResponse( + pages=[], + next_page_token="def", + ), + page.ListPagesResponse( + pages=[ + page.Page(), + ], + next_page_token="ghi", + ), + page.ListPagesResponse( + pages=[ + page.Page(), + page.Page(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(page.ListPagesResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.PagesGrpcTransport, - transports.PagesGrpcAsyncIOTransport, - ], -) -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() + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + pager = client.list_pages(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, page.Page) for i in results) + + pages = list(client.list_pages(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + page.GetPageRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = PagesClient.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_page_rest(request_type): client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.PagesGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + request = request_type(**request_init) -def test_pages_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.PagesTransport( - 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 = page.Page( + name="name_value", + display_name="display_name_value", + transition_route_groups=["transition_route_groups_value"], ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = page.Page.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_pages_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.pages.transports.PagesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.PagesTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_page(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_pages", - "get_page", - "create_page", - "update_page", - "delete_page", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, page.Page) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_get_page_rest_required_fields(request_type=page.GetPageRequest): + transport_class = transports.PagesRestTransport + + 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, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_page._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_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = page.Page() + # 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 = page.Page.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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_page._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "post_get_page" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_get_page" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = page.GetPageRequest.pb(page.GetPageRequest()) + 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 = page.Page.to_json(page.Page()) + + request = page.GetPageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = page.Page() + + client.get_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_page_rest_bad_request( + transport: str = "rest", request_type=page.GetPageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + 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_page(request) + + +def test_get_page_rest_flattened(): + client = PagesClient( + 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 = page.Page() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + + # 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 = page.Page.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_page(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/pages/*}" + % client.transport._host, + args[1], + ) + + +def test_get_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + page.GetPageRequest(), + name="name_value", + ) + + +def test_get_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_page.CreatePageRequest, + dict, + ], +) +def test_create_page_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["page"] = { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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 = gcdc_page.Page( + name="name_value", + display_name="display_name_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_page.Page.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_page(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_page.Page) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_create_page_rest_required_fields(request_type=gcdc_page.CreatePageRequest): + transport_class = transports.PagesRestTransport + + 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() + ).create_page._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() + ).create_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_page.Page() + # 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 = gcdc_page.Page.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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_page._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "page", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "post_create_page" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_create_page" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_page.CreatePageRequest.pb(gcdc_page.CreatePageRequest()) + 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 = gcdc_page.Page.to_json(gcdc_page.Page()) + + request = gcdc_page.CreatePageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_page.Page() + + client.create_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_page_rest_bad_request( + transport: str = "rest", request_type=gcdc_page.CreatePageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["page"] = { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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_page(request) + + +def test_create_page_rest_flattened(): + client = PagesClient( + 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 = gcdc_page.Page() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + page=gcdc_page.Page(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 = gcdc_page.Page.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_page(**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/v3/{parent=projects/*/locations/*/agents/*/flows/*}/pages" + % client.transport._host, + args[1], + ) + + +def test_create_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + gcdc_page.CreatePageRequest(), + parent="parent_value", + page=gcdc_page.Page(name="name_value"), + ) + + +def test_create_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_page.UpdatePageRequest, + dict, + ], +) +def test_update_page_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "page": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + } + request_init["page"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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 = gcdc_page.Page( + name="name_value", + display_name="display_name_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_page.Page.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_page(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_page.Page) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_update_page_rest_required_fields(request_type=gcdc_page.UpdatePageRequest): + transport_class = transports.PagesRestTransport + + 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_page._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_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_page.Page() + # 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 = gcdc_page.Page.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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_page._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("page",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "post_update_page" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_update_page" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_page.UpdatePageRequest.pb(gcdc_page.UpdatePageRequest()) + 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 = gcdc_page.Page.to_json(gcdc_page.Page()) + + request = gcdc_page.UpdatePageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_page.Page() + + client.update_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_page_rest_bad_request( + transport: str = "rest", request_type=gcdc_page.UpdatePageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "page": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + } + request_init["page"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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_page(request) + + +def test_update_page_rest_flattened(): + client = PagesClient( + 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 = gcdc_page.Page() + + # get arguments that satisfy an http rule for this method + sample_request = { + "page": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + page=gcdc_page.Page(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 = gcdc_page.Page.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_page(**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/v3/{page.name=projects/*/locations/*/agents/*/flows/*/pages/*}" + % client.transport._host, + args[1], + ) + + +def test_update_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + gcdc_page.UpdatePageRequest(), + page=gcdc_page.Page(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + page.DeletePageRequest, + dict, + ], +) +def test_delete_page_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + 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_page(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_page_rest_required_fields(request_type=page.DeletePageRequest): + transport_class = transports.PagesRestTransport + + 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_page._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_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = PagesClient( + 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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_page._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "pre_delete_page" + ) as pre: + pre.assert_not_called() + pb_message = page.DeletePageRequest.pb(page.DeletePageRequest()) + 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 = page.DeletePageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_page_rest_bad_request( + transport: str = "rest", request_type=page.DeletePageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + 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_page(request) + + +def test_delete_page_rest_flattened(): + client = PagesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + + # 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_page(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/pages/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + page.DeletePageRequest(), + name="name_value", + ) + + +def test_delete_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PagesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = PagesClient( + 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 = PagesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PagesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = PagesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.PagesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PagesGrpcTransport, + transports.PagesGrpcAsyncIOTransport, + transports.PagesRestTransport, + ], +) +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 = PagesClient.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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.PagesGrpcTransport, + ) + + +def test_pages_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.PagesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_pages_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.pages.transports.PagesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.PagesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_pages", + "get_page", + "create_page", + "update_page", + "delete_page", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_pages_base_transport_with_credentials_file(): @@ -2256,6 +4135,7 @@ def test_pages_transport_auth_adc(transport_class): [ transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport, + transports.PagesRestTransport, ], ) def test_pages_transport_auth_gdch_credentials(transport_class): @@ -2353,11 +4233,23 @@ def test_pages_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_pages_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.PagesRestTransport( + 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_pages_host_no_port(transport_name): @@ -2368,7 +4260,11 @@ def test_pages_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2376,6 +4272,7 @@ def test_pages_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_pages_host_with_port(transport_name): @@ -2386,7 +4283,45 @@ def test_pages_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_pages_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = PagesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = PagesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_pages._session + session2 = client2.transport.list_pages._session + assert session1 != session2 + session1 = client1.transport.get_page._session + session2 = client2.transport.get_page._session + assert session1 != session2 + session1 = client1.transport.create_page._session + session2 = client2.transport.create_page._session + assert session1 != session2 + session1 = client1.transport.update_page._session + session2 = client2.transport.update_page._session + assert session1 != session2 + session1 = client1.transport.delete_page._session + session2 = client2.transport.delete_page._session + assert session1 != session2 def test_pages_grpc_transport_channel(): @@ -2827,6 +4762,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3544,6 +5765,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3561,6 +5783,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py b/tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py index 4a4330ca..0258d812 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_security_settings_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 @@ -106,6 +113,7 @@ def test__get_default_mtls_endpoint(): [ (SecuritySettingsServiceClient, "grpc"), (SecuritySettingsServiceAsyncClient, "grpc_asyncio"), + (SecuritySettingsServiceClient, "rest"), ], ) def test_security_settings_service_client_from_service_account_info( @@ -121,7 +129,11 @@ def test_security_settings_service_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -129,6 +141,7 @@ def test_security_settings_service_client_from_service_account_info( [ (transports.SecuritySettingsServiceGrpcTransport, "grpc"), (transports.SecuritySettingsServiceGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SecuritySettingsServiceRestTransport, "rest"), ], ) def test_security_settings_service_client_service_account_always_use_jwt( @@ -154,6 +167,7 @@ def test_security_settings_service_client_service_account_always_use_jwt( [ (SecuritySettingsServiceClient, "grpc"), (SecuritySettingsServiceAsyncClient, "grpc_asyncio"), + (SecuritySettingsServiceClient, "rest"), ], ) def test_security_settings_service_client_from_service_account_file( @@ -176,13 +190,18 @@ def test_security_settings_service_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_security_settings_service_client_get_transport_class(): transport = SecuritySettingsServiceClient.get_transport_class() available_transports = [ transports.SecuritySettingsServiceGrpcTransport, + transports.SecuritySettingsServiceRestTransport, ] assert transport in available_transports @@ -203,6 +222,11 @@ def test_security_settings_service_client_get_transport_class(): transports.SecuritySettingsServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -358,6 +382,18 @@ def test_security_settings_service_client_client_options( "grpc_asyncio", "false", ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + "true", + ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -563,6 +599,11 @@ def test_security_settings_service_client_get_mtls_endpoint_and_cert_source( transports.SecuritySettingsServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + ), ], ) def test_security_settings_service_client_client_options_scopes( @@ -603,6 +644,12 @@ def test_security_settings_service_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + None, + ), ], ) def test_security_settings_service_client_client_options_credentials_file( @@ -2308,134 +2355,1737 @@ async def test_delete_security_settings_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcdc_security_settings.CreateSecuritySettingsRequest, + dict, + ], +) +def test_create_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["security_settings"] = { + "name": "name_value", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + 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 = gcdc_security_settings.SecuritySettings( + name="name_value", + display_name="display_name_value", + redaction_strategy=gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE, + redaction_scope=gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE, + inspect_template="inspect_template_value", + deidentify_template="deidentify_template_value", + purge_data_types=[ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ], + retention_window_days=2271, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_security_settings.SecuritySettings) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.redaction_strategy + == gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE ) - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + assert ( + response.redaction_scope + == gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE + ) + assert response.inspect_template == "inspect_template_value" + assert response.deidentify_template == "deidentify_template_value" + assert response.purge_data_types == [ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ] + + +def test_create_security_settings_rest_required_fields( + request_type=gcdc_security_settings.CreateSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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 an api_key and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_security_settings._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() + ).create_security_settings._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 = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - client_options=options, - transport=transport, - ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_security_settings.SecuritySettings() + # 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 - # 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 = SecuritySettingsServiceClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "securitySettings", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), ) - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, + "post_create_security_settings", + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, + "pre_create_security_settings", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_security_settings.CreateSecuritySettingsRequest.pb( + gcdc_security_settings.CreateSecuritySettingsRequest() + ) + 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 = gcdc_security_settings.SecuritySettings.to_json( + gcdc_security_settings.SecuritySettings() ) + request = gcdc_security_settings.CreateSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_security_settings.SecuritySettings() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + client.create_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_security_settings_rest_bad_request( + transport: str = "rest", + request_type=gcdc_security_settings.CreateSecuritySettingsRequest, +): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = SecuritySettingsServiceClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["security_settings"] = { + "name": "name_value", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + # 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_security_settings(request) + + +def test_create_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.SecuritySettingsServiceGrpcAsyncIOTransport( + # 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 = gcdc_security_settings.SecuritySettings() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + security_settings=gcdc_security_settings.SecuritySettings( + 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 = gcdc_security_settings.SecuritySettings.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_security_settings(**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/v3/{parent=projects/*/locations/*}/securitySettings" + % client.transport._host, + args[1], + ) + + +def test_create_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( 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_security_settings( + gcdc_security_settings.CreateSecuritySettingsRequest(), + parent="parent_value", + security_settings=gcdc_security_settings.SecuritySettings( + name="name_value" + ), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.SecuritySettingsServiceGrpcTransport, - transports.SecuritySettingsServiceGrpcAsyncIOTransport, - ], -) -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_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + security_settings.GetSecuritySettingsRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = SecuritySettingsServiceClient.get_transport_class(transport_name)( +def test_get_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = SecuritySettingsServiceClient( - credentials=ga_credentials.AnonymousCredentials(), + # 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 = security_settings.SecuritySettings( + name="name_value", + display_name="display_name_value", + redaction_strategy=security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE, + redaction_scope=security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE, + inspect_template="inspect_template_value", + deidentify_template="deidentify_template_value", + purge_data_types=[ + security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ], + retention_window_days=2271, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = security_settings.SecuritySettings.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, security_settings.SecuritySettings) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.redaction_strategy + == security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE ) - assert isinstance( - client.transport, - transports.SecuritySettingsServiceGrpcTransport, + assert ( + response.redaction_scope + == security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE ) + assert response.inspect_template == "inspect_template_value" + assert response.deidentify_template == "deidentify_template_value" + assert response.purge_data_types == [ + security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ] -def test_security_settings_service_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.SecuritySettingsServiceTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +def test_get_security_settings_rest_required_fields( + request_type=security_settings.GetSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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 -def test_security_settings_service_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.security_settings_service.transports.SecuritySettingsServiceTransport.__init__" + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_security_settings._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_security_settings._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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = security_settings.SecuritySettings() + # 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 = security_settings.SecuritySettings.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, "post_get_security_settings" + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, "pre_get_security_settings" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = security_settings.GetSecuritySettingsRequest.pb( + security_settings.GetSecuritySettingsRequest() + ) + 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 = security_settings.SecuritySettings.to_json( + security_settings.SecuritySettings() + ) + + request = security_settings.GetSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = security_settings.SecuritySettings() + + client.get_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_security_settings_rest_bad_request( + transport: str = "rest", request_type=security_settings.GetSecuritySettingsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/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_security_settings(request) + + +def test_get_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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 = security_settings.SecuritySettings() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/securitySettings/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 = security_settings.SecuritySettings.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_security_settings(**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/v3/{name=projects/*/locations/*/securitySettings/*}" + % client.transport._host, + args[1], + ) + + +def test_get_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + security_settings.GetSecuritySettingsRequest(), + name="name_value", + ) + + +def test_get_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_security_settings.UpdateSecuritySettingsRequest, + dict, + ], +) +def test_update_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "security_settings": { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + } + request_init["security_settings"] = { + "name": "projects/sample1/locations/sample2/securitySettings/sample3", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + 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 = gcdc_security_settings.SecuritySettings( + name="name_value", + display_name="display_name_value", + redaction_strategy=gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE, + redaction_scope=gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE, + inspect_template="inspect_template_value", + deidentify_template="deidentify_template_value", + purge_data_types=[ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ], + retention_window_days=2271, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_security_settings.SecuritySettings) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.redaction_strategy + == gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE + ) + assert ( + response.redaction_scope + == gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE + ) + assert response.inspect_template == "inspect_template_value" + assert response.deidentify_template == "deidentify_template_value" + assert response.purge_data_types == [ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ] + + +def test_update_security_settings_rest_required_fields( + request_type=gcdc_security_settings.UpdateSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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_security_settings._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_security_settings._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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_security_settings.SecuritySettings() + # 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 = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "securitySettings", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, + "post_update_security_settings", + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, + "pre_update_security_settings", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_security_settings.UpdateSecuritySettingsRequest.pb( + gcdc_security_settings.UpdateSecuritySettingsRequest() + ) + 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 = gcdc_security_settings.SecuritySettings.to_json( + gcdc_security_settings.SecuritySettings() + ) + + request = gcdc_security_settings.UpdateSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_security_settings.SecuritySettings() + + client.update_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_security_settings_rest_bad_request( + transport: str = "rest", + request_type=gcdc_security_settings.UpdateSecuritySettingsRequest, +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "security_settings": { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + } + request_init["security_settings"] = { + "name": "projects/sample1/locations/sample2/securitySettings/sample3", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + 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_security_settings(request) + + +def test_update_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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 = gcdc_security_settings.SecuritySettings() + + # get arguments that satisfy an http rule for this method + sample_request = { + "security_settings": { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + security_settings=gcdc_security_settings.SecuritySettings( + 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 = gcdc_security_settings.SecuritySettings.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_security_settings(**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/v3/{security_settings.name=projects/*/locations/*/securitySettings/*}" + % client.transport._host, + args[1], + ) + + +def test_update_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + gcdc_security_settings.UpdateSecuritySettingsRequest(), + security_settings=gcdc_security_settings.SecuritySettings( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + security_settings.ListSecuritySettingsRequest, + dict, + ], +) +def test_list_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/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 = security_settings.ListSecuritySettingsResponse( + 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 = security_settings.ListSecuritySettingsResponse.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSecuritySettingsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_security_settings_rest_required_fields( + request_type=security_settings.ListSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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_security_settings._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_security_settings._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", + ) + ) + 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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = security_settings.ListSecuritySettingsResponse() + # 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 = security_settings.ListSecuritySettingsResponse.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, "post_list_security_settings" + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, "pre_list_security_settings" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = security_settings.ListSecuritySettingsRequest.pb( + security_settings.ListSecuritySettingsRequest() + ) + 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 = ( + security_settings.ListSecuritySettingsResponse.to_json( + security_settings.ListSecuritySettingsResponse() + ) + ) + + request = security_settings.ListSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = security_settings.ListSecuritySettingsResponse() + + client.list_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_security_settings_rest_bad_request( + transport: str = "rest", request_type=security_settings.ListSecuritySettingsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/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_security_settings(request) + + +def test_list_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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 = security_settings.ListSecuritySettingsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/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 = security_settings.ListSecuritySettingsResponse.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_security_settings(**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/v3/{parent=projects/*/locations/*}/securitySettings" + % client.transport._host, + args[1], + ) + + +def test_list_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + security_settings.ListSecuritySettingsRequest(), + parent="parent_value", + ) + + +def test_list_security_settings_rest_pager(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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 = ( + security_settings.ListSecuritySettingsResponse( + security_settings=[ + security_settings.SecuritySettings(), + security_settings.SecuritySettings(), + security_settings.SecuritySettings(), + ], + next_page_token="abc", + ), + security_settings.ListSecuritySettingsResponse( + security_settings=[], + next_page_token="def", + ), + security_settings.ListSecuritySettingsResponse( + security_settings=[ + security_settings.SecuritySettings(), + ], + next_page_token="ghi", + ), + security_settings.ListSecuritySettingsResponse( + security_settings=[ + security_settings.SecuritySettings(), + security_settings.SecuritySettings(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + security_settings.ListSecuritySettingsResponse.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": "projects/sample1/locations/sample2"} + + pager = client.list_security_settings(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, security_settings.SecuritySettings) for i in results) + + pages = list(client.list_security_settings(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", + [ + security_settings.DeleteSecuritySettingsRequest, + dict, + ], +) +def test_delete_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/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_security_settings(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_security_settings_rest_required_fields( + request_type=security_settings.DeleteSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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_security_settings._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_security_settings._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 = SecuritySettingsServiceClient( + 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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, + "pre_delete_security_settings", + ) as pre: + pre.assert_not_called() + pb_message = security_settings.DeleteSecuritySettingsRequest.pb( + security_settings.DeleteSecuritySettingsRequest() + ) + 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 = security_settings.DeleteSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_security_settings_rest_bad_request( + transport: str = "rest", + request_type=security_settings.DeleteSecuritySettingsRequest, +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/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_security_settings(request) + + +def test_delete_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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": "projects/sample1/locations/sample2/securitySettings/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_security_settings(**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/v3/{name=projects/*/locations/*/securitySettings/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + security_settings.DeleteSecuritySettingsRequest(), + name="name_value", + ) + + +def test_delete_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + 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 = SecuritySettingsServiceClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SecuritySettingsServiceClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SecuritySettingsServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SecuritySettingsServiceGrpcTransport, + transports.SecuritySettingsServiceGrpcAsyncIOTransport, + transports.SecuritySettingsServiceRestTransport, + ], +) +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 = SecuritySettingsServiceClient.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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SecuritySettingsServiceGrpcTransport, + ) + + +def test_security_settings_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SecuritySettingsServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_security_settings_service_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.security_settings_service.transports.SecuritySettingsServiceTransport.__init__" ) as Transport: Transport.return_value = None transport = transports.SecuritySettingsServiceTransport( @@ -2550,6 +4200,7 @@ def test_security_settings_service_transport_auth_adc(transport_class): [ transports.SecuritySettingsServiceGrpcTransport, transports.SecuritySettingsServiceGrpcAsyncIOTransport, + transports.SecuritySettingsServiceRestTransport, ], ) def test_security_settings_service_transport_auth_gdch_credentials(transport_class): @@ -2654,11 +4305,23 @@ def test_security_settings_service_grpc_transport_client_cert_source_for_mtls( ) +def test_security_settings_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.SecuritySettingsServiceRestTransport( + 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_security_settings_service_host_no_port(transport_name): @@ -2669,7 +4332,11 @@ def test_security_settings_service_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2677,6 +4344,7 @@ def test_security_settings_service_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_security_settings_service_host_with_port(transport_name): @@ -2687,7 +4355,45 @@ def test_security_settings_service_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_security_settings_service_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SecuritySettingsServiceClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SecuritySettingsServiceClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_security_settings._session + session2 = client2.transport.create_security_settings._session + assert session1 != session2 + session1 = client1.transport.get_security_settings._session + session2 = client2.transport.get_security_settings._session + assert session1 != session2 + session1 = client1.transport.update_security_settings._session + session2 = client2.transport.update_security_settings._session + assert session1 != session2 + session1 = client1.transport.list_security_settings._session + session2 = client2.transport.list_security_settings._session + assert session1 != session2 + session1 = client1.transport.delete_security_settings._session + session2 = client2.transport.delete_security_settings._session + assert session1 != session2 def test_security_settings_service_grpc_transport_channel(): @@ -3040,6 +4746,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3761,6 +5753,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3778,6 +5771,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py b/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py index 1fa4d141..e91a1e54 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.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 @@ -107,6 +114,7 @@ def test__get_default_mtls_endpoint(): [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_info( @@ -122,7 +130,11 @@ def test_session_entity_types_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -130,6 +142,7 @@ def test_session_entity_types_client_from_service_account_info( [ (transports.SessionEntityTypesGrpcTransport, "grpc"), (transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_service_account_always_use_jwt( @@ -155,6 +168,7 @@ def test_session_entity_types_client_service_account_always_use_jwt( [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_file( @@ -177,13 +191,18 @@ def test_session_entity_types_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_session_entity_types_client_get_transport_class(): transport = SessionEntityTypesClient.get_transport_class() available_transports = [ transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesRestTransport, ] assert transport in available_transports @@ -200,6 +219,7 @@ def test_session_entity_types_client_get_transport_class(): transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -355,6 +375,18 @@ def test_session_entity_types_client_client_options( "grpc_asyncio", "false", ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "true", + ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -554,6 +586,7 @@ def test_session_entity_types_client_get_mtls_endpoint_and_cert_source(client_cl transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_client_options_scopes( @@ -594,6 +627,12 @@ def test_session_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + None, + ), ], ) def test_session_entity_types_client_client_options_credentials_file( @@ -2198,222 +2237,1741 @@ async def test_delete_session_entity_type_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.ListSessionEntityTypesRequest, + dict, + ], +) +def test_list_session_entity_types_rest(request_type): + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - 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 = session_entity_type.ListSessionEntityTypesResponse( + next_page_token="next_page_token_value", ) - # 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 = SessionEntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_session_entity_types(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSessionEntityTypesPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_required_fields( + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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, + ) ) - client = SessionEntityTypesClient(transport=transport) - assert client.transport is transport + # verify fields with default values are dropped -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_session_entity_types._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_session_entity_types._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", + ) ) - channel = transport.grpc_channel - assert channel + jsonified_request.update(unset_fields) - transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse() + # 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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.SessionEntityTypesGrpcTransport, - transports.SessionEntityTypesGrpcAsyncIOTransport, - ], -) -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() + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.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 -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = SessionEntityTypesClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name + response = client.list_session_entity_types(request) + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.SessionEntityTypesGrpcTransport, + + unset_fields = transport.list_session_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_session_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_session_entity_types_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_list_session_entity_types" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_list_session_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.ListSessionEntityTypesRequest.pb( + session_entity_type.ListSessionEntityTypesRequest() + ) + 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 = ( + session_entity_type.ListSessionEntityTypesResponse.to_json( + session_entity_type.ListSessionEntityTypesResponse() + ) ) + request = session_entity_type.ListSessionEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.ListSessionEntityTypesResponse() -def test_session_entity_types_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_session_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_session_entity_types", - "get_session_entity_type", - "create_session_entity_type", - "update_session_entity_type", - "delete_session_entity_type", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + pre.assert_called_once() + post.assert_called_once() + + +def test_list_session_entity_types_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + client = SessionEntityTypesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request = request_type(**request_init) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # 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_session_entity_types(request) -def test_session_entity_types_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.dialogflowcx_v3.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport( - credentials_file="credentials.json", - quota_project_id="octopus", +def test_list_session_entity_types_rest_flattened(): + client = SessionEntityTypesClient( + 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 = session_entity_type.ListSessionEntityTypesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.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_session_entity_types(**mock_args) -def test_session_entity_types_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.dialogflowcx_v3.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport() - adc.assert_called_once() + # 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/v3/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) -def test_session_entity_types_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) - SessionEntityTypesClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, +def test_list_session_entity_types_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_types( + session_entity_type.ListSessionEntityTypesRequest(), + parent="parent_value", ) -@pytest.mark.parametrize( - "transport_class", +def test_list_session_entity_types_rest_pager(transport: str = "rest"): + client = SessionEntityTypesClient( + 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 = ( + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + next_page_token="abc", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[], + next_page_token="def", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + ], + next_page_token="ghi", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + session_entity_type.ListSessionEntityTypesResponse.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": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + + pager = client.list_session_entity_types(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, session_entity_type.SessionEntityType) for i in results + ) + + pages = list(client.list_session_entity_types(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", + [ + session_entity_type.GetSessionEntityTypeRequest, + dict, + ], +) +def test_get_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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 = session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.SessionEntityType.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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_get_session_entity_type_rest_required_fields( + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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_session_entity_type._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_session_entity_type._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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType() + # 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 = session_entity_type.SessionEntityType.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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_get_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_get_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.GetSessionEntityTypeRequest.pb( + session_entity_type.GetSessionEntityTypeRequest() + ) + 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 = session_entity_type.SessionEntityType.to_json( + session_entity_type.SessionEntityType() + ) + + request = session_entity_type.GetSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.SessionEntityType() + + client.get_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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_session_entity_type(request) + + +def test_get_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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 = session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + + # 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 = session_entity_type.SessionEntityType.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_session_entity_type(**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/v3/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_get_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + session_entity_type.GetSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_get_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_session_entity_type.CreateSessionEntityTypeRequest, + dict, + ], +) +def test_create_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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 = gcdc_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_create_session_entity_type_rest_required_fields( + request_type=gcdc_session_entity_type.CreateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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() + ).create_session_entity_type._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() + ).create_session_entity_type._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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_session_entity_type.SessionEntityType() + # 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "sessionEntityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_create_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_create_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_session_entity_type.CreateSessionEntityTypeRequest.pb( + gcdc_session_entity_type.CreateSessionEntityTypeRequest() + ) + 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 = gcdc_session_entity_type.SessionEntityType.to_json( + gcdc_session_entity_type.SessionEntityType() + ) + + request = gcdc_session_entity_type.CreateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_session_entity_type.SessionEntityType() + + client.create_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcdc_session_entity_type.CreateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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_session_entity_type(request) + + +def test_create_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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 = gcdc_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + session_entity_type=gcdc_session_entity_type.SessionEntityType( + 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(**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/v3/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) + + +def test_create_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + gcdc_session_entity_type.CreateSessionEntityTypeRequest(), + parent="parent_value", + session_entity_type=gcdc_session_entity_type.SessionEntityType( + name="name_value" + ), + ) + + +def test_create_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + dict, + ], +) +def test_update_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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 = gcdc_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_update_session_entity_type_rest_required_fields( + request_type=gcdc_session_entity_type.UpdateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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_session_entity_type._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_session_entity_type._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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_session_entity_type.SessionEntityType() + # 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("sessionEntityType",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_update_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_update_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_session_entity_type.UpdateSessionEntityTypeRequest.pb( + gcdc_session_entity_type.UpdateSessionEntityTypeRequest() + ) + 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 = gcdc_session_entity_type.SessionEntityType.to_json( + gcdc_session_entity_type.SessionEntityType() + ) + + request = gcdc_session_entity_type.UpdateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_session_entity_type.SessionEntityType() + + client.update_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcdc_session_entity_type.UpdateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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_session_entity_type(request) + + +def test_update_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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 = gcdc_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "session_entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + session_entity_type=gcdc_session_entity_type.SessionEntityType( + 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(**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/v3/{session_entity_type.name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + gcdc_session_entity_type.UpdateSessionEntityTypeRequest(), + session_entity_type=gcdc_session_entity_type.SessionEntityType( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.DeleteSessionEntityTypeRequest, + dict, + ], +) +def test_delete_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_session_entity_type_rest_required_fields( + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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_session_entity_type._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_session_entity_type._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 = SessionEntityTypesClient( + 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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "pre_delete_session_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = session_entity_type.DeleteSessionEntityTypeRequest.pb( + session_entity_type.DeleteSessionEntityTypeRequest() + ) + 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 = session_entity_type.DeleteSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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_session_entity_type(request) + + +def test_delete_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + + # 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_session_entity_type(**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/v3/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + session_entity_type.DeleteSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + 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 = SessionEntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SessionEntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, + ], +) +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 = SessionEntityTypesClient.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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SessionEntityTypesGrpcTransport, + ) + + +def test_session_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_session_entity_types_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_session_entity_types", + "get_session_entity_type", + "create_session_entity_type", + "update_session_entity_type", + "delete_session_entity_type", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_session_entity_types_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.dialogflowcx_v3.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_session_entity_types_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.dialogflowcx_v3.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport() + adc.assert_called_once() + + +def test_session_entity_types_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) + SessionEntityTypesClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", [ transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, @@ -2440,6 +3998,7 @@ def test_session_entity_types_transport_auth_adc(transport_class): [ transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, ], ) def test_session_entity_types_transport_auth_gdch_credentials(transport_class): @@ -2542,11 +4101,23 @@ def test_session_entity_types_grpc_transport_client_cert_source_for_mtls( ) +def test_session_entity_types_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.SessionEntityTypesRestTransport( + 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_session_entity_types_host_no_port(transport_name): @@ -2557,7 +4128,11 @@ def test_session_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2565,6 +4140,7 @@ def test_session_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_session_entity_types_host_with_port(transport_name): @@ -2575,7 +4151,45 @@ def test_session_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_session_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionEntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionEntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_session_entity_types._session + session2 = client2.transport.list_session_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_session_entity_type._session + session2 = client2.transport.get_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_session_entity_type._session + session2 = client2.transport.create_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_session_entity_type._session + session2 = client2.transport.update_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_session_entity_type._session + session2 = client2.transport.delete_session_entity_type._session + assert session1 != session2 def test_session_entity_types_grpc_transport_channel(): @@ -2878,6 +4492,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3597,6 +5497,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3614,6 +5515,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_sessions.py b/tests/unit/gapic/dialogflowcx_v3/test_sessions.py index 65fb227d..5a5e305f 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_sessions.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_sessions.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 @@ -98,6 +105,7 @@ def test__get_default_mtls_endpoint(): [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_info(client_class, transport_name): @@ -111,7 +119,11 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -119,6 +131,7 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) [ (transports.SessionsGrpcTransport, "grpc"), (transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_service_account_always_use_jwt( @@ -144,6 +157,7 @@ def test_sessions_client_service_account_always_use_jwt( [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_file(client_class, transport_name): @@ -164,13 +178,18 @@ def test_sessions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_sessions_client_get_transport_class(): transport = SessionsClient.get_transport_class() available_transports = [ transports.SessionsGrpcTransport, + transports.SessionsRestTransport, ] assert transport in available_transports @@ -183,6 +202,7 @@ def test_sessions_client_get_transport_class(): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -324,6 +344,8 @@ def test_sessions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (SessionsClient, transports.SessionsRestTransport, "rest", "true"), + (SessionsClient, transports.SessionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -513,6 +535,7 @@ def test_sessions_client_get_mtls_endpoint_and_cert_source(client_class): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_client_options_scopes( @@ -548,6 +571,7 @@ def test_sessions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (SessionsClient, transports.SessionsRestTransport, "rest", None), ], ) def test_sessions_client_client_options_credentials_file( @@ -1194,6 +1218,605 @@ async def test_fulfill_intent_field_headers_async(): ) in kw["metadata"] +@pytest.mark.parametrize( + "request_type", + [ + session.DetectIntentRequest, + dict, + ], +) +def test_detect_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/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 = session.DetectIntentResponse( + response_id="response_id_value", + output_audio=b"output_audio_blob", + response_type=session.DetectIntentResponse.ResponseType.PARTIAL, + allow_cancellation=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session.DetectIntentResponse.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.detect_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session.DetectIntentResponse) + assert response.response_id == "response_id_value" + assert response.output_audio == b"output_audio_blob" + assert response.response_type == session.DetectIntentResponse.ResponseType.PARTIAL + assert response.allow_cancellation is True + + +def test_detect_intent_rest_required_fields(request_type=session.DetectIntentRequest): + transport_class = transports.SessionsRestTransport + + request_init = {} + request_init["session"] = "" + 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() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["session"] = "session_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "session" in jsonified_request + assert jsonified_request["session"] == "session_value" + + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session.DetectIntentResponse() + # 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 = session.DetectIntentResponse.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.detect_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_detect_intent_rest_unset_required_fields(): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.detect_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "session", + "queryInput", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_detect_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(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.SessionsRestInterceptor, "post_detect_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_detect_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session.DetectIntentRequest.pb(session.DetectIntentRequest()) + 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 = session.DetectIntentResponse.to_json( + session.DetectIntentResponse() + ) + + request = session.DetectIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session.DetectIntentResponse() + + client.detect_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_detect_intent_rest_bad_request( + transport: str = "rest", request_type=session.DetectIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + 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.detect_intent(request) + + +def test_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_detect_intent_rest_no_http_options(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = session.StreamingDetectIntentRequest() + requests = [request] + with pytest.raises(RuntimeError): + client.streaming_detect_intent(requests) + + +@pytest.mark.parametrize( + "request_type", + [ + session.MatchIntentRequest, + dict, + ], +) +def test_match_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/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 = session.MatchIntentResponse( + text="text_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session.MatchIntentResponse.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.match_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session.MatchIntentResponse) + + +def test_match_intent_rest_required_fields(request_type=session.MatchIntentRequest): + transport_class = transports.SessionsRestTransport + + request_init = {} + request_init["session"] = "" + 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() + ).match_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["session"] = "session_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).match_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "session" in jsonified_request + assert jsonified_request["session"] == "session_value" + + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session.MatchIntentResponse() + # 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 = session.MatchIntentResponse.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.match_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_match_intent_rest_unset_required_fields(): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.match_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "session", + "queryInput", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_match_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(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.SessionsRestInterceptor, "post_match_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_match_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session.MatchIntentRequest.pb(session.MatchIntentRequest()) + 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 = session.MatchIntentResponse.to_json( + session.MatchIntentResponse() + ) + + request = session.MatchIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session.MatchIntentResponse() + + client.match_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_match_intent_rest_bad_request( + transport: str = "rest", request_type=session.MatchIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + 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.match_intent(request) + + +def test_match_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + session.FulfillIntentRequest, + dict, + ], +) +def test_fulfill_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "match_intent_request": { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/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 = session.FulfillIntentResponse( + response_id="response_id_value", + output_audio=b"output_audio_blob", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session.FulfillIntentResponse.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.fulfill_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session.FulfillIntentResponse) + assert response.response_id == "response_id_value" + assert response.output_audio == b"output_audio_blob" + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_fulfill_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(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.SessionsRestInterceptor, "post_fulfill_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_fulfill_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session.FulfillIntentRequest.pb(session.FulfillIntentRequest()) + 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 = session.FulfillIntentResponse.to_json( + session.FulfillIntentResponse() + ) + + request = session.FulfillIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session.FulfillIntentResponse() + + client.fulfill_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_fulfill_intent_rest_bad_request( + transport: str = "rest", request_type=session.FulfillIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "match_intent_request": { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + } + 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.fulfill_intent(request) + + +def test_fulfill_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # Since a `google.api.http` annotation is required for using a rest transport + # method, this should error. + with pytest.raises(NotImplementedError) as not_implemented_error: + client.streaming_detect_intent({}) + assert "Method StreamingDetectIntent is not available over REST transport" in str( + not_implemented_error.value + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.SessionsGrpcTransport( @@ -1275,6 +1898,7 @@ def test_transport_get_channel(): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1289,6 +1913,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1435,6 +2060,7 @@ def test_sessions_transport_auth_adc(transport_class): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_sessions_transport_auth_gdch_credentials(transport_class): @@ -1532,11 +2158,23 @@ def test_sessions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_sessions_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.SessionsRestTransport( + 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_sessions_host_no_port(transport_name): @@ -1547,7 +2185,11 @@ def test_sessions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1555,6 +2197,7 @@ def test_sessions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_sessions_host_with_port(transport_name): @@ -1565,7 +2208,42 @@ def test_sessions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_sessions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.detect_intent._session + session2 = client2.transport.detect_intent._session + assert session1 != session2 + session1 = client1.transport.streaming_detect_intent._session + session2 = client2.transport.streaming_detect_intent._session + assert session1 != session2 + session1 = client1.transport.match_intent._session + session2 = client2.transport.match_intent._session + assert session1 != session2 + session1 = client1.transport.fulfill_intent._session + session2 = client2.transport.fulfill_intent._session + assert session1 != session2 def test_sessions_grpc_transport_channel(): @@ -2105,6 +2783,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2822,6 +3786,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2839,6 +3804,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_test_cases.py b/tests/unit/gapic/dialogflowcx_v3/test_test_cases.py index 65f52552..a63c96c2 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_test_cases.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_test_cases.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 @@ -108,6 +115,7 @@ def test__get_default_mtls_endpoint(): [ (TestCasesClient, "grpc"), (TestCasesAsyncClient, "grpc_asyncio"), + (TestCasesClient, "rest"), ], ) def test_test_cases_client_from_service_account_info(client_class, transport_name): @@ -121,7 +129,11 @@ def test_test_cases_client_from_service_account_info(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -129,6 +141,7 @@ def test_test_cases_client_from_service_account_info(client_class, transport_nam [ (transports.TestCasesGrpcTransport, "grpc"), (transports.TestCasesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.TestCasesRestTransport, "rest"), ], ) def test_test_cases_client_service_account_always_use_jwt( @@ -154,6 +167,7 @@ def test_test_cases_client_service_account_always_use_jwt( [ (TestCasesClient, "grpc"), (TestCasesAsyncClient, "grpc_asyncio"), + (TestCasesClient, "rest"), ], ) def test_test_cases_client_from_service_account_file(client_class, transport_name): @@ -174,13 +188,18 @@ def test_test_cases_client_from_service_account_file(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_test_cases_client_get_transport_class(): transport = TestCasesClient.get_transport_class() available_transports = [ transports.TestCasesGrpcTransport, + transports.TestCasesRestTransport, ] assert transport in available_transports @@ -197,6 +216,7 @@ def test_test_cases_client_get_transport_class(): transports.TestCasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (TestCasesClient, transports.TestCasesRestTransport, "rest"), ], ) @mock.patch.object( @@ -340,6 +360,8 @@ def test_test_cases_client_client_options( "grpc_asyncio", "false", ), + (TestCasesClient, transports.TestCasesRestTransport, "rest", "true"), + (TestCasesClient, transports.TestCasesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -533,6 +555,7 @@ def test_test_cases_client_get_mtls_endpoint_and_cert_source(client_class): transports.TestCasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (TestCasesClient, transports.TestCasesRestTransport, "rest"), ], ) def test_test_cases_client_client_options_scopes( @@ -568,6 +591,7 @@ def test_test_cases_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (TestCasesClient, transports.TestCasesRestTransport, "rest", None), ], ) def test_test_cases_client_client_options_credentials_file( @@ -3543,149 +3567,4113 @@ async def test_get_test_case_result_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.TestCasesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + test_case.ListTestCasesRequest, + dict, + ], +) +def test_list_test_cases_rest(request_type): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = TestCasesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = test_case.ListTestCasesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.TestCasesGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.ListTestCasesResponse.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_test_cases(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCasesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_cases_rest_required_fields( + request_type=test_case.ListTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_cases._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_test_cases._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", + "view", + ) + ) + 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 = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.ListTestCasesResponse() + # 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 = test_case.ListTestCasesResponse.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_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = TestCasesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + "view", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.TestCasesGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = TestCasesClient( - client_options=options, - transport=transport, + client = TestCasesClient(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.TestCasesRestInterceptor, "post_list_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_list_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ListTestCasesRequest.pb(test_case.ListTestCasesRequest()) + 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 = test_case.ListTestCasesResponse.to_json( + test_case.ListTestCasesResponse() ) - # 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 = TestCasesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = test_case.ListTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.ListTestCasesResponse() + + client.list_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.TestCasesGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.ListTestCasesRequest +): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = TestCasesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.TestCasesGrpcTransport( + # 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_test_cases(request) + + +def test_list_test_cases_rest_flattened(): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = TestCasesClient(transport=transport) - assert client.transport is 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 = test_case.ListTestCasesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.TestCasesGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = test_case.ListTestCasesResponse.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_test_cases(**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/v3/{parent=projects/*/locations/*/agents/*}/testCases" + % client.transport._host, + args[1], + ) + + +def test_list_test_cases_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.TestCasesGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_test_cases( + test_case.ListTestCasesRequest(), + parent="parent_value", + ) + + +def test_list_test_cases_rest_pager(transport: str = "rest"): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse( + test_cases=[], + next_page_token="def", + ), + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + ], + next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(test_case.ListTestCasesResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.TestCasesGrpcTransport, - transports.TestCasesGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_test_cases(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCase) for i in results) + + pages = list(client.list_test_cases(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + test_case.BatchDeleteTestCasesRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = TestCasesClient.get_transport_class(transport_name)( +def test_batch_delete_test_cases_rest(request_type): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.batch_delete_test_cases(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_batch_delete_test_cases_rest_required_fields( + request_type=test_case.BatchDeleteTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + request_init = {} + request_init["parent"] = "" + 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 + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_test_cases._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["names"] = "names_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_test_cases._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 "names" in jsonified_request + assert jsonified_request["names"] == "names_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = TestCasesClient( 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": "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 = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.TestCasesGrpcTransport, + + unset_fields = transport.batch_delete_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "names", + ) + ) ) -def test_test_cases_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.TestCasesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "pre_batch_delete_test_cases" + ) as pre: + pre.assert_not_called() + pb_message = test_case.BatchDeleteTestCasesRequest.pb( + test_case.BatchDeleteTestCasesRequest() + ) + 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 = test_case.BatchDeleteTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.batch_delete_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) + pre.assert_called_once() -def test_test_cases_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.test_cases.transports.TestCasesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.TestCasesTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_test_cases", - "batch_delete_test_cases", - "get_test_case", - "create_test_case", - "update_test_case", - "run_test_case", +def test_batch_delete_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.BatchDeleteTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.batch_delete_test_cases(request) + + +def test_batch_delete_test_cases_rest_flattened(): + client = TestCasesClient( + 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 = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_test_cases(**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/v3/{parent=projects/*/locations/*/agents/*}/testCases:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_test_cases_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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.batch_delete_test_cases( + test_case.BatchDeleteTestCasesRequest(), + parent="parent_value", + ) + + +def test_batch_delete_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.GetTestCaseRequest, + dict, + ], +) +def test_get_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/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 = test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.TestCase.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_test_case(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.TestCase) + assert response.name == "name_value" + assert response.tags == ["tags_value"] + assert response.display_name == "display_name_value" + assert response.notes == "notes_value" + + +def test_get_test_case_rest_required_fields(request_type=test_case.GetTestCaseRequest): + transport_class = transports.TestCasesRestTransport + + 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_test_case._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_test_case._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.TestCase() + # 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 = test_case.TestCase.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_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_test_case._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_get_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_get_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.GetTestCaseRequest.pb(test_case.GetTestCaseRequest()) + 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 = test_case.TestCase.to_json(test_case.TestCase()) + + request = test_case.GetTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.TestCase() + + client.get_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_test_case_rest_bad_request( + transport: str = "rest", request_type=test_case.GetTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + 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_test_case(request) + + +def test_get_test_case_rest_flattened(): + client = TestCasesClient( + 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 = test_case.TestCase() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + + # 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 = test_case.TestCase.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_test_case(**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/v3/{name=projects/*/locations/*/agents/*/testCases/*}" + % client.transport._host, + args[1], + ) + + +def test_get_test_case_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case( + test_case.GetTestCaseRequest(), + name="name_value", + ) + + +def test_get_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_test_case.CreateTestCaseRequest, + dict, + ], +) +def test_create_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["test_case"] = { + "name": "name_value", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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 = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_test_case.TestCase.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_test_case(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + assert response.name == "name_value" + assert response.tags == ["tags_value"] + assert response.display_name == "display_name_value" + assert response.notes == "notes_value" + + +def test_create_test_case_rest_required_fields( + request_type=gcdc_test_case.CreateTestCaseRequest, +): + transport_class = transports.TestCasesRestTransport + + 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() + ).create_test_case._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() + ).create_test_case._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_test_case.TestCase() + # 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 = gcdc_test_case.TestCase.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_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_test_case._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "testCase", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_create_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_create_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_test_case.CreateTestCaseRequest.pb( + gcdc_test_case.CreateTestCaseRequest() + ) + 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 = gcdc_test_case.TestCase.to_json( + gcdc_test_case.TestCase() + ) + + request = gcdc_test_case.CreateTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_test_case.TestCase() + + client.create_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_test_case_rest_bad_request( + transport: str = "rest", request_type=gcdc_test_case.CreateTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["test_case"] = { + "name": "name_value", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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_test_case(request) + + +def test_create_test_case_rest_flattened(): + client = TestCasesClient( + 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 = gcdc_test_case.TestCase() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + test_case=gcdc_test_case.TestCase(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 = gcdc_test_case.TestCase.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_test_case(**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/v3/{parent=projects/*/locations/*/agents/*}/testCases" + % client.transport._host, + args[1], + ) + + +def test_create_test_case_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case( + gcdc_test_case.CreateTestCaseRequest(), + parent="parent_value", + test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + +def test_create_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_test_case.UpdateTestCaseRequest, + dict, + ], +) +def test_update_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "test_case": { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + } + request_init["test_case"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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 = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_test_case.TestCase.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_test_case(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + assert response.name == "name_value" + assert response.tags == ["tags_value"] + assert response.display_name == "display_name_value" + assert response.notes == "notes_value" + + +def test_update_test_case_rest_required_fields( + request_type=gcdc_test_case.UpdateTestCaseRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_case._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_test_case._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_test_case.TestCase() + # 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 = gcdc_test_case.TestCase.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_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_test_case._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "testCase", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_update_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_update_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_test_case.UpdateTestCaseRequest.pb( + gcdc_test_case.UpdateTestCaseRequest() + ) + 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 = gcdc_test_case.TestCase.to_json( + gcdc_test_case.TestCase() + ) + + request = gcdc_test_case.UpdateTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_test_case.TestCase() + + client.update_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_test_case_rest_bad_request( + transport: str = "rest", request_type=gcdc_test_case.UpdateTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "test_case": { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + } + request_init["test_case"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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_test_case(request) + + +def test_update_test_case_rest_flattened(): + client = TestCasesClient( + 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 = gcdc_test_case.TestCase() + + # get arguments that satisfy an http rule for this method + sample_request = { + "test_case": { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + test_case=gcdc_test_case.TestCase(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 = gcdc_test_case.TestCase.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_test_case(**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/v3/{test_case.name=projects/*/locations/*/agents/*/testCases/*}" + % client.transport._host, + args[1], + ) + + +def test_update_test_case_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case( + gcdc_test_case.UpdateTestCaseRequest(), + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.RunTestCaseRequest, + dict, + ], +) +def test_run_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/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(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.run_test_case(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_run_test_case_rest_required_fields(request_type=test_case.RunTestCaseRequest): + transport_class = transports.TestCasesRestTransport + + 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() + ).run_test_case._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() + ).run_test_case._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 = TestCasesClient( + 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.run_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_run_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.run_test_case._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_run_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_run_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_run_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.RunTestCaseRequest.pb(test_case.RunTestCaseRequest()) + 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 = test_case.RunTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.run_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_run_test_case_rest_bad_request( + transport: str = "rest", request_type=test_case.RunTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + 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.run_test_case(request) + + +def test_run_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.BatchRunTestCasesRequest, + dict, + ], +) +def test_batch_run_test_cases_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.batch_run_test_cases(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_run_test_cases_rest_required_fields( + request_type=test_case.BatchRunTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["test_cases"] = "" + 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_run_test_cases._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["testCases"] = "test_cases_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_run_test_cases._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 "testCases" in jsonified_request + assert jsonified_request["testCases"] == "test_cases_value" + + client = TestCasesClient( + 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.batch_run_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_run_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_run_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "testCases", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_run_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_batch_run_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_batch_run_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.BatchRunTestCasesRequest.pb( + test_case.BatchRunTestCasesRequest() + ) + 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 = test_case.BatchRunTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_run_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_run_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.BatchRunTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.batch_run_test_cases(request) + + +def test_batch_run_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.CalculateCoverageRequest, + dict, + ], +) +def test_calculate_coverage_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"agent": "projects/sample1/locations/sample2/agents/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 = test_case.CalculateCoverageResponse( + agent="agent_value", + intent_coverage=test_case.IntentCoverage( + intents=[test_case.IntentCoverage.Intent(intent="intent_value")] + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.CalculateCoverageResponse.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.calculate_coverage(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.CalculateCoverageResponse) + assert response.agent == "agent_value" + + +def test_calculate_coverage_rest_required_fields( + request_type=test_case.CalculateCoverageRequest, +): + transport_class = transports.TestCasesRestTransport + + request_init = {} + request_init["agent"] = "" + 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() + ).calculate_coverage._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["agent"] = "agent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).calculate_coverage._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("type_",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "agent" in jsonified_request + assert jsonified_request["agent"] == "agent_value" + + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.CalculateCoverageResponse() + # 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 = test_case.CalculateCoverageResponse.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.calculate_coverage(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_calculate_coverage_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.calculate_coverage._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("type",)) + & set( + ( + "agent", + "type", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_calculate_coverage_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_calculate_coverage" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_calculate_coverage" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.CalculateCoverageRequest.pb( + test_case.CalculateCoverageRequest() + ) + 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 = test_case.CalculateCoverageResponse.to_json( + test_case.CalculateCoverageResponse() + ) + + request = test_case.CalculateCoverageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.CalculateCoverageResponse() + + client.calculate_coverage( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_calculate_coverage_rest_bad_request( + transport: str = "rest", request_type=test_case.CalculateCoverageRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"agent": "projects/sample1/locations/sample2/agents/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.calculate_coverage(request) + + +def test_calculate_coverage_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.ImportTestCasesRequest, + dict, + ], +) +def test_import_test_cases_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.import_test_cases(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_test_cases_rest_required_fields( + request_type=test_case.ImportTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + 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() + ).import_test_cases._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() + ).import_test_cases._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 = TestCasesClient( + 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.import_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_import_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_import_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ImportTestCasesRequest.pb( + test_case.ImportTestCasesRequest() + ) + 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 = test_case.ImportTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.ImportTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.import_test_cases(request) + + +def test_import_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.ExportTestCasesRequest, + dict, + ], +) +def test_export_test_cases_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.export_test_cases(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_test_cases_rest_required_fields( + request_type=test_case.ExportTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + 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() + ).export_test_cases._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_test_cases._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 = TestCasesClient( + 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.export_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_export_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_export_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ExportTestCasesRequest.pb( + test_case.ExportTestCasesRequest() + ) + 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 = test_case.ExportTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.ExportTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.export_test_cases(request) + + +def test_export_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.ListTestCaseResultsRequest, + dict, + ], +) +def test_list_test_case_results_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/testCases/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 = test_case.ListTestCaseResultsResponse( + 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 = test_case.ListTestCaseResultsResponse.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_test_case_results(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCaseResultsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_case_results_rest_required_fields( + request_type=test_case.ListTestCaseResultsRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_case_results._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_test_case_results._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.ListTestCaseResultsResponse() + # 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 = test_case.ListTestCaseResultsResponse.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_test_case_results(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_test_case_results_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_test_case_results._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_test_case_results_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_list_test_case_results" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_list_test_case_results" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ListTestCaseResultsRequest.pb( + test_case.ListTestCaseResultsRequest() + ) + 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 = test_case.ListTestCaseResultsResponse.to_json( + test_case.ListTestCaseResultsResponse() + ) + + request = test_case.ListTestCaseResultsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.ListTestCaseResultsResponse() + + client.list_test_case_results( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_test_case_results_rest_bad_request( + transport: str = "rest", request_type=test_case.ListTestCaseResultsRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + 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_test_case_results(request) + + +def test_list_test_case_results_rest_flattened(): + client = TestCasesClient( + 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 = test_case.ListTestCaseResultsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + + # 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 = test_case.ListTestCaseResultsResponse.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_test_case_results(**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/v3/{parent=projects/*/locations/*/agents/*/testCases/*}/results" + % client.transport._host, + args[1], + ) + + +def test_list_test_case_results_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case_results( + test_case.ListTestCaseResultsRequest(), + parent="parent_value", + ) + + +def test_list_test_case_results_rest_pager(transport: str = "rest"): + client = TestCasesClient( + 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 = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], + next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + ], + next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + test_case.ListTestCaseResultsResponse.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": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + + pager = client.list_test_case_results(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCaseResult) for i in results) + + pages = list(client.list_test_case_results(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", + [ + test_case.GetTestCaseResultRequest, + dict, + ], +) +def test_get_test_case_result_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4/results/sample5" + } + 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 = test_case.TestCaseResult( + name="name_value", + environment="environment_value", + test_result=test_case.TestResult.PASSED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.TestCaseResult.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_test_case_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.TestCaseResult) + assert response.name == "name_value" + assert response.environment == "environment_value" + assert response.test_result == test_case.TestResult.PASSED + + +def test_get_test_case_result_rest_required_fields( + request_type=test_case.GetTestCaseResultRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_case_result._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_test_case_result._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.TestCaseResult() + # 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 = test_case.TestCaseResult.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_test_case_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_test_case_result_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_test_case_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_test_case_result_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_get_test_case_result" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_get_test_case_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.GetTestCaseResultRequest.pb( + test_case.GetTestCaseResultRequest() + ) + 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 = test_case.TestCaseResult.to_json( + test_case.TestCaseResult() + ) + + request = test_case.GetTestCaseResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.TestCaseResult() + + client.get_test_case_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_test_case_result_rest_bad_request( + transport: str = "rest", request_type=test_case.GetTestCaseResultRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4/results/sample5" + } + 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_test_case_result(request) + + +def test_get_test_case_result_rest_flattened(): + client = TestCasesClient( + 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 = test_case.TestCaseResult() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4/results/sample5" + } + + # 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 = test_case.TestCaseResult.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_test_case_result(**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/v3/{name=projects/*/locations/*/agents/*/testCases/*/results/*}" + % client.transport._host, + args[1], + ) + + +def test_get_test_case_result_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case_result( + test_case.GetTestCaseResultRequest(), + name="name_value", + ) + + +def test_get_test_case_result_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = TestCasesClient( + 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 = TestCasesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = TestCasesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TestCasesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TestCasesGrpcTransport, + transports.TestCasesGrpcAsyncIOTransport, + transports.TestCasesRestTransport, + ], +) +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 = TestCasesClient.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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.TestCasesGrpcTransport, + ) + + +def test_test_cases_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.TestCasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_test_cases_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.test_cases.transports.TestCasesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TestCasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_test_cases", + "batch_delete_test_cases", + "get_test_case", + "create_test_case", + "update_test_case", + "run_test_case", "batch_run_test_cases", "calculate_coverage", "import_test_cases", @@ -3797,6 +7785,7 @@ def test_test_cases_transport_auth_adc(transport_class): [ transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport, + transports.TestCasesRestTransport, ], ) def test_test_cases_transport_auth_gdch_credentials(transport_class): @@ -3894,11 +7883,40 @@ def test_test_cases_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_test_cases_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.TestCasesRestTransport( + 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_test_cases_rest_lro_client(): + client = TestCasesClient( + 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_test_cases_host_no_port(transport_name): @@ -3909,7 +7927,11 @@ def test_test_cases_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3917,6 +7939,7 @@ def test_test_cases_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_test_cases_host_with_port(transport_name): @@ -3927,7 +7950,66 @@ def test_test_cases_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_test_cases_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = TestCasesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = TestCasesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_test_cases._session + session2 = client2.transport.list_test_cases._session + assert session1 != session2 + session1 = client1.transport.batch_delete_test_cases._session + session2 = client2.transport.batch_delete_test_cases._session + assert session1 != session2 + session1 = client1.transport.get_test_case._session + session2 = client2.transport.get_test_case._session + assert session1 != session2 + session1 = client1.transport.create_test_case._session + session2 = client2.transport.create_test_case._session + assert session1 != session2 + session1 = client1.transport.update_test_case._session + session2 = client2.transport.update_test_case._session + assert session1 != session2 + session1 = client1.transport.run_test_case._session + session2 = client2.transport.run_test_case._session + assert session1 != session2 + session1 = client1.transport.batch_run_test_cases._session + session2 = client2.transport.batch_run_test_cases._session + assert session1 != session2 + session1 = client1.transport.calculate_coverage._session + session2 = client2.transport.calculate_coverage._session + assert session1 != session2 + session1 = client1.transport.import_test_cases._session + session2 = client2.transport.import_test_cases._session + assert session1 != session2 + session1 = client1.transport.export_test_cases._session + session2 = client2.transport.export_test_cases._session + assert session1 != session2 + session1 = client1.transport.list_test_case_results._session + session2 = client2.transport.list_test_case_results._session + assert session1 != session2 + session1 = client1.transport.get_test_case_result._session + session2 = client2.transport.get_test_case_result._session + assert session1 != session2 def test_test_cases_grpc_transport_channel(): @@ -4524,6 +8606,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -5241,6 +9609,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -5258,6 +9627,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py b/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py index b911828a..47473728 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.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 @@ -110,6 +117,7 @@ def test__get_default_mtls_endpoint(): [ (TransitionRouteGroupsClient, "grpc"), (TransitionRouteGroupsAsyncClient, "grpc_asyncio"), + (TransitionRouteGroupsClient, "rest"), ], ) def test_transition_route_groups_client_from_service_account_info( @@ -125,7 +133,11 @@ def test_transition_route_groups_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -133,6 +145,7 @@ def test_transition_route_groups_client_from_service_account_info( [ (transports.TransitionRouteGroupsGrpcTransport, "grpc"), (transports.TransitionRouteGroupsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.TransitionRouteGroupsRestTransport, "rest"), ], ) def test_transition_route_groups_client_service_account_always_use_jwt( @@ -158,6 +171,7 @@ def test_transition_route_groups_client_service_account_always_use_jwt( [ (TransitionRouteGroupsClient, "grpc"), (TransitionRouteGroupsAsyncClient, "grpc_asyncio"), + (TransitionRouteGroupsClient, "rest"), ], ) def test_transition_route_groups_client_from_service_account_file( @@ -180,13 +194,18 @@ def test_transition_route_groups_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_transition_route_groups_client_get_transport_class(): transport = TransitionRouteGroupsClient.get_transport_class() available_transports = [ transports.TransitionRouteGroupsGrpcTransport, + transports.TransitionRouteGroupsRestTransport, ] assert transport in available_transports @@ -207,6 +226,11 @@ def test_transition_route_groups_client_get_transport_class(): transports.TransitionRouteGroupsGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -362,6 +386,18 @@ def test_transition_route_groups_client_client_options( "grpc_asyncio", "false", ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + "true", + ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -565,6 +601,11 @@ def test_transition_route_groups_client_get_mtls_endpoint_and_cert_source(client transports.TransitionRouteGroupsGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + ), ], ) def test_transition_route_groups_client_client_options_scopes( @@ -605,6 +646,12 @@ def test_transition_route_groups_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + None, + ), ], ) def test_transition_route_groups_client_client_options_credentials_file( @@ -2204,208 +2251,2050 @@ async def test_delete_transition_route_group_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + transition_route_group.ListTransitionRouteGroupsRequest, + dict, + ], +) +def test_list_transition_route_groups_rest(request_type): + client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - 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 = transition_route_group.ListTransitionRouteGroupsResponse( + next_page_token="next_page_token_value", ) - # 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 = TransitionRouteGroupsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = transition_route_group.ListTransitionRouteGroupsResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_transition_route_groups(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTransitionRouteGroupsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_transition_route_groups_rest_required_fields( + request_type=transition_route_group.ListTransitionRouteGroupsRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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, + ) ) - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_transition_route_groups._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_transition_route_groups._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( + client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = TransitionRouteGroupsClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = transition_route_group.ListTransitionRouteGroupsResponse() + # 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 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = ( + transition_route_group.ListTransitionRouteGroupsResponse.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_transition_route_groups(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_transition_route_groups_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.TransitionRouteGroupsGrpcAsyncIOTransport( + unset_fields = transport.list_transition_route_groups._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_transition_route_groups_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_list_transition_route_groups", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_list_transition_route_groups", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = transition_route_group.ListTransitionRouteGroupsRequest.pb( + transition_route_group.ListTransitionRouteGroupsRequest() + ) + 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 = ( + transition_route_group.ListTransitionRouteGroupsResponse.to_json( + transition_route_group.ListTransitionRouteGroupsResponse() + ) + ) + request = transition_route_group.ListTransitionRouteGroupsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = transition_route_group.ListTransitionRouteGroupsResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.TransitionRouteGroupsGrpcTransport, - transports.TransitionRouteGroupsGrpcAsyncIOTransport, - ], -) -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() + client.list_transition_route_groups( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = TransitionRouteGroupsClient.get_transport_class(transport_name)( + +def test_list_transition_route_groups_rest_bad_request( + transport: str = "rest", + request_type=transition_route_group.ListTransitionRouteGroupsRequest, +): + client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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_transition_route_groups(request) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + +def test_list_transition_route_groups_rest_flattened(): client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.TransitionRouteGroupsGrpcTransport, + 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 = transition_route_group.ListTransitionRouteGroupsResponse() -def test_transition_route_groups_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.TransitionRouteGroupsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) -def test_transition_route_groups_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.transition_route_groups.transports.TransitionRouteGroupsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.TransitionRouteGroupsTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = transition_route_group.ListTransitionRouteGroupsResponse.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 - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_transition_route_groups", - "get_transition_route_group", - "create_transition_route_group", - "update_transition_route_group", - "delete_transition_route_group", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + client.list_transition_route_groups(**mock_args) - with pytest.raises(NotImplementedError): - transport.close() + # 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/v3/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups" + % client.transport._host, + args[1], + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_transition_route_groups_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_transition_route_groups_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.dialogflowcx_v3.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.TransitionRouteGroupsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_transition_route_groups( + transition_route_group.ListTransitionRouteGroupsRequest(), + parent="parent_value", ) -def test_transition_route_groups_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.dialogflowcx_v3.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.TransitionRouteGroupsTransport() - adc.assert_called_once() - +def test_list_transition_route_groups_rest_pager(transport: str = "rest"): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_transition_route_groups_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: + # 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 = ( + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[ + transition_route_group.TransitionRouteGroup(), + transition_route_group.TransitionRouteGroup(), + transition_route_group.TransitionRouteGroup(), + ], + next_page_token="abc", + ), + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[], + next_page_token="def", + ), + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[ + transition_route_group.TransitionRouteGroup(), + ], + next_page_token="ghi", + ), + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[ + transition_route_group.TransitionRouteGroup(), + transition_route_group.TransitionRouteGroup(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + transition_route_group.ListTransitionRouteGroupsResponse.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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + pager = client.list_transition_route_groups(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, transition_route_group.TransitionRouteGroup) for i in results + ) + + pages = list(client.list_transition_route_groups(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", + [ + transition_route_group.GetTransitionRouteGroupRequest, + dict, + ], +) +def test_get_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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 = transition_route_group.TransitionRouteGroup( + name="name_value", + display_name="display_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, transition_route_group.TransitionRouteGroup) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + + +def test_get_transition_route_group_rest_required_fields( + request_type=transition_route_group.GetTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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_transition_route_group._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_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = transition_route_group.TransitionRouteGroup() + # 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 = transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_transition_route_group._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_get_transition_route_group", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_get_transition_route_group", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = transition_route_group.GetTransitionRouteGroupRequest.pb( + transition_route_group.GetTransitionRouteGroupRequest() + ) + 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 = transition_route_group.TransitionRouteGroup.to_json( + transition_route_group.TransitionRouteGroup() + ) + + request = transition_route_group.GetTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = transition_route_group.TransitionRouteGroup() + + client.get_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=transition_route_group.GetTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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_transition_route_group(request) + + +def test_get_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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 = transition_route_group.TransitionRouteGroup() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + + # 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 = transition_route_group.TransitionRouteGroup.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_transition_route_group(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}" + % client.transport._host, + args[1], + ) + + +def test_get_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + transition_route_group.GetTransitionRouteGroupRequest(), + name="name_value", + ) + + +def test_get_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + dict, + ], +) +def test_create_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["transition_route_group"] = { + "name": "name_value", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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 = gcdc_transition_route_group.TransitionRouteGroup( + name="name_value", + display_name="display_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_transition_route_group.TransitionRouteGroup) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + + +def test_create_transition_route_group_rest_required_fields( + request_type=gcdc_transition_route_group.CreateTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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() + ).create_transition_route_group._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() + ).create_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_transition_route_group.TransitionRouteGroup() + # 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_transition_route_group._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "transitionRouteGroup", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_create_transition_route_group", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_create_transition_route_group", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_transition_route_group.CreateTransitionRouteGroupRequest.pb( + gcdc_transition_route_group.CreateTransitionRouteGroupRequest() + ) + 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 = ( + gcdc_transition_route_group.TransitionRouteGroup.to_json( + gcdc_transition_route_group.TransitionRouteGroup() + ) + ) + + request = gcdc_transition_route_group.CreateTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_transition_route_group.TransitionRouteGroup() + + client.create_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=gcdc_transition_route_group.CreateTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["transition_route_group"] = { + "name": "name_value", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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_transition_route_group(request) + + +def test_create_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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 = gcdc_transition_route_group.TransitionRouteGroup() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(**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/v3/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups" + % client.transport._host, + args[1], + ) + + +def test_create_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + gcdc_transition_route_group.CreateTransitionRouteGroupRequest(), + parent="parent_value", + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + name="name_value" + ), + ) + + +def test_create_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + dict, + ], +) +def test_update_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "transition_route_group": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + } + request_init["transition_route_group"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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 = gcdc_transition_route_group.TransitionRouteGroup( + name="name_value", + display_name="display_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_transition_route_group.TransitionRouteGroup) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + + +def test_update_transition_route_group_rest_required_fields( + request_type=gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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_transition_route_group._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_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_transition_route_group.TransitionRouteGroup() + # 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_transition_route_group._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("transitionRouteGroup",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_update_transition_route_group", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_update_transition_route_group", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_transition_route_group.UpdateTransitionRouteGroupRequest.pb( + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest() + ) + 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 = ( + gcdc_transition_route_group.TransitionRouteGroup.to_json( + gcdc_transition_route_group.TransitionRouteGroup() + ) + ) + + request = gcdc_transition_route_group.UpdateTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_transition_route_group.TransitionRouteGroup() + + client.update_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "transition_route_group": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + } + request_init["transition_route_group"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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_transition_route_group(request) + + +def test_update_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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 = gcdc_transition_route_group.TransitionRouteGroup() + + # get arguments that satisfy an http rule for this method + sample_request = { + "transition_route_group": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(**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/v3/{transition_route_group.name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}" + % client.transport._host, + args[1], + ) + + +def test_update_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest(), + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + transition_route_group.DeleteTransitionRouteGroupRequest, + dict, + ], +) +def test_delete_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_transition_route_group_rest_required_fields( + request_type=transition_route_group.DeleteTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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_transition_route_group._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_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = TransitionRouteGroupsClient( + 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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_transition_route_group._get_unset_required_fields( + {} + ) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "pre_delete_transition_route_group", + ) as pre: + pre.assert_not_called() + pb_message = transition_route_group.DeleteTransitionRouteGroupRequest.pb( + transition_route_group.DeleteTransitionRouteGroupRequest() + ) + 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 = transition_route_group.DeleteTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=transition_route_group.DeleteTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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_transition_route_group(request) + + +def test_delete_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + + # 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_transition_route_group(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + transition_route_group.DeleteTransitionRouteGroupRequest(), + name="name_value", + ) + + +def test_delete_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + 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 = TransitionRouteGroupsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = TransitionRouteGroupsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TransitionRouteGroupsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TransitionRouteGroupsGrpcTransport, + transports.TransitionRouteGroupsGrpcAsyncIOTransport, + transports.TransitionRouteGroupsRestTransport, + ], +) +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 = TransitionRouteGroupsClient.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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.TransitionRouteGroupsGrpcTransport, + ) + + +def test_transition_route_groups_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.TransitionRouteGroupsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_transition_route_groups_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.transition_route_groups.transports.TransitionRouteGroupsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TransitionRouteGroupsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_transition_route_groups", + "get_transition_route_group", + "create_transition_route_group", + "update_transition_route_group", + "delete_transition_route_group", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_transition_route_groups_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.dialogflowcx_v3.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TransitionRouteGroupsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_transition_route_groups_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.dialogflowcx_v3.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TransitionRouteGroupsTransport() + adc.assert_called_once() + + +def test_transition_route_groups_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) TransitionRouteGroupsClient() adc.assert_called_once_with( @@ -2446,6 +4335,7 @@ def test_transition_route_groups_transport_auth_adc(transport_class): [ transports.TransitionRouteGroupsGrpcTransport, transports.TransitionRouteGroupsGrpcAsyncIOTransport, + transports.TransitionRouteGroupsRestTransport, ], ) def test_transition_route_groups_transport_auth_gdch_credentials(transport_class): @@ -2550,11 +4440,23 @@ def test_transition_route_groups_grpc_transport_client_cert_source_for_mtls( ) +def test_transition_route_groups_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.TransitionRouteGroupsRestTransport( + 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_transition_route_groups_host_no_port(transport_name): @@ -2565,7 +4467,11 @@ def test_transition_route_groups_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2573,6 +4479,7 @@ def test_transition_route_groups_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_transition_route_groups_host_with_port(transport_name): @@ -2583,7 +4490,45 @@ def test_transition_route_groups_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_transition_route_groups_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = TransitionRouteGroupsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = TransitionRouteGroupsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_transition_route_groups._session + session2 = client2.transport.list_transition_route_groups._session + assert session1 != session2 + session1 = client1.transport.get_transition_route_group._session + session2 = client2.transport.get_transition_route_group._session + assert session1 != session2 + session1 = client1.transport.create_transition_route_group._session + session2 = client2.transport.create_transition_route_group._session + assert session1 != session2 + session1 = client1.transport.update_transition_route_group._session + session2 = client2.transport.update_transition_route_group._session + assert session1 != session2 + session1 = client1.transport.delete_transition_route_group._session + session2 = client2.transport.delete_transition_route_group._session + assert session1 != session2 def test_transition_route_groups_grpc_transport_channel(): @@ -3007,6 +4952,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3728,6 +5959,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3745,6 +5977,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_versions.py b/tests/unit/gapic/dialogflowcx_v3/test_versions.py index 1859b272..452c887d 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_versions.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_versions.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 @@ -102,6 +109,7 @@ def test__get_default_mtls_endpoint(): [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_info(client_class, transport_name): @@ -115,7 +123,11 @@ def test_versions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -123,6 +135,7 @@ def test_versions_client_from_service_account_info(client_class, transport_name) [ (transports.VersionsGrpcTransport, "grpc"), (transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_service_account_always_use_jwt( @@ -148,6 +161,7 @@ def test_versions_client_service_account_always_use_jwt( [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_file(client_class, transport_name): @@ -168,13 +182,18 @@ def test_versions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_versions_client_get_transport_class(): transport = VersionsClient.get_transport_class() available_transports = [ transports.VersionsGrpcTransport, + transports.VersionsRestTransport, ] assert transport in available_transports @@ -187,6 +206,7 @@ def test_versions_client_get_transport_class(): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -328,6 +348,8 @@ def test_versions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (VersionsClient, transports.VersionsRestTransport, "rest", "true"), + (VersionsClient, transports.VersionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -517,6 +539,7 @@ def test_versions_client_get_mtls_endpoint_and_cert_source(client_class): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_client_options_scopes( @@ -552,6 +575,7 @@ def test_versions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (VersionsClient, transports.VersionsRestTransport, "rest", None), ], ) def test_versions_client_client_options_credentials_file( @@ -2492,141 +2516,2173 @@ async def test_compare_versions_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.VersionsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + version.ListVersionsRequest, + dict, + ], +) +def test_list_versions_rest(request_type): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/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 = version.ListVersionsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.VersionsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.ListVersionsResponse.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_versions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListVersionsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_versions_rest_required_fields(request_type=version.ListVersionsRequest): + transport_class = transports.VersionsRestTransport + + 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_versions._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_versions._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", + ) + ) + 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 = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse() + # 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 = version.ListVersionsResponse.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_versions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_versions_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_versions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.VersionsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_versions_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = VersionsClient( - client_options=options, - transport=transport, + client = VersionsClient(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.VersionsRestInterceptor, "post_list_versions" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_list_versions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.ListVersionsRequest.pb(version.ListVersionsRequest()) + 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 = version.ListVersionsResponse.to_json( + version.ListVersionsResponse() ) - # 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 = VersionsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = version.ListVersionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.ListVersionsResponse() + + client.list_versions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.VersionsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_versions_rest_bad_request( + transport: str = "rest", request_type=version.ListVersionsRequest +): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # 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_versions(request) + + +def test_list_versions_rest_flattened(): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = VersionsClient(transport=transport) - assert client.transport is 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 = version.ListVersionsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = version.ListVersionsResponse.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_versions(**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/v3/{parent=projects/*/locations/*/agents/*/flows/*}/versions" + % client.transport._host, + args[1], + ) + + +def test_list_versions_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.VersionsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_versions( + version.ListVersionsRequest(), + parent="parent_value", + ) + + +def test_list_versions_rest_pager(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + version.Version(), + ], + next_page_token="abc", + ), + version.ListVersionsResponse( + versions=[], + next_page_token="def", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + ], + next_page_token="ghi", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(version.ListVersionsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.VersionsGrpcTransport, - transports.VersionsGrpcAsyncIOTransport, - ], -) -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() + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + pager = client.list_versions(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, version.Version) for i in results) + + pages = list(client.list_versions(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + version.GetVersionRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = VersionsClient.get_transport_class(transport_name)( +def test_get_version_rest(request_type): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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 = version.Version( + name="name_value", + display_name="display_name_value", + description="description_value", + state=version.Version.State.RUNNING, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.Version.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_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, version.Version) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == version.Version.State.RUNNING + + +def test_get_version_rest_required_fields(request_type=version.GetVersionRequest): + transport_class = transports.VersionsRestTransport + + 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_version._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_version._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" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.VersionsGrpcTransport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.Version() + # 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 = version.Version.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_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_versions_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_get_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_get_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.GetVersionRequest.pb(version.GetVersionRequest()) + 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 = version.Version.to_json(version.Version()) + + request = version.GetVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.Version() -def test_versions_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.versions.transports.VersionsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.get_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly + pre.assert_called_once() + post.assert_called_once() + + +def test_get_version_rest_bad_request( + transport: str = "rest", request_type=version.GetVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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_version(request) + + +def test_get_version_rest_flattened(): + client = VersionsClient( + 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 = version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # 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 = version.Version.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_version(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_get_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + version.GetVersionRequest(), + name="name_value", + ) + + +def test_get_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_version.CreateVersionRequest, + dict, + ], +) +def test_create_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["version"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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.create_version(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_version_rest_required_fields( + request_type=gcdc_version.CreateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + 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() + ).create_version._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() + ).create_version._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 = VersionsClient( + 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.create_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "version", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_create_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_create_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_version.CreateVersionRequest.pb( + gcdc_version.CreateVersionRequest() + ) + 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 = gcdc_version.CreateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_version_rest_bad_request( + transport: str = "rest", request_type=gcdc_version.CreateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["version"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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_version(request) + + +def test_create_version_rest_flattened(): + client = VersionsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + version=gcdc_version.Version(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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_version(**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/v3/{parent=projects/*/locations/*/agents/*/flows/*}/versions" + % client.transport._host, + args[1], + ) + + +def test_create_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + gcdc_version.CreateVersionRequest(), + parent="parent_value", + version=gcdc_version.Version(name="name_value"), + ) + + +def test_create_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_version.UpdateVersionRequest, + dict, + ], +) +def test_update_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "version": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + } + request_init["version"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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 = gcdc_version.Version( + name="name_value", + display_name="display_name_value", + description="description_value", + state=gcdc_version.Version.State.RUNNING, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_version.Version.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_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_version.Version) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == gcdc_version.Version.State.RUNNING + + +def test_update_version_rest_required_fields( + request_type=gcdc_version.UpdateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + 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_version._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_version._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 = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_version.Version() + # 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 = gcdc_version.Version.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_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "version", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_update_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_update_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_version.UpdateVersionRequest.pb( + gcdc_version.UpdateVersionRequest() + ) + 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 = gcdc_version.Version.to_json(gcdc_version.Version()) + + request = gcdc_version.UpdateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_version.Version() + + client.update_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_version_rest_bad_request( + transport: str = "rest", request_type=gcdc_version.UpdateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "version": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + } + request_init["version"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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_version(request) + + +def test_update_version_rest_flattened(): + client = VersionsClient( + 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 = gcdc_version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = { + "version": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + version=gcdc_version.Version(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 = gcdc_version.Version.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_version(**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/v3/{version.name=projects/*/locations/*/agents/*/flows/*/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_update_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + gcdc_version.UpdateVersionRequest(), + version=gcdc_version.Version(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.DeleteVersionRequest, + dict, + ], +) +def test_delete_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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_version(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_version_rest_required_fields(request_type=version.DeleteVersionRequest): + transport_class = transports.VersionsRestTransport + + 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_version._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_version._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 = VersionsClient( + 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_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "pre_delete_version" + ) as pre: + pre.assert_not_called() + pb_message = version.DeleteVersionRequest.pb(version.DeleteVersionRequest()) + 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 = version.DeleteVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_version_rest_bad_request( + transport: str = "rest", request_type=version.DeleteVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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_version(request) + + +def test_delete_version_rest_flattened(): + client = VersionsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # 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_version(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + version.DeleteVersionRequest(), + name="name_value", + ) + + +def test_delete_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.LoadVersionRequest, + dict, + ], +) +def test_load_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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.load_version(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_load_version_rest_required_fields(request_type=version.LoadVersionRequest): + transport_class = transports.VersionsRestTransport + + 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() + ).load_version._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() + ).load_version._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 = VersionsClient( + 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.load_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_load_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.load_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_load_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_load_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_load_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.LoadVersionRequest.pb(version.LoadVersionRequest()) + 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 = version.LoadVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.load_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_load_version_rest_bad_request( + transport: str = "rest", request_type=version.LoadVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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.load_version(request) + + +def test_load_version_rest_flattened(): + client = VersionsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # 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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.load_version(**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/v3/{name=projects/*/locations/*/agents/*/flows/*/versions/*}:load" + % client.transport._host, + args[1], + ) + + +def test_load_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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.load_version( + version.LoadVersionRequest(), + name="name_value", + ) + + +def test_load_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.CompareVersionsRequest, + dict, + ], +) +def test_compare_versions_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "base_version": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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 = version.CompareVersionsResponse( + base_version_content_json="base_version_content_json_value", + target_version_content_json="target_version_content_json_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.CompareVersionsResponse.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.compare_versions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, version.CompareVersionsResponse) + assert response.base_version_content_json == "base_version_content_json_value" + assert response.target_version_content_json == "target_version_content_json_value" + + +def test_compare_versions_rest_required_fields( + request_type=version.CompareVersionsRequest, +): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["base_version"] = "" + request_init["target_version"] = "" + 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() + ).compare_versions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["baseVersion"] = "base_version_value" + jsonified_request["targetVersion"] = "target_version_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).compare_versions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "baseVersion" in jsonified_request + assert jsonified_request["baseVersion"] == "base_version_value" + assert "targetVersion" in jsonified_request + assert jsonified_request["targetVersion"] == "target_version_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.CompareVersionsResponse() + # 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 = version.CompareVersionsResponse.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.compare_versions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_compare_versions_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.compare_versions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "baseVersion", + "targetVersion", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_compare_versions_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_compare_versions" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_compare_versions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.CompareVersionsRequest.pb(version.CompareVersionsRequest()) + 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 = version.CompareVersionsResponse.to_json( + version.CompareVersionsResponse() + ) + + request = version.CompareVersionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.CompareVersionsResponse() + + client.compare_versions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_compare_versions_rest_bad_request( + transport: str = "rest", request_type=version.CompareVersionsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "base_version": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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.compare_versions(request) + + +def test_compare_versions_rest_flattened(): + client = VersionsClient( + 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 = version.CompareVersionsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "base_version": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # get truthy value for each flattened field + mock_args = dict( + base_version="base_version_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 = version.CompareVersionsResponse.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.compare_versions(**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/v3/{base_version=projects/*/locations/*/agents/*/flows/*/versions/*}:compareVersions" + % client.transport._host, + args[1], + ) + + +def test_compare_versions_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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.compare_versions( + version.CompareVersionsRequest(), + base_version="base_version_value", + ) + + +def test_compare_versions_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = VersionsClient( + 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 = VersionsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = VersionsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.VersionsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.VersionsGrpcTransport, + transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, + ], +) +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 = VersionsClient.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 = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.VersionsGrpcTransport, + ) + + +def test_versions_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_versions_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.versions.transports.VersionsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly # raise NotImplementedError. methods = ( "list_versions", @@ -2741,6 +4797,7 @@ def test_versions_transport_auth_adc(transport_class): [ transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, ], ) def test_versions_transport_auth_gdch_credentials(transport_class): @@ -2838,11 +4895,40 @@ def test_versions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_versions_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.VersionsRestTransport( + 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_versions_rest_lro_client(): + client = VersionsClient( + 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_versions_host_no_port(transport_name): @@ -2853,7 +4939,11 @@ def test_versions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2861,6 +4951,7 @@ def test_versions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_versions_host_with_port(transport_name): @@ -2871,7 +4962,51 @@ def test_versions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_versions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = VersionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = VersionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_versions._session + session2 = client2.transport.list_versions._session + assert session1 != session2 + session1 = client1.transport.get_version._session + session2 = client2.transport.get_version._session + assert session1 != session2 + session1 = client1.transport.create_version._session + session2 = client2.transport.create_version._session + assert session1 != session2 + session1 = client1.transport.update_version._session + session2 = client2.transport.update_version._session + assert session1 != session2 + session1 = client1.transport.delete_version._session + session2 = client2.transport.delete_version._session + assert session1 != session2 + session1 = client1.transport.load_version._session + session2 = client2.transport.load_version._session + assert session1 != session2 + session1 = client1.transport.compare_versions._session + session2 = client2.transport.compare_versions._session + assert session1 != session2 def test_versions_grpc_transport_channel(): @@ -3198,6 +5333,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3915,6 +6336,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3932,6 +6354,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3/test_webhooks.py b/tests/unit/gapic/dialogflowcx_v3/test_webhooks.py index 957ef01e..29174865 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_webhooks.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_webhooks.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 @@ -95,6 +102,7 @@ def test__get_default_mtls_endpoint(): [ (WebhooksClient, "grpc"), (WebhooksAsyncClient, "grpc_asyncio"), + (WebhooksClient, "rest"), ], ) def test_webhooks_client_from_service_account_info(client_class, transport_name): @@ -108,7 +116,11 @@ def test_webhooks_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +128,7 @@ def test_webhooks_client_from_service_account_info(client_class, transport_name) [ (transports.WebhooksGrpcTransport, "grpc"), (transports.WebhooksGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.WebhooksRestTransport, "rest"), ], ) def test_webhooks_client_service_account_always_use_jwt( @@ -141,6 +154,7 @@ def test_webhooks_client_service_account_always_use_jwt( [ (WebhooksClient, "grpc"), (WebhooksAsyncClient, "grpc_asyncio"), + (WebhooksClient, "rest"), ], ) def test_webhooks_client_from_service_account_file(client_class, transport_name): @@ -161,13 +175,18 @@ def test_webhooks_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_webhooks_client_get_transport_class(): transport = WebhooksClient.get_transport_class() available_transports = [ transports.WebhooksGrpcTransport, + transports.WebhooksRestTransport, ] assert transport in available_transports @@ -180,6 +199,7 @@ def test_webhooks_client_get_transport_class(): [ (WebhooksClient, transports.WebhooksGrpcTransport, "grpc"), (WebhooksAsyncClient, transports.WebhooksGrpcAsyncIOTransport, "grpc_asyncio"), + (WebhooksClient, transports.WebhooksRestTransport, "rest"), ], ) @mock.patch.object( @@ -321,6 +341,8 @@ def test_webhooks_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (WebhooksClient, transports.WebhooksRestTransport, "rest", "true"), + (WebhooksClient, transports.WebhooksRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -510,6 +532,7 @@ def test_webhooks_client_get_mtls_endpoint_and_cert_source(client_class): [ (WebhooksClient, transports.WebhooksGrpcTransport, "grpc"), (WebhooksAsyncClient, transports.WebhooksGrpcAsyncIOTransport, "grpc_asyncio"), + (WebhooksClient, transports.WebhooksRestTransport, "rest"), ], ) def test_webhooks_client_client_options_scopes( @@ -545,6 +568,7 @@ def test_webhooks_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (WebhooksClient, transports.WebhooksRestTransport, "rest", None), ], ) def test_webhooks_client_client_options_credentials_file( @@ -2032,171 +2056,1648 @@ async def test_delete_webhook_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.WebhooksGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + webhook.ListWebhooksRequest, + dict, + ], +) +def test_list_webhooks_rest(request_type): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = WebhooksClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = webhook.ListWebhooksResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.WebhooksGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = webhook.ListWebhooksResponse.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_webhooks(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListWebhooksPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_webhooks_rest_required_fields(request_type=webhook.ListWebhooksRequest): + transport_class = transports.WebhooksRestTransport + + 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_webhooks._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_webhooks._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", + ) + ) + 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 = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = WebhooksClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = webhook.ListWebhooksResponse() + # 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 = webhook.ListWebhooksResponse.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_webhooks(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_webhooks_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_webhooks._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.WebhooksGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_webhooks_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = WebhooksClient( - client_options=options, - transport=transport, + client = WebhooksClient(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.WebhooksRestInterceptor, "post_list_webhooks" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_list_webhooks" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = webhook.ListWebhooksRequest.pb(webhook.ListWebhooksRequest()) + 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 = webhook.ListWebhooksResponse.to_json( + webhook.ListWebhooksResponse() ) - # 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 = WebhooksClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = webhook.ListWebhooksRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = webhook.ListWebhooksResponse() + + client.list_webhooks( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.WebhooksGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_webhooks_rest_bad_request( + transport: str = "rest", request_type=webhook.ListWebhooksRequest +): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = WebhooksClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.WebhooksGrpcTransport( + # 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_webhooks(request) + + +def test_list_webhooks_rest_flattened(): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = WebhooksClient(transport=transport) - assert client.transport is 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 = webhook.ListWebhooksResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.WebhooksGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = webhook.ListWebhooksResponse.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_webhooks(**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/v3/{parent=projects/*/locations/*/agents/*}/webhooks" + % client.transport._host, + args[1], + ) + + +def test_list_webhooks_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.WebhooksGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_webhooks( + webhook.ListWebhooksRequest(), + parent="parent_value", + ) + + +def test_list_webhooks_rest_pager(transport: str = "rest"): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + webhook.ListWebhooksResponse( + webhooks=[ + webhook.Webhook(), + webhook.Webhook(), + webhook.Webhook(), + ], + next_page_token="abc", + ), + webhook.ListWebhooksResponse( + webhooks=[], + next_page_token="def", + ), + webhook.ListWebhooksResponse( + webhooks=[ + webhook.Webhook(), + ], + next_page_token="ghi", + ), + webhook.ListWebhooksResponse( + webhooks=[ + webhook.Webhook(), + webhook.Webhook(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(webhook.ListWebhooksResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.WebhooksGrpcTransport, - transports.WebhooksGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_webhooks(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, webhook.Webhook) for i in results) + + pages = list(client.list_webhooks(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + webhook.GetWebhookRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = WebhooksClient.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_webhook_rest(request_type): client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.WebhooksGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + request = request_type(**request_init) -def test_webhooks_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.WebhooksTransport( - 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 = webhook.Webhook( + name="name_value", + display_name="display_name_value", + disabled=True, + generic_web_service=webhook.Webhook.GenericWebService(uri="uri_value"), ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = webhook.Webhook.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_webhooks_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3.services.webhooks.transports.WebhooksTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.WebhooksTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_webhook(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_webhooks", - "get_webhook", - "create_webhook", - "update_webhook", - "delete_webhook", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, webhook.Webhook) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.disabled is True + + +def test_get_webhook_rest_required_fields(request_type=webhook.GetWebhookRequest): + transport_class = transports.WebhooksRestTransport + + 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, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_webhook._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_webhooks_base_transport_with_credentials_file(): + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_webhook._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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = webhook.Webhook() + # 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 = webhook.Webhook.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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_webhook._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "post_get_webhook" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_get_webhook" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = webhook.GetWebhookRequest.pb(webhook.GetWebhookRequest()) + 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 = webhook.Webhook.to_json(webhook.Webhook()) + + request = webhook.GetWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = webhook.Webhook() + + client.get_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_webhook_rest_bad_request( + transport: str = "rest", request_type=webhook.GetWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + 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_webhook(request) + + +def test_get_webhook_rest_flattened(): + client = WebhooksClient( + 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 = webhook.Webhook() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + + # 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 = webhook.Webhook.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_webhook(**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/v3/{name=projects/*/locations/*/agents/*/webhooks/*}" + % client.transport._host, + args[1], + ) + + +def test_get_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + webhook.GetWebhookRequest(), + name="name_value", + ) + + +def test_get_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_webhook.CreateWebhookRequest, + dict, + ], +) +def test_create_webhook_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["webhook"] = { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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 = gcdc_webhook.Webhook( + name="name_value", + display_name="display_name_value", + disabled=True, + generic_web_service=gcdc_webhook.Webhook.GenericWebService(uri="uri_value"), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_webhook.Webhook.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_webhook(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_webhook.Webhook) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.disabled is True + + +def test_create_webhook_rest_required_fields( + request_type=gcdc_webhook.CreateWebhookRequest, +): + transport_class = transports.WebhooksRestTransport + + 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() + ).create_webhook._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() + ).create_webhook._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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_webhook.Webhook() + # 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 = gcdc_webhook.Webhook.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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_webhook._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "webhook", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "post_create_webhook" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_create_webhook" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_webhook.CreateWebhookRequest.pb( + gcdc_webhook.CreateWebhookRequest() + ) + 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 = gcdc_webhook.Webhook.to_json(gcdc_webhook.Webhook()) + + request = gcdc_webhook.CreateWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_webhook.Webhook() + + client.create_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_webhook_rest_bad_request( + transport: str = "rest", request_type=gcdc_webhook.CreateWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["webhook"] = { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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_webhook(request) + + +def test_create_webhook_rest_flattened(): + client = WebhooksClient( + 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 = gcdc_webhook.Webhook() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + webhook=gcdc_webhook.Webhook(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 = gcdc_webhook.Webhook.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_webhook(**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/v3/{parent=projects/*/locations/*/agents/*}/webhooks" + % client.transport._host, + args[1], + ) + + +def test_create_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + gcdc_webhook.CreateWebhookRequest(), + parent="parent_value", + webhook=gcdc_webhook.Webhook(name="name_value"), + ) + + +def test_create_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_webhook.UpdateWebhookRequest, + dict, + ], +) +def test_update_webhook_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "webhook": { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + } + request_init["webhook"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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 = gcdc_webhook.Webhook( + name="name_value", + display_name="display_name_value", + disabled=True, + generic_web_service=gcdc_webhook.Webhook.GenericWebService(uri="uri_value"), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_webhook.Webhook.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_webhook(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_webhook.Webhook) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.disabled is True + + +def test_update_webhook_rest_required_fields( + request_type=gcdc_webhook.UpdateWebhookRequest, +): + transport_class = transports.WebhooksRestTransport + + 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_webhook._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_webhook._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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_webhook.Webhook() + # 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 = gcdc_webhook.Webhook.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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_webhook._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("webhook",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "post_update_webhook" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_update_webhook" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_webhook.UpdateWebhookRequest.pb( + gcdc_webhook.UpdateWebhookRequest() + ) + 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 = gcdc_webhook.Webhook.to_json(gcdc_webhook.Webhook()) + + request = gcdc_webhook.UpdateWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_webhook.Webhook() + + client.update_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_webhook_rest_bad_request( + transport: str = "rest", request_type=gcdc_webhook.UpdateWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "webhook": { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + } + request_init["webhook"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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_webhook(request) + + +def test_update_webhook_rest_flattened(): + client = WebhooksClient( + 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 = gcdc_webhook.Webhook() + + # get arguments that satisfy an http rule for this method + sample_request = { + "webhook": { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + webhook=gcdc_webhook.Webhook(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 = gcdc_webhook.Webhook.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_webhook(**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/v3/{webhook.name=projects/*/locations/*/agents/*/webhooks/*}" + % client.transport._host, + args[1], + ) + + +def test_update_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + gcdc_webhook.UpdateWebhookRequest(), + webhook=gcdc_webhook.Webhook(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + webhook.DeleteWebhookRequest, + dict, + ], +) +def test_delete_webhook_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/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 = 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_webhook(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_webhook_rest_required_fields(request_type=webhook.DeleteWebhookRequest): + transport_class = transports.WebhooksRestTransport + + 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_webhook._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_webhook._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = WebhooksClient( + 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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_webhook._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "pre_delete_webhook" + ) as pre: + pre.assert_not_called() + pb_message = webhook.DeleteWebhookRequest.pb(webhook.DeleteWebhookRequest()) + 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 = webhook.DeleteWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_webhook_rest_bad_request( + transport: str = "rest", request_type=webhook.DeleteWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + 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_webhook(request) + + +def test_delete_webhook_rest_flattened(): + client = WebhooksClient( + 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": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + + # 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_webhook(**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/v3/{name=projects/*/locations/*/agents/*/webhooks/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + webhook.DeleteWebhookRequest(), + name="name_value", + ) + + +def test_delete_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebhooksClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = WebhooksClient( + 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 = WebhooksClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebhooksClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = WebhooksClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.WebhooksGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebhooksGrpcTransport, + transports.WebhooksGrpcAsyncIOTransport, + transports.WebhooksRestTransport, + ], +) +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 = WebhooksClient.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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.WebhooksGrpcTransport, + ) + + +def test_webhooks_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.WebhooksTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_webhooks_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.webhooks.transports.WebhooksTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.WebhooksTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_webhooks", + "get_webhook", + "create_webhook", + "update_webhook", + "delete_webhook", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_webhooks_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 @@ -2274,6 +3775,7 @@ def test_webhooks_transport_auth_adc(transport_class): [ transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport, + transports.WebhooksRestTransport, ], ) def test_webhooks_transport_auth_gdch_credentials(transport_class): @@ -2371,11 +3873,23 @@ def test_webhooks_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_webhooks_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.WebhooksRestTransport( + 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_webhooks_host_no_port(transport_name): @@ -2386,7 +3900,11 @@ def test_webhooks_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2394,6 +3912,7 @@ def test_webhooks_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_webhooks_host_with_port(transport_name): @@ -2404,7 +3923,45 @@ def test_webhooks_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_webhooks_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = WebhooksClient( + credentials=creds1, + transport=transport_name, + ) + client2 = WebhooksClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_webhooks._session + session2 = client2.transport.list_webhooks._session + assert session1 != session2 + session1 = client1.transport.get_webhook._session + session2 = client2.transport.get_webhook._session + assert session1 != session2 + session1 = client1.transport.create_webhook._session + session2 = client2.transport.create_webhook._session + assert session1 != session2 + session1 = client1.transport.update_webhook._session + session2 = client2.transport.update_webhook._session + assert session1 != session2 + session1 = client1.transport.delete_webhook._session + session2 = client2.transport.delete_webhook._session + assert session1 != session2 def test_webhooks_grpc_transport_channel(): @@ -2723,6 +4280,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3440,6 +5283,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3457,6 +5301,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py index 08e59988..e50cbfb7 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.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 @@ -48,7 +55,9 @@ from google.cloud.dialogflowcx_v3beta1.types import advanced_settings from google.cloud.dialogflowcx_v3beta1.types import agent from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3beta1.types import audio_config from google.cloud.dialogflowcx_v3beta1.types import flow +from google.cloud.dialogflowcx_v3beta1.types import gcs from google.cloud.location import locations_pb2 from google.longrunning import operations_pb2 from google.oauth2 import service_account @@ -101,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_info(client_class, transport_name): @@ -114,7 +124,11 @@ def test_agents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -122,6 +136,7 @@ def test_agents_client_from_service_account_info(client_class, transport_name): [ (transports.AgentsGrpcTransport, "grpc"), (transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -145,6 +160,7 @@ def test_agents_client_service_account_always_use_jwt(transport_class, transport [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_file(client_class, transport_name): @@ -165,13 +181,18 @@ def test_agents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_agents_client_get_transport_class(): transport = AgentsClient.get_transport_class() available_transports = [ transports.AgentsGrpcTransport, + transports.AgentsRestTransport, ] assert transport in available_transports @@ -184,6 +205,7 @@ def test_agents_client_get_transport_class(): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -323,6 +345,8 @@ def test_agents_client_client_options(client_class, transport_class, transport_n "grpc_asyncio", "false", ), + (AgentsClient, transports.AgentsRestTransport, "rest", "true"), + (AgentsClient, transports.AgentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -508,6 +532,7 @@ def test_agents_client_get_mtls_endpoint_and_cert_source(client_class): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_client_options_scopes( @@ -543,6 +568,7 @@ def test_agents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AgentsClient, transports.AgentsRestTransport, "rest", None), ], ) def test_agents_client_client_options_credentials_file( @@ -2811,258 +2837,2694 @@ async def test_get_agent_validation_result_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.AgentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + agent.ListAgentsRequest, + dict, + ], +) +def test_list_agents_rest(request_type): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = AgentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AgentsClient( - 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 = agent.ListAgentsResponse( + next_page_token="next_page_token_value", ) - # 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 = AgentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.ListAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_agents(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAgentsPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - client = AgentsClient(transport=transport) - assert client.transport is transport +def test_list_agents_rest_required_fields(request_type=agent.ListAgentsRequest): + transport_class = transports.AgentsRestTransport -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + 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, + ) ) - channel = transport.grpc_channel - assert channel - transport = transports.AgentsGrpcAsyncIOTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - channel = transport.grpc_channel - assert channel + # verify fields with default values are dropped + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_agents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], -) -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() + # verify required fields with default values are now present + jsonified_request["parent"] = "parent_value" -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = AgentsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_agents._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", + ) ) - assert transport.kind == transport_name + 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 = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.ListAgentsResponse() + # 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 = agent.ListAgentsResponse.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_agents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_agents_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.AgentsGrpcTransport, + + unset_fields = transport.list_agents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_agents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_agents_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_list_agents" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_list_agents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ListAgentsRequest.pb(agent.ListAgentsRequest()) + 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 = agent.ListAgentsResponse.to_json( + agent.ListAgentsResponse() ) + request = agent.ListAgentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.ListAgentsResponse() -def test_agents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.agents.transports.AgentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_agents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_agents", - "get_agent", - "create_agent", - "update_agent", - "delete_agent", - "export_agent", - "restore_agent", - "validate_agent", - "get_agent_validation_result", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + pre.assert_called_once() + post.assert_called_once() - with pytest.raises(NotImplementedError): - transport.close() - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client +def test_list_agents_rest_bad_request( + transport: str = "rest", request_type=agent.ListAgentsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/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_agents(request) -def test_agents_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.dialogflowcx_v3beta1.services.agents.transports.AgentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AgentsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) +def test_list_agents_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) -def test_agents_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.dialogflowcx_v3beta1.services.agents.transports.AgentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.AgentsTransport() - adc.assert_called_once() + # 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 = agent.ListAgentsResponse() + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} -def test_agents_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) - AgentsClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, + # 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 = agent.ListAgentsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], -) -def test_agents_transport_auth_adc(transport_class): - # If credentials and host are not provided, the transport class should use - # ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class(quota_project_id="octopus", scopes=["1", "2"]) - adc.assert_called_once_with( - scopes=["1", "2"], - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + client.list_agents(**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/v3beta1/{parent=projects/*/locations/*}/agents" + % client.transport._host, + args[1], ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], +def test_list_agents_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agents( + agent.ListAgentsRequest(), + parent="parent_value", + ) + + +def test_list_agents_rest_pager(transport: str = "rest"): + client = AgentsClient( + 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 = ( + agent.ListAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + agent.Agent(), + ], + next_page_token="abc", + ), + agent.ListAgentsResponse( + agents=[], + next_page_token="def", + ), + agent.ListAgentsResponse( + agents=[ + agent.Agent(), + ], + next_page_token="ghi", + ), + agent.ListAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(agent.ListAgentsResponse.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": "projects/sample1/locations/sample2"} + + pager = client.list_agents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, agent.Agent) for i in results) + + pages = list(client.list_agents(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", + [ + agent.GetAgentRequest, + dict, + ], +) +def test_get_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = agent.Agent( + name="name_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + start_flow="start_flow_value", + security_settings="security_settings_value", + enable_stackdriver_logging=True, + enable_spell_correction=True, + locked=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.Agent.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_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.Agent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True + assert response.enable_spell_correction is True + assert response.locked is True + + +def test_get_agent_rest_required_fields(request_type=agent.GetAgentRequest): + transport_class = transports.AgentsRestTransport + + 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_agent._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_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.Agent() + # 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 = agent.Agent.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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_get_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetAgentRequest.pb(agent.GetAgentRequest()) + 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 = agent.Agent.to_json(agent.Agent()) + + request = agent.GetAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.Agent() + + client.get_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_agent_rest_bad_request( + transport: str = "rest", request_type=agent.GetAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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_agent(request) + + +def test_get_agent_rest_flattened(): + client = AgentsClient( + 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 = agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/locations/sample2/agents/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 = agent.Agent.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_agent(**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/v3beta1/{name=projects/*/locations/*/agents/*}" + % client.transport._host, + args[1], + ) + + +def test_get_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + agent.GetAgentRequest(), + name="name_value", + ) + + +def test_get_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_agent.CreateAgentRequest, + dict, + ], +) +def test_create_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["agent"] = { + "name": "name_value", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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 = gcdc_agent.Agent( + name="name_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + start_flow="start_flow_value", + security_settings="security_settings_value", + enable_stackdriver_logging=True, + enable_spell_correction=True, + locked=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_agent.Agent.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_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_agent.Agent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True + assert response.enable_spell_correction is True + assert response.locked is True + + +def test_create_agent_rest_required_fields(request_type=gcdc_agent.CreateAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).create_agent._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() + ).create_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_agent.Agent() + # 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 = gcdc_agent.Agent.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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_agent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "agent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_create_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_create_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_agent.CreateAgentRequest.pb(gcdc_agent.CreateAgentRequest()) + 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 = gcdc_agent.Agent.to_json(gcdc_agent.Agent()) + + request = gcdc_agent.CreateAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_agent.Agent() + + client.create_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_agent_rest_bad_request( + transport: str = "rest", request_type=gcdc_agent.CreateAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["agent"] = { + "name": "name_value", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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_agent(request) + + +def test_create_agent_rest_flattened(): + client = AgentsClient( + 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 = gcdc_agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + agent=gcdc_agent.Agent(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 = gcdc_agent.Agent.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_agent(**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/v3beta1/{parent=projects/*/locations/*}/agents" + % client.transport._host, + args[1], + ) + + +def test_create_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + gcdc_agent.CreateAgentRequest(), + parent="parent_value", + agent=gcdc_agent.Agent(name="name_value"), + ) + + +def test_create_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_agent.UpdateAgentRequest, + dict, + ], +) +def test_update_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "agent": {"name": "projects/sample1/locations/sample2/agents/sample3"} + } + request_init["agent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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 = gcdc_agent.Agent( + name="name_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + start_flow="start_flow_value", + security_settings="security_settings_value", + enable_stackdriver_logging=True, + enable_spell_correction=True, + locked=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_agent.Agent.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_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_agent.Agent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True + assert response.enable_spell_correction is True + assert response.locked is True + + +def test_update_agent_rest_required_fields(request_type=gcdc_agent.UpdateAgentRequest): + transport_class = transports.AgentsRestTransport + + 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_agent._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_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_agent.Agent() + # 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 = gcdc_agent.Agent.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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("agent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_update_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_update_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_agent.UpdateAgentRequest.pb(gcdc_agent.UpdateAgentRequest()) + 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 = gcdc_agent.Agent.to_json(gcdc_agent.Agent()) + + request = gcdc_agent.UpdateAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_agent.Agent() + + client.update_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_agent_rest_bad_request( + transport: str = "rest", request_type=gcdc_agent.UpdateAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "agent": {"name": "projects/sample1/locations/sample2/agents/sample3"} + } + request_init["agent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "speech_to_text_settings": {"enable_speech_adaptation": True}, + "start_flow": "start_flow_value", + "security_settings": "security_settings_value", + "enable_stackdriver_logging": True, + "enable_spell_correction": True, + "locked": True, + "advanced_settings": { + "audio_export_gcs_destination": {"uri": "uri_value"}, + "logging_settings": { + "enable_stackdriver_logging": True, + "enable_interaction_logging": True, + }, + }, + "text_to_speech_settings": {"synthesize_speech_configs": {}}, + } + 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_agent(request) + + +def test_update_agent_rest_flattened(): + client = AgentsClient( + 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 = gcdc_agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = { + "agent": {"name": "projects/sample1/locations/sample2/agents/sample3"} + } + + # get truthy value for each flattened field + mock_args = dict( + agent=gcdc_agent.Agent(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 = gcdc_agent.Agent.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_agent(**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/v3beta1/{agent.name=projects/*/locations/*/agents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + gcdc_agent.UpdateAgentRequest(), + agent=gcdc_agent.Agent(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.DeleteAgentRequest, + dict, + ], +) +def test_delete_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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_agent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_agent_rest_required_fields(request_type=agent.DeleteAgentRequest): + transport_class = transports.AgentsRestTransport + + 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_agent._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_agent._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 = AgentsClient( + 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_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "pre_delete_agent" + ) as pre: + pre.assert_not_called() + pb_message = agent.DeleteAgentRequest.pb(agent.DeleteAgentRequest()) + 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 = agent.DeleteAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_agent_rest_bad_request( + transport: str = "rest", request_type=agent.DeleteAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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_agent(request) + + +def test_delete_agent_rest_flattened(): + client = AgentsClient( + 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": "projects/sample1/locations/sample2/agents/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_agent(**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/v3beta1/{name=projects/*/locations/*/agents/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent( + agent.DeleteAgentRequest(), + name="name_value", + ) + + +def test_delete_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ExportAgentRequest, + dict, + ], +) +def test_export_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = 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.export_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_agent_rest_required_fields(request_type=agent.ExportAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).export_agent._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() + ).export_agent._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 = AgentsClient( + 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.export_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_export_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_export_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ExportAgentRequest.pb(agent.ExportAgentRequest()) + 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 = agent.ExportAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ExportAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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.export_agent(request) + + +def test_export_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.RestoreAgentRequest, + dict, + ], +) +def test_restore_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = 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.restore_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_restore_agent_rest_required_fields(request_type=agent.RestoreAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).restore_agent._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() + ).restore_agent._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 = AgentsClient( + 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.restore_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_restore_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.restore_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_restore_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_restore_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_restore_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.RestoreAgentRequest.pb(agent.RestoreAgentRequest()) + 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 = agent.RestoreAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.restore_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_restore_agent_rest_bad_request( + transport: str = "rest", request_type=agent.RestoreAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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.restore_agent(request) + + +def test_restore_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ValidateAgentRequest, + dict, + ], +) +def test_validate_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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 = agent.AgentValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.AgentValidationResult.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.validate_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + assert response.name == "name_value" + + +def test_validate_agent_rest_required_fields(request_type=agent.ValidateAgentRequest): + transport_class = transports.AgentsRestTransport + + 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() + ).validate_agent._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() + ).validate_agent._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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.AgentValidationResult() + # 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 = agent.AgentValidationResult.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.validate_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_validate_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.validate_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_validate_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_validate_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_validate_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ValidateAgentRequest.pb(agent.ValidateAgentRequest()) + 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 = agent.AgentValidationResult.to_json( + agent.AgentValidationResult() + ) + + request = agent.ValidateAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.AgentValidationResult() + + client.validate_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_validate_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ValidateAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/agents/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.validate_agent(request) + + +def test_validate_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.GetAgentValidationResultRequest, + dict, + ], +) +def test_get_agent_validation_result_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/validationResult" + } + 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 = agent.AgentValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.AgentValidationResult.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_agent_validation_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + assert response.name == "name_value" + + +def test_get_agent_validation_result_rest_required_fields( + request_type=agent.GetAgentValidationResultRequest, +): + transport_class = transports.AgentsRestTransport + + 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_agent_validation_result._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_agent_validation_result._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.AgentValidationResult() + # 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 = agent.AgentValidationResult.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_agent_validation_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_agent_validation_result_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_agent_validation_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_agent_validation_result_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(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.AgentsRestInterceptor, "post_get_agent_validation_result" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_agent_validation_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetAgentValidationResultRequest.pb( + agent.GetAgentValidationResultRequest() + ) + 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 = agent.AgentValidationResult.to_json( + agent.AgentValidationResult() + ) + + request = agent.GetAgentValidationResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.AgentValidationResult() + + client.get_agent_validation_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_agent_validation_result_rest_bad_request( + transport: str = "rest", request_type=agent.GetAgentValidationResultRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/validationResult" + } + 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_agent_validation_result(request) + + +def test_get_agent_validation_result_rest_flattened(): + client = AgentsClient( + 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 = agent.AgentValidationResult() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/validationResult" + } + + # 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 = agent.AgentValidationResult.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_agent_validation_result(**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/v3beta1/{name=projects/*/locations/*/agents/*/validationResult}" + % client.transport._host, + args[1], + ) + + +def test_get_agent_validation_result_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + 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_agent_validation_result( + agent.GetAgentValidationResultRequest(), + name="name_value", + ) + + +def test_get_agent_validation_result_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AgentsClient( + 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 = AgentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AgentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AgentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, + ], +) +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 = AgentsClient.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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AgentsGrpcTransport, + ) + + +def test_agents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_agents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.agents.transports.AgentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_agents", + "get_agent", + "create_agent", + "update_agent", + "delete_agent", + "export_agent", + "restore_agent", + "validate_agent", + "get_agent_validation_result", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_agents_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.dialogflowcx_v3beta1.services.agents.transports.AgentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AgentsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_agents_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.dialogflowcx_v3beta1.services.agents.transports.AgentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.AgentsTransport() + adc.assert_called_once() + + +def test_agents_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) + AgentsClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + ], +) +def test_agents_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, + ], ) def test_agents_transport_auth_gdch_credentials(transport_class): host = "https://language.com" @@ -3159,11 +5621,40 @@ def test_agents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_agents_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.AgentsRestTransport( + 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_agents_rest_lro_client(): + client = AgentsClient( + 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_agents_host_no_port(transport_name): @@ -3174,7 +5665,11 @@ def test_agents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3182,6 +5677,7 @@ def test_agents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_agents_host_with_port(transport_name): @@ -3192,7 +5688,57 @@ def test_agents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_agents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AgentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AgentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_agents._session + session2 = client2.transport.list_agents._session + assert session1 != session2 + session1 = client1.transport.get_agent._session + session2 = client2.transport.get_agent._session + assert session1 != session2 + session1 = client1.transport.create_agent._session + session2 = client2.transport.create_agent._session + assert session1 != session2 + session1 = client1.transport.update_agent._session + session2 = client2.transport.update_agent._session + assert session1 != session2 + session1 = client1.transport.delete_agent._session + session2 = client2.transport.delete_agent._session + assert session1 != session2 + session1 = client1.transport.export_agent._session + session2 = client2.transport.export_agent._session + assert session1 != session2 + session1 = client1.transport.restore_agent._session + session2 = client2.transport.restore_agent._session + assert session1 != session2 + session1 = client1.transport.validate_agent._session + session2 = client2.transport.validate_agent._session + assert session1 != session2 + session1 = client1.transport.get_agent_validation_result._session + session2 = client2.transport.get_agent_validation_result._session + assert session1 != session2 def test_agents_grpc_transport_channel(): @@ -3654,6 +6200,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4371,6 +7203,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4388,6 +7221,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_changelogs.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_changelogs.py index 076d66f7..49bbeda0 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_changelogs.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_changelogs.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 @@ -95,6 +102,7 @@ def test__get_default_mtls_endpoint(): [ (ChangelogsClient, "grpc"), (ChangelogsAsyncClient, "grpc_asyncio"), + (ChangelogsClient, "rest"), ], ) def test_changelogs_client_from_service_account_info(client_class, transport_name): @@ -108,7 +116,11 @@ def test_changelogs_client_from_service_account_info(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +128,7 @@ def test_changelogs_client_from_service_account_info(client_class, transport_nam [ (transports.ChangelogsGrpcTransport, "grpc"), (transports.ChangelogsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ChangelogsRestTransport, "rest"), ], ) def test_changelogs_client_service_account_always_use_jwt( @@ -141,6 +154,7 @@ def test_changelogs_client_service_account_always_use_jwt( [ (ChangelogsClient, "grpc"), (ChangelogsAsyncClient, "grpc_asyncio"), + (ChangelogsClient, "rest"), ], ) def test_changelogs_client_from_service_account_file(client_class, transport_name): @@ -161,13 +175,18 @@ def test_changelogs_client_from_service_account_file(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_changelogs_client_get_transport_class(): transport = ChangelogsClient.get_transport_class() available_transports = [ transports.ChangelogsGrpcTransport, + transports.ChangelogsRestTransport, ] assert transport in available_transports @@ -184,6 +203,7 @@ def test_changelogs_client_get_transport_class(): transports.ChangelogsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +347,8 @@ def test_changelogs_client_client_options( "grpc_asyncio", "false", ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest", "true"), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -520,6 +542,7 @@ def test_changelogs_client_get_mtls_endpoint_and_cert_source(client_class): transports.ChangelogsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest"), ], ) def test_changelogs_client_client_options_scopes( @@ -555,6 +578,7 @@ def test_changelogs_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ChangelogsClient, transports.ChangelogsRestTransport, "rest", None), ], ) def test_changelogs_client_client_options_credentials_file( @@ -1331,6 +1355,624 @@ async def test_get_changelog_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + changelog.ListChangelogsRequest, + dict, + ], +) +def test_list_changelogs_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = changelog.ListChangelogsResponse( + 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 = changelog.ListChangelogsResponse.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_changelogs(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListChangelogsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_changelogs_rest_required_fields( + request_type=changelog.ListChangelogsRequest, +): + transport_class = transports.ChangelogsRestTransport + + 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_changelogs._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_changelogs._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 = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = changelog.ListChangelogsResponse() + # 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 = changelog.ListChangelogsResponse.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_changelogs(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_changelogs_rest_unset_required_fields(): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_changelogs._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_changelogs_rest_interceptors(null_interceptor): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ChangelogsRestInterceptor(), + ) + client = ChangelogsClient(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.ChangelogsRestInterceptor, "post_list_changelogs" + ) as post, mock.patch.object( + transports.ChangelogsRestInterceptor, "pre_list_changelogs" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = changelog.ListChangelogsRequest.pb( + changelog.ListChangelogsRequest() + ) + 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 = changelog.ListChangelogsResponse.to_json( + changelog.ListChangelogsResponse() + ) + + request = changelog.ListChangelogsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = changelog.ListChangelogsResponse() + + client.list_changelogs( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_changelogs_rest_bad_request( + transport: str = "rest", request_type=changelog.ListChangelogsRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.list_changelogs(request) + + +def test_list_changelogs_rest_flattened(): + client = ChangelogsClient( + 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 = changelog.ListChangelogsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = changelog.ListChangelogsResponse.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_changelogs(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/changelogs" + % client.transport._host, + args[1], + ) + + +def test_list_changelogs_rest_flattened_error(transport: str = "rest"): + client = ChangelogsClient( + 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_changelogs( + changelog.ListChangelogsRequest(), + parent="parent_value", + ) + + +def test_list_changelogs_rest_pager(transport: str = "rest"): + client = ChangelogsClient( + 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 = ( + changelog.ListChangelogsResponse( + changelogs=[ + changelog.Changelog(), + changelog.Changelog(), + changelog.Changelog(), + ], + next_page_token="abc", + ), + changelog.ListChangelogsResponse( + changelogs=[], + next_page_token="def", + ), + changelog.ListChangelogsResponse( + changelogs=[ + changelog.Changelog(), + ], + next_page_token="ghi", + ), + changelog.ListChangelogsResponse( + changelogs=[ + changelog.Changelog(), + changelog.Changelog(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(changelog.ListChangelogsResponse.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": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_changelogs(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, changelog.Changelog) for i in results) + + pages = list(client.list_changelogs(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", + [ + changelog.GetChangelogRequest, + dict, + ], +) +def test_get_changelog_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/changelogs/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 = changelog.Changelog( + name="name_value", + user_email="user_email_value", + display_name="display_name_value", + action="action_value", + type_="type__value", + resource="resource_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = changelog.Changelog.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_changelog(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, changelog.Changelog) + assert response.name == "name_value" + assert response.user_email == "user_email_value" + assert response.display_name == "display_name_value" + assert response.action == "action_value" + assert response.type_ == "type__value" + assert response.resource == "resource_value" + + +def test_get_changelog_rest_required_fields(request_type=changelog.GetChangelogRequest): + transport_class = transports.ChangelogsRestTransport + + 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_changelog._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_changelog._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 = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = changelog.Changelog() + # 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 = changelog.Changelog.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_changelog(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_changelog_rest_unset_required_fields(): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_changelog._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_changelog_rest_interceptors(null_interceptor): + transport = transports.ChangelogsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ChangelogsRestInterceptor(), + ) + client = ChangelogsClient(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.ChangelogsRestInterceptor, "post_get_changelog" + ) as post, mock.patch.object( + transports.ChangelogsRestInterceptor, "pre_get_changelog" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = changelog.GetChangelogRequest.pb(changelog.GetChangelogRequest()) + 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 = changelog.Changelog.to_json(changelog.Changelog()) + + request = changelog.GetChangelogRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = changelog.Changelog() + + client.get_changelog( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_changelog_rest_bad_request( + transport: str = "rest", request_type=changelog.GetChangelogRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/changelogs/sample4" + } + 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_changelog(request) + + +def test_get_changelog_rest_flattened(): + client = ChangelogsClient( + 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 = changelog.Changelog() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/changelogs/sample4" + } + + # 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 = changelog.Changelog.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_changelog(**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/v3beta1/{name=projects/*/locations/*/agents/*/changelogs/*}" + % client.transport._host, + args[1], + ) + + +def test_get_changelog_rest_flattened_error(transport: str = "rest"): + client = ChangelogsClient( + 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_changelog( + changelog.GetChangelogRequest(), + name="name_value", + ) + + +def test_get_changelog_rest_error(): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.ChangelogsGrpcTransport( @@ -1412,6 +2054,7 @@ def test_transport_get_channel(): [ transports.ChangelogsGrpcTransport, transports.ChangelogsGrpcAsyncIOTransport, + transports.ChangelogsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1426,6 +2069,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1570,6 +2214,7 @@ def test_changelogs_transport_auth_adc(transport_class): [ transports.ChangelogsGrpcTransport, transports.ChangelogsGrpcAsyncIOTransport, + transports.ChangelogsRestTransport, ], ) def test_changelogs_transport_auth_gdch_credentials(transport_class): @@ -1667,11 +2312,23 @@ def test_changelogs_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_changelogs_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.ChangelogsRestTransport( + 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_changelogs_host_no_port(transport_name): @@ -1682,7 +2339,11 @@ def test_changelogs_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1690,6 +2351,7 @@ def test_changelogs_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_changelogs_host_with_port(transport_name): @@ -1700,7 +2362,36 @@ def test_changelogs_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_changelogs_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ChangelogsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ChangelogsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_changelogs._session + session2 = client2.transport.list_changelogs._session + assert session1 != session2 + session1 = client1.transport.get_changelog._session + session2 = client2.transport.get_changelog._session + assert session1 != session2 def test_changelogs_grpc_transport_channel(): @@ -1990,6 +2681,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ChangelogsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ChangelogsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2707,6 +3684,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2724,6 +3702,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_deployments.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_deployments.py index fc51f3f2..d6267084 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_deployments.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_deployments.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 @@ -97,6 +104,7 @@ def test__get_default_mtls_endpoint(): [ (DeploymentsClient, "grpc"), (DeploymentsAsyncClient, "grpc_asyncio"), + (DeploymentsClient, "rest"), ], ) def test_deployments_client_from_service_account_info(client_class, transport_name): @@ -110,7 +118,11 @@ def test_deployments_client_from_service_account_info(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -118,6 +130,7 @@ def test_deployments_client_from_service_account_info(client_class, transport_na [ (transports.DeploymentsGrpcTransport, "grpc"), (transports.DeploymentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.DeploymentsRestTransport, "rest"), ], ) def test_deployments_client_service_account_always_use_jwt( @@ -143,6 +156,7 @@ def test_deployments_client_service_account_always_use_jwt( [ (DeploymentsClient, "grpc"), (DeploymentsAsyncClient, "grpc_asyncio"), + (DeploymentsClient, "rest"), ], ) def test_deployments_client_from_service_account_file(client_class, transport_name): @@ -163,13 +177,18 @@ def test_deployments_client_from_service_account_file(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_deployments_client_get_transport_class(): transport = DeploymentsClient.get_transport_class() available_transports = [ transports.DeploymentsGrpcTransport, + transports.DeploymentsRestTransport, ] assert transport in available_transports @@ -186,6 +205,7 @@ def test_deployments_client_get_transport_class(): transports.DeploymentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -329,6 +349,8 @@ def test_deployments_client_client_options( "grpc_asyncio", "false", ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest", "true"), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -522,6 +544,7 @@ def test_deployments_client_get_mtls_endpoint_and_cert_source(client_class): transports.DeploymentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest"), ], ) def test_deployments_client_client_options_scopes( @@ -557,6 +580,7 @@ def test_deployments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (DeploymentsClient, transports.DeploymentsRestTransport, "rest", None), ], ) def test_deployments_client_client_options_credentials_file( @@ -1325,6 +1349,632 @@ async def test_get_deployment_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + deployment.ListDeploymentsRequest, + dict, + ], +) +def test_list_deployments_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/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 = deployment.ListDeploymentsResponse( + 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 = deployment.ListDeploymentsResponse.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_deployments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListDeploymentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_deployments_rest_required_fields( + request_type=deployment.ListDeploymentsRequest, +): + transport_class = transports.DeploymentsRestTransport + + 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_deployments._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_deployments._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", + ) + ) + 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 = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = deployment.ListDeploymentsResponse() + # 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 = deployment.ListDeploymentsResponse.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_deployments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_deployments_rest_unset_required_fields(): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_deployments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_deployments_rest_interceptors(null_interceptor): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.DeploymentsRestInterceptor(), + ) + client = DeploymentsClient(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.DeploymentsRestInterceptor, "post_list_deployments" + ) as post, mock.patch.object( + transports.DeploymentsRestInterceptor, "pre_list_deployments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = deployment.ListDeploymentsRequest.pb( + deployment.ListDeploymentsRequest() + ) + 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 = deployment.ListDeploymentsResponse.to_json( + deployment.ListDeploymentsResponse() + ) + + request = deployment.ListDeploymentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = deployment.ListDeploymentsResponse() + + client.list_deployments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_deployments_rest_bad_request( + transport: str = "rest", request_type=deployment.ListDeploymentsRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_deployments(request) + + +def test_list_deployments_rest_flattened(): + client = DeploymentsClient( + 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 = deployment.ListDeploymentsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = deployment.ListDeploymentsResponse.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_deployments(**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/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/deployments" + % client.transport._host, + args[1], + ) + + +def test_list_deployments_rest_flattened_error(transport: str = "rest"): + client = DeploymentsClient( + 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_deployments( + deployment.ListDeploymentsRequest(), + parent="parent_value", + ) + + +def test_list_deployments_rest_pager(transport: str = "rest"): + client = DeploymentsClient( + 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 = ( + deployment.ListDeploymentsResponse( + deployments=[ + deployment.Deployment(), + deployment.Deployment(), + deployment.Deployment(), + ], + next_page_token="abc", + ), + deployment.ListDeploymentsResponse( + deployments=[], + next_page_token="def", + ), + deployment.ListDeploymentsResponse( + deployments=[ + deployment.Deployment(), + ], + next_page_token="ghi", + ), + deployment.ListDeploymentsResponse( + deployments=[ + deployment.Deployment(), + deployment.Deployment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + deployment.ListDeploymentsResponse.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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + pager = client.list_deployments(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, deployment.Deployment) for i in results) + + pages = list(client.list_deployments(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", + [ + deployment.GetDeploymentRequest, + dict, + ], +) +def test_get_deployment_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/deployments/sample5" + } + 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 = deployment.Deployment( + name="name_value", + flow_version="flow_version_value", + state=deployment.Deployment.State.RUNNING, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = deployment.Deployment.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_deployment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, deployment.Deployment) + assert response.name == "name_value" + assert response.flow_version == "flow_version_value" + assert response.state == deployment.Deployment.State.RUNNING + + +def test_get_deployment_rest_required_fields( + request_type=deployment.GetDeploymentRequest, +): + transport_class = transports.DeploymentsRestTransport + + 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_deployment._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_deployment._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 = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = deployment.Deployment() + # 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 = deployment.Deployment.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_deployment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_deployment_rest_unset_required_fields(): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_deployment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_deployment_rest_interceptors(null_interceptor): + transport = transports.DeploymentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.DeploymentsRestInterceptor(), + ) + client = DeploymentsClient(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.DeploymentsRestInterceptor, "post_get_deployment" + ) as post, mock.patch.object( + transports.DeploymentsRestInterceptor, "pre_get_deployment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = deployment.GetDeploymentRequest.pb( + deployment.GetDeploymentRequest() + ) + 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 = deployment.Deployment.to_json( + deployment.Deployment() + ) + + request = deployment.GetDeploymentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = deployment.Deployment() + + client.get_deployment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_deployment_rest_bad_request( + transport: str = "rest", request_type=deployment.GetDeploymentRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/deployments/sample5" + } + 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_deployment(request) + + +def test_get_deployment_rest_flattened(): + client = DeploymentsClient( + 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 = deployment.Deployment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/deployments/sample5" + } + + # 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 = deployment.Deployment.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_deployment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/deployments/*}" + % client.transport._host, + args[1], + ) + + +def test_get_deployment_rest_flattened_error(transport: str = "rest"): + client = DeploymentsClient( + 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_deployment( + deployment.GetDeploymentRequest(), + name="name_value", + ) + + +def test_get_deployment_rest_error(): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.DeploymentsGrpcTransport( @@ -1406,6 +2056,7 @@ def test_transport_get_channel(): [ transports.DeploymentsGrpcTransport, transports.DeploymentsGrpcAsyncIOTransport, + transports.DeploymentsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1420,6 +2071,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1564,6 +2216,7 @@ def test_deployments_transport_auth_adc(transport_class): [ transports.DeploymentsGrpcTransport, transports.DeploymentsGrpcAsyncIOTransport, + transports.DeploymentsRestTransport, ], ) def test_deployments_transport_auth_gdch_credentials(transport_class): @@ -1661,11 +2314,23 @@ def test_deployments_grpc_transport_client_cert_source_for_mtls(transport_class) ) +def test_deployments_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.DeploymentsRestTransport( + 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_deployments_host_no_port(transport_name): @@ -1676,7 +2341,11 @@ def test_deployments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1684,6 +2353,7 @@ def test_deployments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_deployments_host_with_port(transport_name): @@ -1694,7 +2364,36 @@ def test_deployments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_deployments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = DeploymentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = DeploymentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_deployments._session + session2 = client2.transport.list_deployments._session + assert session1 != session2 + session1 = client1.transport.get_deployment._session + session2 = client2.transport.get_deployment._session + assert session1 != session2 def test_deployments_grpc_transport_channel(): @@ -2089,6 +2788,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = DeploymentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = DeploymentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2806,6 +3791,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2823,6 +3809,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py index 6a24970b..910af343 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.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 @@ -98,6 +105,7 @@ def test__get_default_mtls_endpoint(): [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_info(client_class, transport_name): @@ -111,7 +119,11 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -119,6 +131,7 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n [ (transports.EntityTypesGrpcTransport, "grpc"), (transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_service_account_always_use_jwt( @@ -144,6 +157,7 @@ def test_entity_types_client_service_account_always_use_jwt( [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_file(client_class, transport_name): @@ -164,13 +178,18 @@ def test_entity_types_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_entity_types_client_get_transport_class(): transport = EntityTypesClient.get_transport_class() available_transports = [ transports.EntityTypesGrpcTransport, + transports.EntityTypesRestTransport, ] assert transport in available_transports @@ -187,6 +206,7 @@ def test_entity_types_client_get_transport_class(): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -330,6 +350,8 @@ def test_entity_types_client_client_options( "grpc_asyncio", "false", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "true"), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -523,6 +545,7 @@ def test_entity_types_client_get_mtls_endpoint_and_cert_source(client_class): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_client_options_scopes( @@ -558,6 +581,7 @@ def test_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", None), ], ) def test_entity_types_client_client_options_credentials_file( @@ -2166,211 +2190,1753 @@ async def test_delete_entity_type_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + entity_type.ListEntityTypesRequest, + dict, + ], +) +def test_list_entity_types_rest(request_type): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EntityTypesClient( - 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 = entity_type.ListEntityTypesResponse( + next_page_token="next_page_token_value", ) - # 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 = EntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_entity_types(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEntityTypesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_entity_types_rest_required_fields( + request_type=entity_type.ListEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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, + ) ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_entity_types._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_entity_types._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EntityTypesClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse() + # 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 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = entity_type.ListEntityTypesResponse.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_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.EntityTypesGrpcAsyncIOTransport( + unset_fields = transport.list_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_list_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_list_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.ListEntityTypesRequest.pb( + entity_type.ListEntityTypesRequest() + ) + 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 = entity_type.ListEntityTypesResponse.to_json( + entity_type.ListEntityTypesResponse() + ) + request = entity_type.ListEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.ListEntityTypesResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.EntityTypesGrpcTransport, - transports.EntityTypesGrpcAsyncIOTransport, - ], -) -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() + client.list_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = EntityTypesClient.get_transport_class(transport_name)( + +def test_list_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.ListEntityTypesRequest +): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # 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_entity_types(request) + + +def test_list_entity_types_rest_flattened(): client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.EntityTypesGrpcTransport, + 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 = entity_type.ListEntityTypesResponse() -def test_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = entity_type.ListEntityTypesResponse.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_entity_types_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.entity_types.transports.EntityTypesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.EntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_entity_types(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/entityTypes" + % client.transport._host, + args[1], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_entity_types", - "get_entity_type", - "create_entity_type", - "update_entity_type", - "delete_entity_type", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + +def test_list_entity_types_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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() + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_entity_types( + entity_type.ListEntityTypesRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_entity_types_rest_pager(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_entity_types_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.dialogflowcx_v3beta1.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.EntityTypesTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", + # 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 = ( + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + entity_type.EntityType(), + ], + next_page_token="abc", + ), + entity_type.ListEntityTypesResponse( + entity_types=[], + next_page_token="def", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + ], + next_page_token="ghi", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple( + entity_type.ListEntityTypesResponse.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 -def test_entity_types_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.dialogflowcx_v3beta1.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.EntityTypesTransport() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + pager = client.list_entity_types(request=sample_request) -def test_entity_types_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) - EntityTypesClient() - adc.assert_called_once_with( + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, entity_type.EntityType) for i in results) + + pages = list(client.list_entity_types(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", + [ + entity_type.GetEntityTypeRequest, + dict, + ], +) +def test_get_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/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 = entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + redact=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.EntityType.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_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + assert response.redact is True + + +def test_get_entity_type_rest_required_fields( + request_type=entity_type.GetEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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_entity_type._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_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType() + # 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 = entity_type.EntityType.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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_get_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_get_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.GetEntityTypeRequest.pb( + entity_type.GetEntityTypeRequest() + ) + 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 = entity_type.EntityType.to_json( + entity_type.EntityType() + ) + + request = entity_type.GetEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.EntityType() + + client.get_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.GetEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + 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_entity_type(request) + + +def test_get_entity_type_rest_flattened(): + client = EntityTypesClient( + 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 = entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + + # 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 = entity_type.EntityType.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_entity_type(**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/v3beta1/{name=projects/*/locations/*/agents/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_get_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + entity_type.GetEntityTypeRequest(), + name="name_value", + ) + + +def test_get_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_entity_type.CreateEntityTypeRequest, + dict, + ], +) +def test_create_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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 = gcdc_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + redact=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_entity_type.EntityType.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_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcdc_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + assert response.redact is True + + +def test_create_entity_type_rest_required_fields( + request_type=gcdc_entity_type.CreateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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() + ).create_entity_type._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() + ).create_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_entity_type.EntityType() + # 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 = gcdc_entity_type.EntityType.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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "entityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_create_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_create_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_entity_type.CreateEntityTypeRequest.pb( + gcdc_entity_type.CreateEntityTypeRequest() + ) + 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 = gcdc_entity_type.EntityType.to_json( + gcdc_entity_type.EntityType() + ) + + request = gcdc_entity_type.CreateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_entity_type.EntityType() + + client.create_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcdc_entity_type.CreateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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_entity_type(request) + + +def test_create_entity_type_rest_flattened(): + client = EntityTypesClient( + 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 = gcdc_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_type=gcdc_entity_type.EntityType(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 = gcdc_entity_type.EntityType.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_entity_type(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/entityTypes" + % client.transport._host, + args[1], + ) + + +def test_create_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + gcdc_entity_type.CreateEntityTypeRequest(), + parent="parent_value", + entity_type=gcdc_entity_type.EntityType(name="name_value"), + ) + + +def test_create_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_entity_type.UpdateEntityTypeRequest, + dict, + ], +) +def test_update_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + } + request_init["entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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 = gcdc_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + redact=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_entity_type.EntityType.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_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcdc_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + assert response.redact is True + + +def test_update_entity_type_rest_required_fields( + request_type=gcdc_entity_type.UpdateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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_entity_type._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_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_entity_type.EntityType() + # 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 = gcdc_entity_type.EntityType.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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("entityType",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "post_update_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_update_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_entity_type.UpdateEntityTypeRequest.pb( + gcdc_entity_type.UpdateEntityTypeRequest() + ) + 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 = gcdc_entity_type.EntityType.to_json( + gcdc_entity_type.EntityType() + ) + + request = gcdc_entity_type.UpdateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_entity_type.EntityType() + + client.update_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcdc_entity_type.UpdateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + } + request_init["entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "excluded_phrases": [{"value": "value_value"}], + "enable_fuzzy_extraction": True, + "redact": True, + } + 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_entity_type(request) + + +def test_update_entity_type_rest_flattened(): + client = EntityTypesClient( + 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 = gcdc_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + entity_type=gcdc_entity_type.EntityType(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 = gcdc_entity_type.EntityType.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_entity_type(**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/v3beta1/{entity_type.name=projects/*/locations/*/agents/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + gcdc_entity_type.UpdateEntityTypeRequest(), + entity_type=gcdc_entity_type.EntityType(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.DeleteEntityTypeRequest, + dict, + ], +) +def test_delete_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/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 = 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_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_entity_type_rest_required_fields( + request_type=entity_type.DeleteEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + 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_entity_type._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_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = EntityTypesClient( + 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_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(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.EntityTypesRestInterceptor, "pre_delete_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = entity_type.DeleteEntityTypeRequest.pb( + entity_type.DeleteEntityTypeRequest() + ) + 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 = entity_type.DeleteEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.DeleteEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + 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_entity_type(request) + + +def test_delete_entity_type_rest_flattened(): + client = EntityTypesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/entityTypes/sample4" + } + + # 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_entity_type(**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/v3beta1/{name=projects/*/locations/*/agents/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + 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_entity_type( + entity_type.DeleteEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EntityTypesClient( + 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 = EntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EntityTypesGrpcTransport, + transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, + ], +) +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 = EntityTypesClient.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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EntityTypesGrpcTransport, + ) + + +def test_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_entity_types_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.entity_types.transports.EntityTypesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.EntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_entity_types", + "get_entity_type", + "create_entity_type", + "update_entity_type", + "delete_entity_type", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_entity_types_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.dialogflowcx_v3beta1.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.EntityTypesTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_entity_types_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.dialogflowcx_v3beta1.services.entity_types.transports.EntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.EntityTypesTransport() + adc.assert_called_once() + + +def test_entity_types_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) + EntityTypesClient() + adc.assert_called_once_with( scopes=None, default_scopes=( "https://www.googleapis.com/auth/cloud-platform", @@ -2408,6 +3974,7 @@ def test_entity_types_transport_auth_adc(transport_class): [ transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, ], ) def test_entity_types_transport_auth_gdch_credentials(transport_class): @@ -2505,11 +4072,23 @@ def test_entity_types_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_entity_types_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.EntityTypesRestTransport( + 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_entity_types_host_no_port(transport_name): @@ -2520,7 +4099,11 @@ def test_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2528,6 +4111,7 @@ def test_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_entity_types_host_with_port(transport_name): @@ -2538,7 +4122,45 @@ def test_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_entity_types._session + session2 = client2.transport.list_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_entity_type._session + session2 = client2.transport.get_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_entity_type._session + session2 = client2.transport.create_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_entity_type._session + session2 = client2.transport.update_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_entity_type._session + session2 = client2.transport.delete_entity_type._session + assert session1 != session2 def test_entity_types_grpc_transport_channel(): @@ -2828,6 +4450,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3545,6 +5453,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3562,6 +5471,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py index 7c28e919..a43c91fd 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.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 @@ -106,6 +113,7 @@ def test__get_default_mtls_endpoint(): [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_info(client_class, transport_name): @@ -119,7 +127,11 @@ def test_environments_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -127,6 +139,7 @@ def test_environments_client_from_service_account_info(client_class, transport_n [ (transports.EnvironmentsGrpcTransport, "grpc"), (transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_service_account_always_use_jwt( @@ -152,6 +165,7 @@ def test_environments_client_service_account_always_use_jwt( [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_file(client_class, transport_name): @@ -172,13 +186,18 @@ def test_environments_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_environments_client_get_transport_class(): transport = EnvironmentsClient.get_transport_class() available_transports = [ transports.EnvironmentsGrpcTransport, + transports.EnvironmentsRestTransport, ] assert transport in available_transports @@ -195,6 +214,7 @@ def test_environments_client_get_transport_class(): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -338,6 +358,8 @@ def test_environments_client_client_options( "grpc_asyncio", "false", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "true"), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -531,6 +553,7 @@ def test_environments_client_get_mtls_endpoint_and_cert_source(client_class): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_client_options_scopes( @@ -571,6 +594,7 @@ def test_environments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", None), ], ) def test_environments_client_client_options_credentials_file( @@ -3286,141 +3310,2859 @@ async def test_deploy_flow_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EnvironmentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + environment.ListEnvironmentsRequest, + dict, + ], +) +def test_list_environments_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = environment.ListEnvironmentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.ListEnvironmentsResponse.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_environments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEnvironmentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_environments_rest_required_fields( + request_type=environment.ListEnvironmentsRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environments._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_environments._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", + ) + ) + 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 = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse() + # 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 = environment.ListEnvironmentsResponse.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_environments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_environments_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_environments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_environments_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options=options, - transport=transport, + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_list_environments" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_list_environments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.ListEnvironmentsRequest.pb( + environment.ListEnvironmentsRequest() + ) + 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 = environment.ListEnvironmentsResponse.to_json( + environment.ListEnvironmentsResponse() ) - # 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 = EnvironmentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = environment.ListEnvironmentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.ListEnvironmentsResponse() + + client.list_environments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_environments_rest_bad_request( + transport: str = "rest", request_type=environment.ListEnvironmentsRequest +): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # 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_environments(request) + + +def test_list_environments_rest_flattened(): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EnvironmentsClient(transport=transport) - assert client.transport is 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 = environment.ListEnvironmentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = environment.ListEnvironmentsResponse.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_environments(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/environments" + % client.transport._host, + args[1], + ) + + +def test_list_environments_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.EnvironmentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_environments( + environment.ListEnvironmentsRequest(), + parent="parent_value", + ) + + +def test_list_environments_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + environment.Environment(), + ], + next_page_token="abc", + ), + environment.ListEnvironmentsResponse( + environments=[], + next_page_token="def", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + ], + next_page_token="ghi", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.ListEnvironmentsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.EnvironmentsGrpcTransport, - transports.EnvironmentsGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_environments(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.Environment) for i in results) + + pages = list(client.list_environments(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + environment.GetEnvironmentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = EnvironmentsClient.get_transport_class(transport_name)( +def test_get_environment_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/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 = environment.Environment( + name="name_value", + display_name="display_name_value", + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.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_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + + +def test_get_environment_rest_required_fields( + request_type=environment.GetEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environment._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_environment._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" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.EnvironmentsGrpcTransport, + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # 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 = environment.Environment.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_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_environments_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_get_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_get_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.GetEnvironmentRequest.pb( + environment.GetEnvironmentRequest() + ) + 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 = environment.Environment.to_json( + environment.Environment() ) + request = environment.GetEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() -def test_environments_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.environments.transports.EnvironmentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.get_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly + pre.assert_called_once() + post.assert_called_once() + + +def test_get_environment_rest_bad_request( + transport: str = "rest", request_type=environment.GetEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_environment(request) + + +def test_get_environment_rest_flattened(): + client = EnvironmentsClient( + 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 = environment.Environment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = environment.Environment.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_environment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*}" + % client.transport._host, + args[1], + ) + + +def test_get_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + environment.GetEnvironmentRequest(), + name="name_value", + ) + + +def test_get_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_environment.CreateEnvironmentRequest, + dict, + ], +) +def test_create_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["environment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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.create_environment(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_environment_rest_required_fields( + request_type=gcdc_environment.CreateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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() + ).create_environment._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() + ).create_environment._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 = EnvironmentsClient( + 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.create_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "environment", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_create_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_create_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_environment.CreateEnvironmentRequest.pb( + gcdc_environment.CreateEnvironmentRequest() + ) + 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 = gcdc_environment.CreateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_environment_rest_bad_request( + transport: str = "rest", request_type=gcdc_environment.CreateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["environment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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_environment(request) + + +def test_create_environment_rest_flattened(): + client = EnvironmentsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + environment=gcdc_environment.Environment(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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_environment(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/environments" + % client.transport._host, + args[1], + ) + + +def test_create_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + gcdc_environment.CreateEnvironmentRequest(), + parent="parent_value", + environment=gcdc_environment.Environment(name="name_value"), + ) + + +def test_create_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_environment.UpdateEnvironmentRequest, + dict, + ], +) +def test_update_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + } + request_init["environment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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.update_environment(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_update_environment_rest_required_fields( + request_type=gcdc_environment.UpdateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environment._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_environment._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 = EnvironmentsClient( + 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": "patch", + "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.update_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "environment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_update_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_update_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_environment.UpdateEnvironmentRequest.pb( + gcdc_environment.UpdateEnvironmentRequest() + ) + 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 = gcdc_environment.UpdateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.update_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_environment_rest_bad_request( + transport: str = "rest", request_type=gcdc_environment.UpdateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + } + request_init["environment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4", + "display_name": "display_name_value", + "description": "description_value", + "version_configs": [{"version": "version_value"}], + "update_time": {"seconds": 751, "nanos": 543}, + "test_cases_config": { + "test_cases": ["test_cases_value1", "test_cases_value2"], + "enable_continuous_run": True, + "enable_predeployment_run": True, + }, + "webhook_config": { + "webhook_overrides": [ + { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [ + b"allowed_ca_certs_blob1", + b"allowed_ca_certs_blob2", + ], + }, + "service_directory": { + "service": "service_value", + "generic_web_service": {}, + }, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + ] + }, + } + 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_environment(request) + + +def test_update_environment_rest_flattened(): + client = EnvironmentsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "environment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + environment=gcdc_environment.Environment(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 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_environment(**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/v3beta1/{environment.name=projects/*/locations/*/agents/*/environments/*}" + % client.transport._host, + args[1], + ) + + +def test_update_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + gcdc_environment.UpdateEnvironmentRequest(), + environment=gcdc_environment.Environment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.DeleteEnvironmentRequest, + dict, + ], +) +def test_delete_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/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 = 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_environment(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_environment_rest_required_fields( + request_type=environment.DeleteEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_environment._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_environment._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 = EnvironmentsClient( + 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_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "pre_delete_environment" + ) as pre: + pre.assert_not_called() + pb_message = environment.DeleteEnvironmentRequest.pb( + environment.DeleteEnvironmentRequest() + ) + 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 = environment.DeleteEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_environment_rest_bad_request( + transport: str = "rest", request_type=environment.DeleteEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_environment(request) + + +def test_delete_environment_rest_flattened(): + client = EnvironmentsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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_environment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_environment_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_environment( + environment.DeleteEnvironmentRequest(), + name="name_value", + ) + + +def test_delete_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.LookupEnvironmentHistoryRequest, + dict, + ], +) +def test_lookup_environment_history_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/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 = environment.LookupEnvironmentHistoryResponse( + 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 = environment.LookupEnvironmentHistoryResponse.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.lookup_environment_history(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.LookupEnvironmentHistoryPager) + assert response.next_page_token == "next_page_token_value" + + +def test_lookup_environment_history_rest_required_fields( + request_type=environment.LookupEnvironmentHistoryRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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() + ).lookup_environment_history._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() + ).lookup_environment_history._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", + ) + ) + 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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.LookupEnvironmentHistoryResponse() + # 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 = environment.LookupEnvironmentHistoryResponse.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.lookup_environment_history(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_lookup_environment_history_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.lookup_environment_history._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("name",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_lookup_environment_history_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_lookup_environment_history" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_lookup_environment_history" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.LookupEnvironmentHistoryRequest.pb( + environment.LookupEnvironmentHistoryRequest() + ) + 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 = ( + environment.LookupEnvironmentHistoryResponse.to_json( + environment.LookupEnvironmentHistoryResponse() + ) + ) + + request = environment.LookupEnvironmentHistoryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.LookupEnvironmentHistoryResponse() + + client.lookup_environment_history( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_lookup_environment_history_rest_bad_request( + transport: str = "rest", request_type=environment.LookupEnvironmentHistoryRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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.lookup_environment_history(request) + + +def test_lookup_environment_history_rest_flattened(): + client = EnvironmentsClient( + 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 = environment.LookupEnvironmentHistoryResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = environment.LookupEnvironmentHistoryResponse.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.lookup_environment_history(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*}:lookupEnvironmentHistory" + % client.transport._host, + args[1], + ) + + +def test_lookup_environment_history_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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.lookup_environment_history( + environment.LookupEnvironmentHistoryRequest(), + name="name_value", + ) + + +def test_lookup_environment_history_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( + 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 = ( + environment.LookupEnvironmentHistoryResponse( + environments=[ + environment.Environment(), + environment.Environment(), + environment.Environment(), + ], + next_page_token="abc", + ), + environment.LookupEnvironmentHistoryResponse( + environments=[], + next_page_token="def", + ), + environment.LookupEnvironmentHistoryResponse( + environments=[ + environment.Environment(), + ], + next_page_token="ghi", + ), + environment.LookupEnvironmentHistoryResponse( + environments=[ + environment.Environment(), + environment.Environment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.LookupEnvironmentHistoryResponse.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 = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + pager = client.lookup_environment_history(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.Environment) for i in results) + + pages = list(client.lookup_environment_history(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", + [ + environment.RunContinuousTestRequest, + dict, + ], +) +def test_run_continuous_test_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/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(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.run_continuous_test(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_run_continuous_test_rest_required_fields( + request_type=environment.RunContinuousTestRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["environment"] = "" + 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() + ).run_continuous_test._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["environment"] = "environment_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).run_continuous_test._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "environment" in jsonified_request + assert jsonified_request["environment"] == "environment_value" + + client = EnvironmentsClient( + 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.run_continuous_test(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_run_continuous_test_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.run_continuous_test._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("environment",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_run_continuous_test_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_run_continuous_test" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_run_continuous_test" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.RunContinuousTestRequest.pb( + environment.RunContinuousTestRequest() + ) + 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 = environment.RunContinuousTestRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.run_continuous_test( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_run_continuous_test_rest_bad_request( + transport: str = "rest", request_type=environment.RunContinuousTestRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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.run_continuous_test(request) + + +def test_run_continuous_test_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.ListContinuousTestResultsRequest, + dict, + ], +) +def test_list_continuous_test_results_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/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 = environment.ListContinuousTestResultsResponse( + 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 = environment.ListContinuousTestResultsResponse.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_continuous_test_results(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListContinuousTestResultsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_continuous_test_results_rest_required_fields( + request_type=environment.ListContinuousTestResultsRequest, +): + transport_class = transports.EnvironmentsRestTransport + + 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_continuous_test_results._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_continuous_test_results._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", + ) + ) + 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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.ListContinuousTestResultsResponse() + # 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 = environment.ListContinuousTestResultsResponse.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_continuous_test_results(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_continuous_test_results_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_continuous_test_results._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_continuous_test_results_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_list_continuous_test_results" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_list_continuous_test_results" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.ListContinuousTestResultsRequest.pb( + environment.ListContinuousTestResultsRequest() + ) + 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 = ( + environment.ListContinuousTestResultsResponse.to_json( + environment.ListContinuousTestResultsResponse() + ) + ) + + request = environment.ListContinuousTestResultsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.ListContinuousTestResultsResponse() + + client.list_continuous_test_results( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_continuous_test_results_rest_bad_request( + transport: str = "rest", request_type=environment.ListContinuousTestResultsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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_continuous_test_results(request) + + +def test_list_continuous_test_results_rest_flattened(): + client = EnvironmentsClient( + 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 = environment.ListContinuousTestResultsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = environment.ListContinuousTestResultsResponse.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_continuous_test_results(**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/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/continuousTestResults" + % client.transport._host, + args[1], + ) + + +def test_list_continuous_test_results_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( + 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_continuous_test_results( + environment.ListContinuousTestResultsRequest(), + parent="parent_value", + ) + + +def test_list_continuous_test_results_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( + 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 = ( + environment.ListContinuousTestResultsResponse( + continuous_test_results=[ + environment.ContinuousTestResult(), + environment.ContinuousTestResult(), + environment.ContinuousTestResult(), + ], + next_page_token="abc", + ), + environment.ListContinuousTestResultsResponse( + continuous_test_results=[], + next_page_token="def", + ), + environment.ListContinuousTestResultsResponse( + continuous_test_results=[ + environment.ContinuousTestResult(), + ], + next_page_token="ghi", + ), + environment.ListContinuousTestResultsResponse( + continuous_test_results=[ + environment.ContinuousTestResult(), + environment.ContinuousTestResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.ListContinuousTestResultsResponse.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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + pager = client.list_continuous_test_results(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.ContinuousTestResult) for i in results) + + pages = list(client.list_continuous_test_results(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", + [ + environment.DeployFlowRequest, + dict, + ], +) +def test_deploy_flow_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/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(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.deploy_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_deploy_flow_rest_required_fields(request_type=environment.DeployFlowRequest): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["environment"] = "" + request_init["flow_version"] = "" + 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() + ).deploy_flow._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["environment"] = "environment_value" + jsonified_request["flowVersion"] = "flow_version_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).deploy_flow._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "environment" in jsonified_request + assert jsonified_request["environment"] == "environment_value" + assert "flowVersion" in jsonified_request + assert jsonified_request["flowVersion"] == "flow_version_value" + + client = EnvironmentsClient( + 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.deploy_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_deploy_flow_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.deploy_flow._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "environment", + "flowVersion", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_deploy_flow_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(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.EnvironmentsRestInterceptor, "post_deploy_flow" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_deploy_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.DeployFlowRequest.pb(environment.DeployFlowRequest()) + 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 = environment.DeployFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.deploy_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_deploy_flow_rest_bad_request( + transport: str = "rest", request_type=environment.DeployFlowRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + 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.deploy_flow(request) + + +def test_deploy_flow_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EnvironmentsClient( + 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 = EnvironmentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EnvironmentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EnvironmentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EnvironmentsGrpcTransport, + transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, + ], +) +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 = EnvironmentsClient.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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EnvironmentsGrpcTransport, + ) + + +def test_environments_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_environments_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.environments.transports.EnvironmentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly # raise NotImplementedError. methods = ( "list_environments", @@ -3537,6 +6279,7 @@ def test_environments_transport_auth_adc(transport_class): [ transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, ], ) def test_environments_transport_auth_gdch_credentials(transport_class): @@ -3634,11 +6377,40 @@ def test_environments_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_environments_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.EnvironmentsRestTransport( + 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_environments_rest_lro_client(): + client = EnvironmentsClient( + 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_environments_host_no_port(transport_name): @@ -3649,7 +6421,11 @@ def test_environments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3657,6 +6433,7 @@ def test_environments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_environments_host_with_port(transport_name): @@ -3667,7 +6444,57 @@ def test_environments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_environments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EnvironmentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EnvironmentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_environments._session + session2 = client2.transport.list_environments._session + assert session1 != session2 + session1 = client1.transport.get_environment._session + session2 = client2.transport.get_environment._session + assert session1 != session2 + session1 = client1.transport.create_environment._session + session2 = client2.transport.create_environment._session + assert session1 != session2 + session1 = client1.transport.update_environment._session + session2 = client2.transport.update_environment._session + assert session1 != session2 + session1 = client1.transport.delete_environment._session + session2 = client2.transport.delete_environment._session + assert session1 != session2 + session1 = client1.transport.lookup_environment_history._session + session2 = client2.transport.lookup_environment_history._session + assert session1 != session2 + session1 = client1.transport.run_continuous_test._session + session2 = client2.transport.run_continuous_test._session + assert session1 != session2 + session1 = client1.transport.list_continuous_test_results._session + session2 = client2.transport.list_continuous_test_results._session + assert session1 != session2 + session1 = client1.transport.deploy_flow._session + session2 = client2.transport.deploy_flow._session + assert session1 != session2 def test_environments_grpc_transport_channel(): @@ -4178,6 +7005,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4895,6 +8008,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4912,6 +8026,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py index 80d925d1..2fbc1e15 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.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 @@ -100,6 +107,7 @@ def test__get_default_mtls_endpoint(): [ (ExperimentsClient, "grpc"), (ExperimentsAsyncClient, "grpc_asyncio"), + (ExperimentsClient, "rest"), ], ) def test_experiments_client_from_service_account_info(client_class, transport_name): @@ -113,7 +121,11 @@ def test_experiments_client_from_service_account_info(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -121,6 +133,7 @@ def test_experiments_client_from_service_account_info(client_class, transport_na [ (transports.ExperimentsGrpcTransport, "grpc"), (transports.ExperimentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ExperimentsRestTransport, "rest"), ], ) def test_experiments_client_service_account_always_use_jwt( @@ -146,6 +159,7 @@ def test_experiments_client_service_account_always_use_jwt( [ (ExperimentsClient, "grpc"), (ExperimentsAsyncClient, "grpc_asyncio"), + (ExperimentsClient, "rest"), ], ) def test_experiments_client_from_service_account_file(client_class, transport_name): @@ -166,13 +180,18 @@ def test_experiments_client_from_service_account_file(client_class, transport_na assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_experiments_client_get_transport_class(): transport = ExperimentsClient.get_transport_class() available_transports = [ transports.ExperimentsGrpcTransport, + transports.ExperimentsRestTransport, ] assert transport in available_transports @@ -189,6 +208,7 @@ def test_experiments_client_get_transport_class(): transports.ExperimentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -332,6 +352,8 @@ def test_experiments_client_client_options( "grpc_asyncio", "false", ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest", "true"), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -525,6 +547,7 @@ def test_experiments_client_get_mtls_endpoint_and_cert_source(client_class): transports.ExperimentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest"), ], ) def test_experiments_client_client_options_scopes( @@ -560,6 +583,7 @@ def test_experiments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ExperimentsClient, transports.ExperimentsRestTransport, "rest", None), ], ) def test_experiments_client_client_options_credentials_file( @@ -2612,209 +2636,2511 @@ async def test_stop_experiment_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ExperimentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + experiment.ListExperimentsRequest, + dict, + ], +) +def test_list_experiments_rest(request_type): + client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ExperimentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ExperimentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ExperimentsClient( - 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 = experiment.ListExperimentsResponse( + next_page_token="next_page_token_value", ) - # 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 = ExperimentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.ListExperimentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_experiments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListExperimentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_experiments_rest_required_fields( + request_type=experiment.ListExperimentsRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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, + ) ) - with pytest.raises(ValueError): - client = ExperimentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_experiments._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_experiments._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", ) + ) + 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_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ExperimentsGrpcTransport( + client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = ExperimentsClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.ListExperimentsResponse() + # 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 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ExperimentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = experiment.ListExperimentsResponse.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_experiments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_experiments_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.ExperimentsGrpcAsyncIOTransport( + unset_fields = transport.list_experiments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_experiments_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_list_experiments" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_list_experiments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.ListExperimentsRequest.pb( + experiment.ListExperimentsRequest() + ) + 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 = experiment.ListExperimentsResponse.to_json( + experiment.ListExperimentsResponse() + ) + request = experiment.ListExperimentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.ListExperimentsResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.ExperimentsGrpcTransport, - transports.ExperimentsGrpcAsyncIOTransport, - ], -) -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() + client.list_experiments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = ExperimentsClient.get_transport_class(transport_name)( + +def test_list_experiments_rest_bad_request( + transport: str = "rest", request_type=experiment.ListExperimentsRequest +): + client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # 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_experiments(request) + + +def test_list_experiments_rest_flattened(): client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ExperimentsGrpcTransport, + 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 = experiment.ListExperimentsResponse() -def test_experiments_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ExperimentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # 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 = experiment.ListExperimentsResponse.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_experiments_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.experiments.transports.ExperimentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ExperimentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_experiments(**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/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/experiments" + % client.transport._host, + args[1], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_experiments", - "get_experiment", - "create_experiment", - "update_experiment", - "delete_experiment", - "start_experiment", - "stop_experiment", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + +def test_list_experiments_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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() + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_experiments( + experiment.ListExperimentsRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_experiments_rest_pager(transport: str = "rest"): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_experiments_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.dialogflowcx_v3beta1.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.ExperimentsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", + # 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 = ( + experiment.ListExperimentsResponse( + experiments=[ + experiment.Experiment(), + experiment.Experiment(), + experiment.Experiment(), + ], + next_page_token="abc", + ), + experiment.ListExperimentsResponse( + experiments=[], + next_page_token="def", + ), + experiment.ListExperimentsResponse( + experiments=[ + experiment.Experiment(), + ], + next_page_token="ghi", + ), + experiment.ListExperimentsResponse( + experiments=[ + experiment.Experiment(), + experiment.Experiment(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple( + experiment.ListExperimentsResponse.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 -def test_experiments_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.dialogflowcx_v3beta1.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.ExperimentsTransport() - adc.assert_called_once() + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + pager = client.list_experiments(request=sample_request) -def test_experiments_auth_adc(): - # If no credentials are provided, we should use ADC credentials. + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, experiment.Experiment) for i in results) + + pages = list(client.list_experiments(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", + [ + experiment.GetExperimentRequest, + dict, + ], +) +def test_get_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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 = experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.Experiment.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_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_get_experiment_rest_required_fields( + request_type=experiment.GetExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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_experiment._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_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.Experiment() + # 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 = experiment.Experiment.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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_get_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_get_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.GetExperimentRequest.pb( + experiment.GetExperimentRequest() + ) + 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 = experiment.Experiment.to_json( + experiment.Experiment() + ) + + request = experiment.GetExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.Experiment() + + client.get_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.GetExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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_experiment(request) + + +def test_get_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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 = experiment.Experiment.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_experiment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}" + % client.transport._host, + args[1], + ) + + +def test_get_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + experiment.GetExperimentRequest(), + name="name_value", + ) + + +def test_get_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_experiment.CreateExperimentRequest, + dict, + ], +) +def test_create_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request_init["experiment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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 = gcdc_experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=gcdc_experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_experiment.Experiment.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_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == gcdc_experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_create_experiment_rest_required_fields( + request_type=gcdc_experiment.CreateExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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() + ).create_experiment._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() + ).create_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_experiment.Experiment() + # 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 = gcdc_experiment.Experiment.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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_experiment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "experiment", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_create_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_create_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_experiment.CreateExperimentRequest.pb( + gcdc_experiment.CreateExperimentRequest() + ) + 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 = gcdc_experiment.Experiment.to_json( + gcdc_experiment.Experiment() + ) + + request = gcdc_experiment.CreateExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_experiment.Experiment() + + client.create_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_experiment_rest_bad_request( + transport: str = "rest", request_type=gcdc_experiment.CreateExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + request_init["experiment"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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_experiment(request) + + +def test_create_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = gcdc_experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/environments/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + experiment=gcdc_experiment.Experiment(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 = gcdc_experiment.Experiment.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_experiment(**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/v3beta1/{parent=projects/*/locations/*/agents/*/environments/*}/experiments" + % client.transport._host, + args[1], + ) + + +def test_create_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + gcdc_experiment.CreateExperimentRequest(), + parent="parent_value", + experiment=gcdc_experiment.Experiment(name="name_value"), + ) + + +def test_create_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_experiment.UpdateExperimentRequest, + dict, + ], +) +def test_update_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "experiment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + } + request_init["experiment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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 = gcdc_experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=gcdc_experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_experiment.Experiment.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_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == gcdc_experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_update_experiment_rest_required_fields( + request_type=gcdc_experiment.UpdateExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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_experiment._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_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_experiment.Experiment() + # 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 = gcdc_experiment.Experiment.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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_experiment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "experiment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_update_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_update_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_experiment.UpdateExperimentRequest.pb( + gcdc_experiment.UpdateExperimentRequest() + ) + 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 = gcdc_experiment.Experiment.to_json( + gcdc_experiment.Experiment() + ) + + request = gcdc_experiment.UpdateExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_experiment.Experiment() + + client.update_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_experiment_rest_bad_request( + transport: str = "rest", request_type=gcdc_experiment.UpdateExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "experiment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + } + request_init["experiment"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5", + "display_name": "display_name_value", + "description": "description_value", + "state": 1, + "definition": { + "condition": "condition_value", + "version_variants": { + "variants": [ + { + "version": "version_value", + "traffic_allocation": 0.1892, + "is_control_group": True, + } + ] + }, + }, + "rollout_config": { + "rollout_steps": [ + { + "display_name": "display_name_value", + "traffic_percent": 1583, + "min_duration": {"seconds": 751, "nanos": 543}, + } + ], + "rollout_condition": "rollout_condition_value", + "failure_condition": "failure_condition_value", + }, + "rollout_state": { + "step": "step_value", + "step_index": 1075, + "start_time": {"seconds": 751, "nanos": 543}, + }, + "rollout_failure_reason": "rollout_failure_reason_value", + "result": { + "version_metrics": [ + { + "version": "version_value", + "metrics": [ + { + "type_": 1, + "count_type": 1, + "ratio": 0.543, + "count": 0.553, + "confidence_interval": { + "confidence_level": 0.16690000000000002, + "ratio": 0.543, + "lower_bound": 0.1184, + "upper_bound": 0.1187, + }, + } + ], + "session_count": 1420, + } + ], + "last_update_time": {}, + }, + "create_time": {}, + "start_time": {}, + "end_time": {}, + "last_update_time": {}, + "experiment_length": {}, + "variants_history": [{"version_variants": {}, "update_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_experiment(request) + + +def test_update_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = gcdc_experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "experiment": { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + experiment=gcdc_experiment.Experiment(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 = gcdc_experiment.Experiment.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_experiment(**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/v3beta1/{experiment.name=projects/*/locations/*/agents/*/environments/*/experiments/*}" + % client.transport._host, + args[1], + ) + + +def test_update_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + gcdc_experiment.UpdateExperimentRequest(), + experiment=gcdc_experiment.Experiment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + experiment.DeleteExperimentRequest, + dict, + ], +) +def test_delete_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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_experiment(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_experiment_rest_required_fields( + request_type=experiment.DeleteExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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_experiment._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_experiment._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 = ExperimentsClient( + 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_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "pre_delete_experiment" + ) as pre: + pre.assert_not_called() + pb_message = experiment.DeleteExperimentRequest.pb( + experiment.DeleteExperimentRequest() + ) + 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 = experiment.DeleteExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.DeleteExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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_experiment(request) + + +def test_delete_experiment_rest_flattened(): + client = ExperimentsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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_experiment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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_experiment( + experiment.DeleteExperimentRequest(), + name="name_value", + ) + + +def test_delete_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + experiment.StartExperimentRequest, + dict, + ], +) +def test_start_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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 = experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.Experiment.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.start_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_start_experiment_rest_required_fields( + request_type=experiment.StartExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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() + ).start_experiment._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() + ).start_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.Experiment() + # 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 = experiment.Experiment.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.start_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_start_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.start_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_start_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_start_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_start_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.StartExperimentRequest.pb( + experiment.StartExperimentRequest() + ) + 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 = experiment.Experiment.to_json( + experiment.Experiment() + ) + + request = experiment.StartExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.Experiment() + + client.start_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_start_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.StartExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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.start_experiment(request) + + +def test_start_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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 = experiment.Experiment.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.start_experiment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:start" + % client.transport._host, + args[1], + ) + + +def test_start_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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.start_experiment( + experiment.StartExperimentRequest(), + name="name_value", + ) + + +def test_start_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + experiment.StopExperimentRequest, + dict, + ], +) +def test_stop_experiment_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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 = experiment.Experiment( + name="name_value", + display_name="display_name_value", + description="description_value", + state=experiment.Experiment.State.DRAFT, + rollout_failure_reason="rollout_failure_reason_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = experiment.Experiment.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.stop_experiment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, experiment.Experiment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == experiment.Experiment.State.DRAFT + assert response.rollout_failure_reason == "rollout_failure_reason_value" + + +def test_stop_experiment_rest_required_fields( + request_type=experiment.StopExperimentRequest, +): + transport_class = transports.ExperimentsRestTransport + + 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() + ).stop_experiment._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() + ).stop_experiment._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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = experiment.Experiment() + # 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 = experiment.Experiment.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.stop_experiment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_stop_experiment_rest_unset_required_fields(): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.stop_experiment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_stop_experiment_rest_interceptors(null_interceptor): + transport = transports.ExperimentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ExperimentsRestInterceptor(), + ) + client = ExperimentsClient(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.ExperimentsRestInterceptor, "post_stop_experiment" + ) as post, mock.patch.object( + transports.ExperimentsRestInterceptor, "pre_stop_experiment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = experiment.StopExperimentRequest.pb( + experiment.StopExperimentRequest() + ) + 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 = experiment.Experiment.to_json( + experiment.Experiment() + ) + + request = experiment.StopExperimentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = experiment.Experiment() + + client.stop_experiment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_stop_experiment_rest_bad_request( + transport: str = "rest", request_type=experiment.StopExperimentRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + 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.stop_experiment(request) + + +def test_stop_experiment_rest_flattened(): + client = ExperimentsClient( + 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 = experiment.Experiment() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/environments/sample4/experiments/sample5" + } + + # 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 = experiment.Experiment.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.stop_experiment(**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/v3beta1/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:stop" + % client.transport._host, + args[1], + ) + + +def test_stop_experiment_rest_flattened_error(transport: str = "rest"): + client = ExperimentsClient( + 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.stop_experiment( + experiment.StopExperimentRequest(), + name="name_value", + ) + + +def test_stop_experiment_rest_error(): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExperimentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ExperimentsClient( + 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 = ExperimentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ExperimentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ExperimentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ExperimentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ExperimentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ExperimentsGrpcTransport, + transports.ExperimentsGrpcAsyncIOTransport, + transports.ExperimentsRestTransport, + ], +) +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 = ExperimentsClient.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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ExperimentsGrpcTransport, + ) + + +def test_experiments_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ExperimentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_experiments_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.experiments.transports.ExperimentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ExperimentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_experiments", + "get_experiment", + "create_experiment", + "update_experiment", + "delete_experiment", + "start_experiment", + "stop_experiment", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_experiments_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.dialogflowcx_v3beta1.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ExperimentsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_experiments_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.dialogflowcx_v3beta1.services.experiments.transports.ExperimentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ExperimentsTransport() + adc.assert_called_once() + + +def test_experiments_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) ExperimentsClient() @@ -2856,6 +5182,7 @@ def test_experiments_transport_auth_adc(transport_class): [ transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport, + transports.ExperimentsRestTransport, ], ) def test_experiments_transport_auth_gdch_credentials(transport_class): @@ -2953,11 +5280,23 @@ def test_experiments_grpc_transport_client_cert_source_for_mtls(transport_class) ) +def test_experiments_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.ExperimentsRestTransport( + 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_experiments_host_no_port(transport_name): @@ -2968,7 +5307,11 @@ def test_experiments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2976,6 +5319,7 @@ def test_experiments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_experiments_host_with_port(transport_name): @@ -2986,7 +5330,51 @@ def test_experiments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_experiments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ExperimentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ExperimentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_experiments._session + session2 = client2.transport.list_experiments._session + assert session1 != session2 + session1 = client1.transport.get_experiment._session + session2 = client2.transport.get_experiment._session + assert session1 != session2 + session1 = client1.transport.create_experiment._session + session2 = client2.transport.create_experiment._session + assert session1 != session2 + session1 = client1.transport.update_experiment._session + session2 = client2.transport.update_experiment._session + assert session1 != session2 + session1 = client1.transport.delete_experiment._session + session2 = client2.transport.delete_experiment._session + assert session1 != session2 + session1 = client1.transport.start_experiment._session + session2 = client2.transport.start_experiment._session + assert session1 != session2 + session1 = client1.transport.stop_experiment._session + session2 = client2.transport.stop_experiment._session + assert session1 != session2 def test_experiments_grpc_transport_channel(): @@ -3313,6 +5701,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ExperimentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ExperimentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4030,6 +6704,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4047,6 +6722,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py index a5b0de3f..f1fe3715 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.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 @@ -104,6 +111,7 @@ def test__get_default_mtls_endpoint(): [ (FlowsClient, "grpc"), (FlowsAsyncClient, "grpc_asyncio"), + (FlowsClient, "rest"), ], ) def test_flows_client_from_service_account_info(client_class, transport_name): @@ -117,7 +125,11 @@ def test_flows_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -125,6 +137,7 @@ def test_flows_client_from_service_account_info(client_class, transport_name): [ (transports.FlowsGrpcTransport, "grpc"), (transports.FlowsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.FlowsRestTransport, "rest"), ], ) def test_flows_client_service_account_always_use_jwt(transport_class, transport_name): @@ -148,6 +161,7 @@ def test_flows_client_service_account_always_use_jwt(transport_class, transport_ [ (FlowsClient, "grpc"), (FlowsAsyncClient, "grpc_asyncio"), + (FlowsClient, "rest"), ], ) def test_flows_client_from_service_account_file(client_class, transport_name): @@ -168,13 +182,18 @@ def test_flows_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_flows_client_get_transport_class(): transport = FlowsClient.get_transport_class() available_transports = [ transports.FlowsGrpcTransport, + transports.FlowsRestTransport, ] assert transport in available_transports @@ -187,6 +206,7 @@ def test_flows_client_get_transport_class(): [ (FlowsClient, transports.FlowsGrpcTransport, "grpc"), (FlowsAsyncClient, transports.FlowsGrpcAsyncIOTransport, "grpc_asyncio"), + (FlowsClient, transports.FlowsRestTransport, "rest"), ], ) @mock.patch.object( @@ -326,6 +346,8 @@ def test_flows_client_client_options(client_class, transport_class, transport_na "grpc_asyncio", "false", ), + (FlowsClient, transports.FlowsRestTransport, "rest", "true"), + (FlowsClient, transports.FlowsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -511,6 +533,7 @@ def test_flows_client_get_mtls_endpoint_and_cert_source(client_class): [ (FlowsClient, transports.FlowsGrpcTransport, "grpc"), (FlowsAsyncClient, transports.FlowsGrpcAsyncIOTransport, "grpc_asyncio"), + (FlowsClient, transports.FlowsRestTransport, "rest"), ], ) def test_flows_client_client_options_scopes( @@ -546,6 +569,7 @@ def test_flows_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (FlowsClient, transports.FlowsRestTransport, "rest", None), ], ) def test_flows_client_client_options_credentials_file( @@ -2944,209 +2968,3187 @@ async def test_export_flow_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.FlowsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcdc_flow.CreateFlowRequest, + dict, + ], +) +def test_create_flow_rest(request_type): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = FlowsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["flow"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + 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 = gcdc_flow.Flow( + name="name_value", + display_name="display_name_value", + description="description_value", + transition_route_groups=["transition_route_groups_value"], ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.FlowsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = FlowsClient( - 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 = gcdc_flow.Flow.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_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_flow.Flow) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_create_flow_rest_required_fields(request_type=gcdc_flow.CreateFlowRequest): + transport_class = transports.FlowsRestTransport + + 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 an api_key and a transport instance. - transport = transports.FlowsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_flow._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() + ).create_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_flow.Flow() + # 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 = gcdc_flow.Flow.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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = FlowsClient( - 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 = FlowsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_flow._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "flow", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.FlowsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), ) - with pytest.raises(ValueError): - client = FlowsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = FlowsClient(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.FlowsRestInterceptor, "post_create_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_create_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_flow.CreateFlowRequest.pb(gcdc_flow.CreateFlowRequest()) + 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 = gcdc_flow.Flow.to_json(gcdc_flow.Flow()) + + request = gcdc_flow.CreateFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_flow.Flow() + + client.create_flow( + 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.FlowsGrpcTransport( + +def test_create_flow_rest_bad_request( + transport: str = "rest", request_type=gcdc_flow.CreateFlowRequest +): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = FlowsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["flow"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.FlowsGrpcTransport( + # 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_flow(request) + + +def test_create_flow_rest_flattened(): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.FlowsGrpcAsyncIOTransport( + # 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 = gcdc_flow.Flow() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + flow=gcdc_flow.Flow(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 = gcdc_flow.Flow.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_flow(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/flows" + % client.transport._host, + args[1], + ) + + +def test_create_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( 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_flow( + gcdc_flow.CreateFlowRequest(), + parent="parent_value", + flow=gcdc_flow.Flow(name="name_value"), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.FlowsGrpcTransport, - transports.FlowsGrpcAsyncIOTransport, - ], -) -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_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + flow.DeleteFlowRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = FlowsClient.get_transport_class(transport_name)( +def test_delete_flow_rest(request_type): + client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = FlowsClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.FlowsGrpcTransport, - ) + # 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 = "" -def test_flows_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.FlowsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_flow(request) + # Establish that the response is the type that we expect. + assert response is None -def test_flows_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.flows.transports.FlowsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.FlowsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_flow", - "delete_flow", - "list_flows", - "get_flow", - "update_flow", - "train_flow", - "validate_flow", - "get_flow_validation_result", - "import_flow", - "export_flow", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", +def test_delete_flow_rest_required_fields(request_type=flow.DeleteFlowRequest): + transport_class = transports.FlowsRestTransport + + 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, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_flow._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # verify required fields with default values are now present + jsonified_request["name"] = "name_value" -def test_flows_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.dialogflowcx_v3beta1.services.flows.transports.FlowsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.FlowsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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" -def test_flows_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.dialogflowcx_v3beta1.services.flows.transports.FlowsTransport._prep_wrapped_messages" - ) as Transport: + client = FlowsClient( + 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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "pre_delete_flow" + ) as pre: + pre.assert_not_called() + pb_message = flow.DeleteFlowRequest.pb(flow.DeleteFlowRequest()) + 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 = flow.DeleteFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_flow_rest_bad_request( + transport: str = "rest", request_type=flow.DeleteFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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_flow(request) + + +def test_delete_flow_rest_flattened(): + client = FlowsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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_flow(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow( + flow.DeleteFlowRequest(), + name="name_value", + ) + + +def test_delete_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ListFlowsRequest, + dict, + ], +) +def test_list_flows_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = flow.ListFlowsResponse( + 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 = flow.ListFlowsResponse.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_flows(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListFlowsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_flows_rest_required_fields(request_type=flow.ListFlowsRequest): + transport_class = transports.FlowsRestTransport + + 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_flows._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_flows._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.ListFlowsResponse() + # 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 = flow.ListFlowsResponse.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_flows(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_flows_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_flows._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_flows_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_list_flows" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_list_flows" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ListFlowsRequest.pb(flow.ListFlowsRequest()) + 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 = flow.ListFlowsResponse.to_json( + flow.ListFlowsResponse() + ) + + request = flow.ListFlowsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.ListFlowsResponse() + + client.list_flows( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_flows_rest_bad_request( + transport: str = "rest", request_type=flow.ListFlowsRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.list_flows(request) + + +def test_list_flows_rest_flattened(): + client = FlowsClient( + 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 = flow.ListFlowsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = flow.ListFlowsResponse.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_flows(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/flows" + % client.transport._host, + args[1], + ) + + +def test_list_flows_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flows( + flow.ListFlowsRequest(), + parent="parent_value", + ) + + +def test_list_flows_rest_pager(transport: str = "rest"): + client = FlowsClient( + 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 = ( + flow.ListFlowsResponse( + flows=[ + flow.Flow(), + flow.Flow(), + flow.Flow(), + ], + next_page_token="abc", + ), + flow.ListFlowsResponse( + flows=[], + next_page_token="def", + ), + flow.ListFlowsResponse( + flows=[ + flow.Flow(), + ], + next_page_token="ghi", + ), + flow.ListFlowsResponse( + flows=[ + flow.Flow(), + flow.Flow(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(flow.ListFlowsResponse.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": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_flows(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, flow.Flow) for i in results) + + pages = list(client.list_flows(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", + [ + flow.GetFlowRequest, + dict, + ], +) +def test_get_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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 = flow.Flow( + name="name_value", + display_name="display_name_value", + description="description_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = flow.Flow.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_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.Flow) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_get_flow_rest_required_fields(request_type=flow.GetFlowRequest): + transport_class = transports.FlowsRestTransport + + 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_flow._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_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.Flow() + # 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 = flow.Flow.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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_get_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_get_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.GetFlowRequest.pb(flow.GetFlowRequest()) + 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 = flow.Flow.to_json(flow.Flow()) + + request = flow.GetFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.Flow() + + client.get_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_flow_rest_bad_request( + transport: str = "rest", request_type=flow.GetFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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_flow(request) + + +def test_get_flow_rest_flattened(): + client = FlowsClient( + 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 = flow.Flow() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = flow.Flow.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_flow(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}" + % client.transport._host, + args[1], + ) + + +def test_get_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow( + flow.GetFlowRequest(), + name="name_value", + ) + + +def test_get_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_flow.UpdateFlowRequest, + dict, + ], +) +def test_update_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "flow": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + } + request_init["flow"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + 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 = gcdc_flow.Flow( + name="name_value", + display_name="display_name_value", + description="description_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_flow.Flow.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_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_flow.Flow) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_update_flow_rest_required_fields(request_type=gcdc_flow.UpdateFlowRequest): + transport_class = transports.FlowsRestTransport + + 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_flow._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_flow._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_flow.Flow() + # 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 = gcdc_flow.Flow.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_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_flow._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("flow",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_update_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_update_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_flow.UpdateFlowRequest.pb(gcdc_flow.UpdateFlowRequest()) + 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 = gcdc_flow.Flow.to_json(gcdc_flow.Flow()) + + request = gcdc_flow.UpdateFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_flow.Flow() + + client.update_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_flow_rest_bad_request( + transport: str = "rest", request_type=gcdc_flow.UpdateFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "flow": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + } + request_init["flow"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4", + "display_name": "display_name_value", + "description": "description_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + } + 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_flow(request) + + +def test_update_flow_rest_flattened(): + client = FlowsClient( + 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 = gcdc_flow.Flow() + + # get arguments that satisfy an http rule for this method + sample_request = { + "flow": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + flow=gcdc_flow.Flow(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 = gcdc_flow.Flow.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_flow(**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/v3beta1/{flow.name=projects/*/locations/*/agents/*/flows/*}" + % client.transport._host, + args[1], + ) + + +def test_update_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow( + gcdc_flow.UpdateFlowRequest(), + flow=gcdc_flow.Flow(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.TrainFlowRequest, + dict, + ], +) +def test_train_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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(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.train_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_train_flow_rest_required_fields(request_type=flow.TrainFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).train_flow._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() + ).train_flow._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 = FlowsClient( + 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.train_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_train_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.train_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_train_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_train_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_train_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.TrainFlowRequest.pb(flow.TrainFlowRequest()) + 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 = flow.TrainFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.train_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_train_flow_rest_bad_request( + transport: str = "rest", request_type=flow.TrainFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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.train_flow(request) + + +def test_train_flow_rest_flattened(): + client = FlowsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.train_flow(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*}:train" + % client.transport._host, + args[1], + ) + + +def test_train_flow_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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.train_flow( + flow.TrainFlowRequest(), + name="name_value", + ) + + +def test_train_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ValidateFlowRequest, + dict, + ], +) +def test_validate_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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 = flow.FlowValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = flow.FlowValidationResult.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.validate_flow(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + assert response.name == "name_value" + + +def test_validate_flow_rest_required_fields(request_type=flow.ValidateFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).validate_flow._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() + ).validate_flow._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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.FlowValidationResult() + # 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 = flow.FlowValidationResult.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.validate_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_validate_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.validate_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_validate_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_validate_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_validate_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ValidateFlowRequest.pb(flow.ValidateFlowRequest()) + 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 = flow.FlowValidationResult.to_json( + flow.FlowValidationResult() + ) + + request = flow.ValidateFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.FlowValidationResult() + + client.validate_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_validate_flow_rest_bad_request( + transport: str = "rest", request_type=flow.ValidateFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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.validate_flow(request) + + +def test_validate_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.GetFlowValidationResultRequest, + dict, + ], +) +def test_get_flow_validation_result_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/validationResult" + } + 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 = flow.FlowValidationResult( + name="name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = flow.FlowValidationResult.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_flow_validation_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + assert response.name == "name_value" + + +def test_get_flow_validation_result_rest_required_fields( + request_type=flow.GetFlowValidationResultRequest, +): + transport_class = transports.FlowsRestTransport + + 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_flow_validation_result._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_flow_validation_result._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = flow.FlowValidationResult() + # 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 = flow.FlowValidationResult.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_flow_validation_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_flow_validation_result_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_flow_validation_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_flow_validation_result_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_get_flow_validation_result" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_get_flow_validation_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.GetFlowValidationResultRequest.pb( + flow.GetFlowValidationResultRequest() + ) + 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 = flow.FlowValidationResult.to_json( + flow.FlowValidationResult() + ) + + request = flow.GetFlowValidationResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = flow.FlowValidationResult() + + client.get_flow_validation_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_flow_validation_result_rest_bad_request( + transport: str = "rest", request_type=flow.GetFlowValidationResultRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/validationResult" + } + 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_flow_validation_result(request) + + +def test_get_flow_validation_result_rest_flattened(): + client = FlowsClient( + 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 = flow.FlowValidationResult() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/validationResult" + } + + # 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 = flow.FlowValidationResult.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_flow_validation_result(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/validationResult}" + % client.transport._host, + args[1], + ) + + +def test_get_flow_validation_result_rest_flattened_error(transport: str = "rest"): + client = FlowsClient( + 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_flow_validation_result( + flow.GetFlowValidationResultRequest(), + name="name_value", + ) + + +def test_get_flow_validation_result_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ImportFlowRequest, + dict, + ], +) +def test_import_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.import_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_flow_rest_required_fields(request_type=flow.ImportFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).import_flow._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() + ).import_flow._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 = FlowsClient( + 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.import_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_import_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_import_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ImportFlowRequest.pb(flow.ImportFlowRequest()) + 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 = flow.ImportFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_flow_rest_bad_request( + transport: str = "rest", request_type=flow.ImportFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.import_flow(request) + + +def test_import_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + flow.ExportFlowRequest, + dict, + ], +) +def test_export_flow_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/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(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.export_flow(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_flow_rest_required_fields(request_type=flow.ExportFlowRequest): + transport_class = transports.FlowsRestTransport + + 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() + ).export_flow._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() + ).export_flow._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 = FlowsClient( + 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.export_flow(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_flow_rest_unset_required_fields(): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_flow._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_flow_rest_interceptors(null_interceptor): + transport = transports.FlowsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.FlowsRestInterceptor(), + ) + client = FlowsClient(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.FlowsRestInterceptor, "post_export_flow" + ) as post, mock.patch.object( + transports.FlowsRestInterceptor, "pre_export_flow" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = flow.ExportFlowRequest.pb(flow.ExportFlowRequest()) + 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 = flow.ExportFlowRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_flow( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_flow_rest_bad_request( + transport: str = "rest", request_type=flow.ExportFlowRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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.export_flow(request) + + +def test_export_flow_rest_error(): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = FlowsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = FlowsClient( + 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 = FlowsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = FlowsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = FlowsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.FlowsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.FlowsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.FlowsGrpcTransport, + transports.FlowsGrpcAsyncIOTransport, + transports.FlowsRestTransport, + ], +) +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 = FlowsClient.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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.FlowsGrpcTransport, + ) + + +def test_flows_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.FlowsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_flows_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.flows.transports.FlowsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.FlowsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_flow", + "delete_flow", + "list_flows", + "get_flow", + "update_flow", + "train_flow", + "validate_flow", + "get_flow_validation_result", + "import_flow", + "export_flow", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_flows_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.dialogflowcx_v3beta1.services.flows.transports.FlowsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.FlowsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_flows_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.dialogflowcx_v3beta1.services.flows.transports.FlowsTransport._prep_wrapped_messages" + ) as Transport: Transport.return_value = None adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.FlowsTransport() @@ -3196,6 +6198,7 @@ def test_flows_transport_auth_adc(transport_class): [ transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport, + transports.FlowsRestTransport, ], ) def test_flows_transport_auth_gdch_credentials(transport_class): @@ -3293,11 +6296,40 @@ def test_flows_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_flows_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.FlowsRestTransport( + 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_flows_rest_lro_client(): + client = FlowsClient( + 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_flows_host_no_port(transport_name): @@ -3308,7 +6340,11 @@ def test_flows_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3316,6 +6352,7 @@ def test_flows_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_flows_host_with_port(transport_name): @@ -3326,7 +6363,60 @@ def test_flows_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_flows_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = FlowsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = FlowsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_flow._session + session2 = client2.transport.create_flow._session + assert session1 != session2 + session1 = client1.transport.delete_flow._session + session2 = client2.transport.delete_flow._session + assert session1 != session2 + session1 = client1.transport.list_flows._session + session2 = client2.transport.list_flows._session + assert session1 != session2 + session1 = client1.transport.get_flow._session + session2 = client2.transport.get_flow._session + assert session1 != session2 + session1 = client1.transport.update_flow._session + session2 = client2.transport.update_flow._session + assert session1 != session2 + session1 = client1.transport.train_flow._session + session2 = client2.transport.train_flow._session + assert session1 != session2 + session1 = client1.transport.validate_flow._session + session2 = client2.transport.validate_flow._session + assert session1 != session2 + session1 = client1.transport.get_flow_validation_result._session + session2 = client2.transport.get_flow_validation_result._session + assert session1 != session2 + session1 = client1.transport.import_flow._session + session2 = client2.transport.import_flow._session + assert session1 != session2 + session1 = client1.transport.export_flow._session + session2 = client2.transport.export_flow._session + assert session1 != session2 def test_flows_grpc_transport_channel(): @@ -3801,6 +6891,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = FlowsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = FlowsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4518,6 +7894,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4535,6 +7912,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py index c277e413..4dac57be 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.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 @@ -93,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_info(client_class, transport_name): @@ -106,7 +114,11 @@ def test_intents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -114,6 +126,7 @@ def test_intents_client_from_service_account_info(client_class, transport_name): [ (transports.IntentsGrpcTransport, "grpc"), (transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -137,6 +150,7 @@ def test_intents_client_service_account_always_use_jwt(transport_class, transpor [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_file(client_class, transport_name): @@ -157,13 +171,18 @@ def test_intents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_intents_client_get_transport_class(): transport = IntentsClient.get_transport_class() available_transports = [ transports.IntentsGrpcTransport, + transports.IntentsRestTransport, ] assert transport in available_transports @@ -176,6 +195,7 @@ def test_intents_client_get_transport_class(): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -315,6 +335,8 @@ def test_intents_client_client_options(client_class, transport_class, transport_ "grpc_asyncio", "false", ), + (IntentsClient, transports.IntentsRestTransport, "rest", "true"), + (IntentsClient, transports.IntentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -500,6 +522,7 @@ def test_intents_client_get_mtls_endpoint_and_cert_source(client_class): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_client_options_scopes( @@ -535,6 +558,7 @@ def test_intents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (IntentsClient, transports.IntentsRestTransport, "rest", None), ], ) def test_intents_client_client_options_credentials_file( @@ -2035,141 +2059,1682 @@ async def test_delete_intent_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.IntentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + intent.ListIntentsRequest, + dict, + ], +) +def test_list_intents_rest(request_type): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = IntentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = intent.ListIntentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.IntentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.ListIntentsResponse.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_intents(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListIntentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_intents_rest_required_fields(request_type=intent.ListIntentsRequest): + transport_class = transports.IntentsRestTransport + + 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_intents._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_intents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + "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 = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse() + # 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 = intent.ListIntentsResponse.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_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_intents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.IntentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = IntentsClient( - client_options=options, - transport=transport, + client = IntentsClient(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.IntentsRestInterceptor, "post_list_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_list_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.ListIntentsRequest.pb(intent.ListIntentsRequest()) + 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 = intent.ListIntentsResponse.to_json( + intent.ListIntentsResponse() ) - # 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 = IntentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = intent.ListIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.ListIntentsResponse() + + client.list_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.IntentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_intents_rest_bad_request( + transport: str = "rest", request_type=intent.ListIntentsRequest +): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( + # 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_intents(request) + + +def test_list_intents_rest_flattened(): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = IntentsClient(transport=transport) - assert client.transport is 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 = intent.ListIntentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = intent.ListIntentsResponse.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_intents(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/intents" + % client.transport._host, + args[1], + ) + + +def test_list_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.IntentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_intents( + intent.ListIntentsRequest(), + parent="parent_value", + ) + + +def test_list_intents_rest_pager(transport: str = "rest"): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + intent.Intent(), + ], + next_page_token="abc", + ), + intent.ListIntentsResponse( + intents=[], + next_page_token="def", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + ], + next_page_token="ghi", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(intent.ListIntentsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_intents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, intent.Intent) for i in results) + + pages = list(client.list_intents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + intent.GetIntentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = IntentsClient.get_transport_class(transport_name)( +def test_get_intent_rest(request_type): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/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 = intent.Intent( + name="name_value", + display_name="display_name_value", + priority=898, + is_fallback=True, + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.Intent.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_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.priority == 898 + assert response.is_fallback is True + assert response.description == "description_value" + + +def test_get_intent_rest_required_fields(request_type=intent.GetIntentRequest): + transport_class = transports.IntentsRestTransport + + 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_intent._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_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.IntentsGrpcTransport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.Intent() + # 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 = intent.Intent.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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_intent._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) -def test_intents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "post_get_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_get_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.GetIntentRequest.pb(intent.GetIntentRequest()) + 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 = intent.Intent.to_json(intent.Intent()) + + request = intent.GetIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.Intent() -def test_intents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.intents.transports.IntentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.get_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly + pre.assert_called_once() + post.assert_called_once() + + +def test_get_intent_rest_bad_request( + transport: str = "rest", request_type=intent.GetIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + 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_intent(request) + + +def test_get_intent_rest_flattened(): + client = IntentsClient( + 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 = intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + + # 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 = intent.Intent.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_intent(**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/v3beta1/{name=projects/*/locations/*/agents/*/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_get_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + intent.GetIntentRequest(), + name="name_value", + ) + + +def test_get_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_intent.CreateIntentRequest, + dict, + ], +) +def test_create_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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 = gcdc_intent.Intent( + name="name_value", + display_name="display_name_value", + priority=898, + is_fallback=True, + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_intent.Intent.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_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.priority == 898 + assert response.is_fallback is True + assert response.description == "description_value" + + +def test_create_intent_rest_required_fields( + request_type=gcdc_intent.CreateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + 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() + ).create_intent._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() + ).create_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_intent.Intent() + # 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 = gcdc_intent.Intent.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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "intent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "post_create_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_create_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_intent.CreateIntentRequest.pb( + gcdc_intent.CreateIntentRequest() + ) + 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 = gcdc_intent.Intent.to_json(gcdc_intent.Intent()) + + request = gcdc_intent.CreateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_intent.Intent() + + client.create_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_intent_rest_bad_request( + transport: str = "rest", request_type=gcdc_intent.CreateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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_intent(request) + + +def test_create_intent_rest_flattened(): + client = IntentsClient( + 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 = gcdc_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + intent=gcdc_intent.Intent(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 = gcdc_intent.Intent.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_intent(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/intents" + % client.transport._host, + args[1], + ) + + +def test_create_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + gcdc_intent.CreateIntentRequest(), + parent="parent_value", + intent=gcdc_intent.Intent(name="name_value"), + ) + + +def test_create_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_intent.UpdateIntentRequest, + dict, + ], +) +def test_update_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "intent": { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + } + request_init["intent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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 = gcdc_intent.Intent( + name="name_value", + display_name="display_name_value", + priority=898, + is_fallback=True, + description="description_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_intent.Intent.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_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.priority == 898 + assert response.is_fallback is True + assert response.description == "description_value" + + +def test_update_intent_rest_required_fields( + request_type=gcdc_intent.UpdateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + 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_intent._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_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_intent.Intent() + # 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 = gcdc_intent.Intent.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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("intent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "post_update_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_update_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_intent.UpdateIntentRequest.pb( + gcdc_intent.UpdateIntentRequest() + ) + 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 = gcdc_intent.Intent.to_json(gcdc_intent.Intent()) + + request = gcdc_intent.UpdateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_intent.Intent() + + client.update_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_intent_rest_bad_request( + transport: str = "rest", request_type=gcdc_intent.UpdateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "intent": { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + } + request_init["intent"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [{"text": "text_value", "parameter_id": "parameter_id_value"}], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + } + 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_intent(request) + + +def test_update_intent_rest_flattened(): + client = IntentsClient( + 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 = gcdc_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = { + "intent": { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + intent=gcdc_intent.Intent(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 = gcdc_intent.Intent.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_intent(**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/v3beta1/{intent.name=projects/*/locations/*/agents/*/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + gcdc_intent.UpdateIntentRequest(), + intent=gcdc_intent.Intent(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.DeleteIntentRequest, + dict, + ], +) +def test_delete_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/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 = 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_intent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_intent_rest_required_fields(request_type=intent.DeleteIntentRequest): + transport_class = transports.IntentsRestTransport + + 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_intent._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_intent._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 = IntentsClient( + 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_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_intent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(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.IntentsRestInterceptor, "pre_delete_intent" + ) as pre: + pre.assert_not_called() + pb_message = intent.DeleteIntentRequest.pb(intent.DeleteIntentRequest()) + 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 = intent.DeleteIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_intent_rest_bad_request( + transport: str = "rest", request_type=intent.DeleteIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + 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_intent(request) + + +def test_delete_intent_rest_flattened(): + client = IntentsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/intents/sample4" + } + + # 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_intent(**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/v3beta1/{name=projects/*/locations/*/agents/*/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + 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_intent( + intent.DeleteIntentRequest(), + name="name_value", + ) + + +def test_delete_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = IntentsClient( + 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 = IntentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = IntentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.IntentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, + ], +) +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 = IntentsClient.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 = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.IntentsGrpcTransport, + ) + + +def test_intents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_intents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.intents.transports.IntentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly # raise NotImplementedError. methods = ( "list_intents", @@ -2277,6 +3842,7 @@ def test_intents_transport_auth_adc(transport_class): [ transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, ], ) def test_intents_transport_auth_gdch_credentials(transport_class): @@ -2374,11 +3940,23 @@ def test_intents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_intents_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.IntentsRestTransport( + 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_intents_host_no_port(transport_name): @@ -2389,7 +3967,11 @@ def test_intents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2397,6 +3979,7 @@ def test_intents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_intents_host_with_port(transport_name): @@ -2407,7 +3990,45 @@ def test_intents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_intents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = IntentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = IntentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_intents._session + session2 = client2.transport.list_intents._session + assert session1 != session2 + session1 = client1.transport.get_intent._session + session2 = client2.transport.get_intent._session + assert session1 != session2 + session1 = client1.transport.create_intent._session + session2 = client2.transport.create_intent._session + assert session1 != session2 + session1 = client1.transport.update_intent._session + session2 = client2.transport.update_intent._session + assert session1 != session2 + session1 = client1.transport.delete_intent._session + session2 = client2.transport.delete_intent._session + assert session1 != session2 def test_intents_grpc_transport_channel(): @@ -2726,6 +4347,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3443,6 +5350,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3460,6 +5368,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py index 27b83665..f0dbc2ab 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.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 @@ -96,6 +103,7 @@ def test__get_default_mtls_endpoint(): [ (PagesClient, "grpc"), (PagesAsyncClient, "grpc_asyncio"), + (PagesClient, "rest"), ], ) def test_pages_client_from_service_account_info(client_class, transport_name): @@ -109,7 +117,11 @@ def test_pages_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -117,6 +129,7 @@ def test_pages_client_from_service_account_info(client_class, transport_name): [ (transports.PagesGrpcTransport, "grpc"), (transports.PagesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.PagesRestTransport, "rest"), ], ) def test_pages_client_service_account_always_use_jwt(transport_class, transport_name): @@ -140,6 +153,7 @@ def test_pages_client_service_account_always_use_jwt(transport_class, transport_ [ (PagesClient, "grpc"), (PagesAsyncClient, "grpc_asyncio"), + (PagesClient, "rest"), ], ) def test_pages_client_from_service_account_file(client_class, transport_name): @@ -160,13 +174,18 @@ def test_pages_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_pages_client_get_transport_class(): transport = PagesClient.get_transport_class() available_transports = [ transports.PagesGrpcTransport, + transports.PagesRestTransport, ] assert transport in available_transports @@ -179,6 +198,7 @@ def test_pages_client_get_transport_class(): [ (PagesClient, transports.PagesGrpcTransport, "grpc"), (PagesAsyncClient, transports.PagesGrpcAsyncIOTransport, "grpc_asyncio"), + (PagesClient, transports.PagesRestTransport, "rest"), ], ) @mock.patch.object( @@ -318,6 +338,8 @@ def test_pages_client_client_options(client_class, transport_class, transport_na "grpc_asyncio", "false", ), + (PagesClient, transports.PagesRestTransport, "rest", "true"), + (PagesClient, transports.PagesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -503,6 +525,7 @@ def test_pages_client_get_mtls_endpoint_and_cert_source(client_class): [ (PagesClient, transports.PagesGrpcTransport, "grpc"), (PagesAsyncClient, transports.PagesGrpcAsyncIOTransport, "grpc_asyncio"), + (PagesClient, transports.PagesRestTransport, "rest"), ], ) def test_pages_client_client_options_scopes( @@ -538,6 +561,7 @@ def test_pages_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (PagesClient, transports.PagesRestTransport, "rest", None), ], ) def test_pages_client_client_options_credentials_file( @@ -2014,168 +2038,2023 @@ async def test_delete_page_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.PagesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + page.ListPagesRequest, + dict, + ], +) +def test_list_pages_rest(request_type): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = PagesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/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 = page.ListPagesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.PagesGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = page.ListPagesResponse.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_pages(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListPagesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_pages_rest_required_fields(request_type=page.ListPagesRequest): + transport_class = transports.PagesRestTransport + + 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_pages._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_pages._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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 = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = PagesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = page.ListPagesResponse() + # 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 = page.ListPagesResponse.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_pages(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_pages_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_pages._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.PagesGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_pages_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = PagesClient( - client_options=options, - transport=transport, + client = PagesClient(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.PagesRestInterceptor, "post_list_pages" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_list_pages" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = page.ListPagesRequest.pb(page.ListPagesRequest()) + 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 = page.ListPagesResponse.to_json( + page.ListPagesResponse() ) - # 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 = PagesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = page.ListPagesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = page.ListPagesResponse() + + client.list_pages( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.PagesGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_pages_rest_bad_request( + transport: str = "rest", request_type=page.ListPagesRequest +): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = PagesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.PagesGrpcTransport( + # 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_pages(request) + + +def test_list_pages_rest_flattened(): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = PagesClient(transport=transport) - assert client.transport is 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 = page.ListPagesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.PagesGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = page.ListPagesResponse.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_pages(**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/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/pages" + % client.transport._host, + args[1], + ) + + +def test_list_pages_rest_flattened_error(transport: str = "rest"): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.PagesGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_pages( + page.ListPagesRequest(), + parent="parent_value", + ) + + +def test_list_pages_rest_pager(transport: str = "rest"): + client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + page.ListPagesResponse( + pages=[ + page.Page(), + page.Page(), + page.Page(), + ], + next_page_token="abc", + ), + page.ListPagesResponse( + pages=[], + next_page_token="def", + ), + page.ListPagesResponse( + pages=[ + page.Page(), + ], + next_page_token="ghi", + ), + page.ListPagesResponse( + pages=[ + page.Page(), + page.Page(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(page.ListPagesResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.PagesGrpcTransport, - transports.PagesGrpcAsyncIOTransport, - ], -) -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() + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + pager = client.list_pages(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, page.Page) for i in results) + + pages = list(client.list_pages(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + page.GetPageRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = PagesClient.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_page_rest(request_type): client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.PagesGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + request = request_type(**request_init) -def test_pages_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.PagesTransport( - 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 = page.Page( + name="name_value", + display_name="display_name_value", + transition_route_groups=["transition_route_groups_value"], ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = page.Page.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_pages_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.pages.transports.PagesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.PagesTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_page(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_pages", - "get_page", - "create_page", - "update_page", - "delete_page", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, page.Page) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_get_page_rest_required_fields(request_type=page.GetPageRequest): + transport_class = transports.PagesRestTransport + + 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, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_page._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_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = page.Page() + # 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 = page.Page.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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_page._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "post_get_page" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_get_page" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = page.GetPageRequest.pb(page.GetPageRequest()) + 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 = page.Page.to_json(page.Page()) + + request = page.GetPageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = page.Page() + + client.get_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_page_rest_bad_request( + transport: str = "rest", request_type=page.GetPageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + 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_page(request) + + +def test_get_page_rest_flattened(): + client = PagesClient( + 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 = page.Page() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + + # 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 = page.Page.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_page(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/pages/*}" + % client.transport._host, + args[1], + ) + + +def test_get_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + page.GetPageRequest(), + name="name_value", + ) + + +def test_get_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_page.CreatePageRequest, + dict, + ], +) +def test_create_page_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["page"] = { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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 = gcdc_page.Page( + name="name_value", + display_name="display_name_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_page.Page.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_page(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_page.Page) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_create_page_rest_required_fields(request_type=gcdc_page.CreatePageRequest): + transport_class = transports.PagesRestTransport + + 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() + ).create_page._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() + ).create_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_page.Page() + # 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 = gcdc_page.Page.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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_page._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "page", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "post_create_page" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_create_page" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_page.CreatePageRequest.pb(gcdc_page.CreatePageRequest()) + 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 = gcdc_page.Page.to_json(gcdc_page.Page()) + + request = gcdc_page.CreatePageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_page.Page() + + client.create_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_page_rest_bad_request( + transport: str = "rest", request_type=gcdc_page.CreatePageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["page"] = { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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_page(request) + + +def test_create_page_rest_flattened(): + client = PagesClient( + 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 = gcdc_page.Page() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + page=gcdc_page.Page(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 = gcdc_page.Page.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_page(**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/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/pages" + % client.transport._host, + args[1], + ) + + +def test_create_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + gcdc_page.CreatePageRequest(), + parent="parent_value", + page=gcdc_page.Page(name="name_value"), + ) + + +def test_create_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_page.UpdatePageRequest, + dict, + ], +) +def test_update_page_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "page": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + } + request_init["page"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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 = gcdc_page.Page( + name="name_value", + display_name="display_name_value", + transition_route_groups=["transition_route_groups_value"], + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_page.Page.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_page(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_page.Page) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.transition_route_groups == ["transition_route_groups_value"] + + +def test_update_page_rest_required_fields(request_type=gcdc_page.UpdatePageRequest): + transport_class = transports.PagesRestTransport + + 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_page._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_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_page.Page() + # 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 = gcdc_page.Page.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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_page._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("page",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "post_update_page" + ) as post, mock.patch.object( + transports.PagesRestInterceptor, "pre_update_page" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_page.UpdatePageRequest.pb(gcdc_page.UpdatePageRequest()) + 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 = gcdc_page.Page.to_json(gcdc_page.Page()) + + request = gcdc_page.UpdatePageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_page.Page() + + client.update_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_page_rest_bad_request( + transport: str = "rest", request_type=gcdc_page.UpdatePageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "page": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + } + request_init["page"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [{"message": {}, "additional_cases": {}}], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + } + 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_page(request) + + +def test_update_page_rest_flattened(): + client = PagesClient( + 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 = gcdc_page.Page() + + # get arguments that satisfy an http rule for this method + sample_request = { + "page": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + page=gcdc_page.Page(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 = gcdc_page.Page.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_page(**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/v3beta1/{page.name=projects/*/locations/*/agents/*/flows/*/pages/*}" + % client.transport._host, + args[1], + ) + + +def test_update_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + gcdc_page.UpdatePageRequest(), + page=gcdc_page.Page(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + page.DeletePageRequest, + dict, + ], +) +def test_delete_page_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + 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_page(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_page_rest_required_fields(request_type=page.DeletePageRequest): + transport_class = transports.PagesRestTransport + + 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_page._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_page._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = PagesClient( + 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_page(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_page_rest_unset_required_fields(): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_page._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_page_rest_interceptors(null_interceptor): + transport = transports.PagesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.PagesRestInterceptor(), + ) + client = PagesClient(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.PagesRestInterceptor, "pre_delete_page" + ) as pre: + pre.assert_not_called() + pb_message = page.DeletePageRequest.pb(page.DeletePageRequest()) + 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 = page.DeletePageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_page( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_page_rest_bad_request( + transport: str = "rest", request_type=page.DeletePageRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + 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_page(request) + + +def test_delete_page_rest_flattened(): + client = PagesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/pages/sample5" + } + + # 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_page(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/pages/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_page_rest_flattened_error(transport: str = "rest"): + client = PagesClient( + 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_page( + page.DeletePageRequest(), + name="name_value", + ) + + +def test_delete_page_rest_error(): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PagesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = PagesClient( + 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 = PagesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PagesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = PagesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.PagesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.PagesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PagesGrpcTransport, + transports.PagesGrpcAsyncIOTransport, + transports.PagesRestTransport, + ], +) +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 = PagesClient.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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.PagesGrpcTransport, + ) + + +def test_pages_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.PagesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_pages_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.pages.transports.PagesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.PagesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_pages", + "get_page", + "create_page", + "update_page", + "delete_page", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_pages_base_transport_with_credentials_file(): @@ -2256,6 +4135,7 @@ def test_pages_transport_auth_adc(transport_class): [ transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport, + transports.PagesRestTransport, ], ) def test_pages_transport_auth_gdch_credentials(transport_class): @@ -2353,11 +4233,23 @@ def test_pages_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_pages_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.PagesRestTransport( + 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_pages_host_no_port(transport_name): @@ -2368,7 +4260,11 @@ def test_pages_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2376,6 +4272,7 @@ def test_pages_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_pages_host_with_port(transport_name): @@ -2386,7 +4283,45 @@ def test_pages_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_pages_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = PagesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = PagesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_pages._session + session2 = client2.transport.list_pages._session + assert session1 != session2 + session1 = client1.transport.get_page._session + session2 = client2.transport.get_page._session + assert session1 != session2 + session1 = client1.transport.create_page._session + session2 = client2.transport.create_page._session + assert session1 != session2 + session1 = client1.transport.update_page._session + session2 = client2.transport.update_page._session + assert session1 != session2 + session1 = client1.transport.delete_page._session + session2 = client2.transport.delete_page._session + assert session1 != session2 def test_pages_grpc_transport_channel(): @@ -2827,6 +4762,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = PagesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = PagesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3544,6 +5765,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3561,6 +5783,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py index afa17471..bb266975 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_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 @@ -108,6 +115,7 @@ def test__get_default_mtls_endpoint(): [ (SecuritySettingsServiceClient, "grpc"), (SecuritySettingsServiceAsyncClient, "grpc_asyncio"), + (SecuritySettingsServiceClient, "rest"), ], ) def test_security_settings_service_client_from_service_account_info( @@ -123,7 +131,11 @@ def test_security_settings_service_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -131,6 +143,7 @@ def test_security_settings_service_client_from_service_account_info( [ (transports.SecuritySettingsServiceGrpcTransport, "grpc"), (transports.SecuritySettingsServiceGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SecuritySettingsServiceRestTransport, "rest"), ], ) def test_security_settings_service_client_service_account_always_use_jwt( @@ -156,6 +169,7 @@ def test_security_settings_service_client_service_account_always_use_jwt( [ (SecuritySettingsServiceClient, "grpc"), (SecuritySettingsServiceAsyncClient, "grpc_asyncio"), + (SecuritySettingsServiceClient, "rest"), ], ) def test_security_settings_service_client_from_service_account_file( @@ -178,13 +192,18 @@ def test_security_settings_service_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_security_settings_service_client_get_transport_class(): transport = SecuritySettingsServiceClient.get_transport_class() available_transports = [ transports.SecuritySettingsServiceGrpcTransport, + transports.SecuritySettingsServiceRestTransport, ] assert transport in available_transports @@ -205,6 +224,11 @@ def test_security_settings_service_client_get_transport_class(): transports.SecuritySettingsServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -360,6 +384,18 @@ def test_security_settings_service_client_client_options( "grpc_asyncio", "false", ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + "true", + ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -565,6 +601,11 @@ def test_security_settings_service_client_get_mtls_endpoint_and_cert_source( transports.SecuritySettingsServiceGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + ), ], ) def test_security_settings_service_client_client_options_scopes( @@ -605,6 +646,12 @@ def test_security_settings_service_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + SecuritySettingsServiceClient, + transports.SecuritySettingsServiceRestTransport, + "rest", + None, + ), ], ) def test_security_settings_service_client_client_options_credentials_file( @@ -2310,134 +2357,1737 @@ async def test_delete_security_settings_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcdc_security_settings.CreateSecuritySettingsRequest, + dict, + ], +) +def test_create_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["security_settings"] = { + "name": "name_value", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + 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 = gcdc_security_settings.SecuritySettings( + name="name_value", + display_name="display_name_value", + redaction_strategy=gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE, + redaction_scope=gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE, + inspect_template="inspect_template_value", + deidentify_template="deidentify_template_value", + purge_data_types=[ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ], + retention_window_days=2271, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_security_settings.SecuritySettings) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.redaction_strategy + == gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE ) - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + assert ( + response.redaction_scope + == gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE + ) + assert response.inspect_template == "inspect_template_value" + assert response.deidentify_template == "deidentify_template_value" + assert response.purge_data_types == [ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ] + + +def test_create_security_settings_rest_required_fields( + request_type=gcdc_security_settings.CreateSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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 an api_key and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_security_settings._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() + ).create_security_settings._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 = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - client_options=options, - transport=transport, - ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_security_settings.SecuritySettings() + # 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 - # 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 = SecuritySettingsServiceClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "securitySettings", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), ) - with pytest.raises(ValueError): - client = SecuritySettingsServiceClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, + "post_create_security_settings", + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, + "pre_create_security_settings", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_security_settings.CreateSecuritySettingsRequest.pb( + gcdc_security_settings.CreateSecuritySettingsRequest() + ) + 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 = gcdc_security_settings.SecuritySettings.to_json( + gcdc_security_settings.SecuritySettings() ) + request = gcdc_security_settings.CreateSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_security_settings.SecuritySettings() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + client.create_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_security_settings_rest_bad_request( + transport: str = "rest", + request_type=gcdc_security_settings.CreateSecuritySettingsRequest, +): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = SecuritySettingsServiceClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["security_settings"] = { + "name": "name_value", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.SecuritySettingsServiceGrpcTransport( + # 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_security_settings(request) + + +def test_create_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.SecuritySettingsServiceGrpcAsyncIOTransport( + # 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 = gcdc_security_settings.SecuritySettings() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + security_settings=gcdc_security_settings.SecuritySettings( + 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 = gcdc_security_settings.SecuritySettings.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_security_settings(**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/v3beta1/{parent=projects/*/locations/*}/securitySettings" + % client.transport._host, + args[1], + ) + + +def test_create_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( 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_security_settings( + gcdc_security_settings.CreateSecuritySettingsRequest(), + parent="parent_value", + security_settings=gcdc_security_settings.SecuritySettings( + name="name_value" + ), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.SecuritySettingsServiceGrpcTransport, - transports.SecuritySettingsServiceGrpcAsyncIOTransport, - ], -) -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_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + security_settings.GetSecuritySettingsRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = SecuritySettingsServiceClient.get_transport_class(transport_name)( +def test_get_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = SecuritySettingsServiceClient( - credentials=ga_credentials.AnonymousCredentials(), + # 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 = security_settings.SecuritySettings( + name="name_value", + display_name="display_name_value", + redaction_strategy=security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE, + redaction_scope=security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE, + inspect_template="inspect_template_value", + deidentify_template="deidentify_template_value", + purge_data_types=[ + security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ], + retention_window_days=2271, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = security_settings.SecuritySettings.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, security_settings.SecuritySettings) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.redaction_strategy + == security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE ) - assert isinstance( - client.transport, - transports.SecuritySettingsServiceGrpcTransport, + assert ( + response.redaction_scope + == security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE ) + assert response.inspect_template == "inspect_template_value" + assert response.deidentify_template == "deidentify_template_value" + assert response.purge_data_types == [ + security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ] -def test_security_settings_service_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.SecuritySettingsServiceTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +def test_get_security_settings_rest_required_fields( + request_type=security_settings.GetSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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 -def test_security_settings_service_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.security_settings_service.transports.SecuritySettingsServiceTransport.__init__" + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_security_settings._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_security_settings._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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = security_settings.SecuritySettings() + # 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 = security_settings.SecuritySettings.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, "post_get_security_settings" + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, "pre_get_security_settings" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = security_settings.GetSecuritySettingsRequest.pb( + security_settings.GetSecuritySettingsRequest() + ) + 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 = security_settings.SecuritySettings.to_json( + security_settings.SecuritySettings() + ) + + request = security_settings.GetSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = security_settings.SecuritySettings() + + client.get_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_security_settings_rest_bad_request( + transport: str = "rest", request_type=security_settings.GetSecuritySettingsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/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_security_settings(request) + + +def test_get_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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 = security_settings.SecuritySettings() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/securitySettings/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 = security_settings.SecuritySettings.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_security_settings(**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/v3beta1/{name=projects/*/locations/*/securitySettings/*}" + % client.transport._host, + args[1], + ) + + +def test_get_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + security_settings.GetSecuritySettingsRequest(), + name="name_value", + ) + + +def test_get_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_security_settings.UpdateSecuritySettingsRequest, + dict, + ], +) +def test_update_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "security_settings": { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + } + request_init["security_settings"] = { + "name": "projects/sample1/locations/sample2/securitySettings/sample3", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + 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 = gcdc_security_settings.SecuritySettings( + name="name_value", + display_name="display_name_value", + redaction_strategy=gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE, + redaction_scope=gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE, + inspect_template="inspect_template_value", + deidentify_template="deidentify_template_value", + purge_data_types=[ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ], + retention_window_days=2271, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_security_settings.SecuritySettings) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.redaction_strategy + == gcdc_security_settings.SecuritySettings.RedactionStrategy.REDACT_WITH_SERVICE + ) + assert ( + response.redaction_scope + == gcdc_security_settings.SecuritySettings.RedactionScope.REDACT_DISK_STORAGE + ) + assert response.inspect_template == "inspect_template_value" + assert response.deidentify_template == "deidentify_template_value" + assert response.purge_data_types == [ + gcdc_security_settings.SecuritySettings.PurgeDataType.DIALOGFLOW_HISTORY + ] + + +def test_update_security_settings_rest_required_fields( + request_type=gcdc_security_settings.UpdateSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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_security_settings._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_security_settings._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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_security_settings.SecuritySettings() + # 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 = gcdc_security_settings.SecuritySettings.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "securitySettings", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, + "post_update_security_settings", + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, + "pre_update_security_settings", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_security_settings.UpdateSecuritySettingsRequest.pb( + gcdc_security_settings.UpdateSecuritySettingsRequest() + ) + 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 = gcdc_security_settings.SecuritySettings.to_json( + gcdc_security_settings.SecuritySettings() + ) + + request = gcdc_security_settings.UpdateSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_security_settings.SecuritySettings() + + client.update_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_security_settings_rest_bad_request( + transport: str = "rest", + request_type=gcdc_security_settings.UpdateSecuritySettingsRequest, +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "security_settings": { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + } + request_init["security_settings"] = { + "name": "projects/sample1/locations/sample2/securitySettings/sample3", + "display_name": "display_name_value", + "redaction_strategy": 1, + "redaction_scope": 2, + "inspect_template": "inspect_template_value", + "deidentify_template": "deidentify_template_value", + "retention_window_days": 2271, + "purge_data_types": [1], + "audio_export_settings": { + "gcs_bucket": "gcs_bucket_value", + "audio_export_pattern": "audio_export_pattern_value", + "enable_audio_redaction": True, + "audio_format": 1, + }, + "insights_export_settings": {"enable_insights_export": True}, + } + 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_security_settings(request) + + +def test_update_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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 = gcdc_security_settings.SecuritySettings() + + # get arguments that satisfy an http rule for this method + sample_request = { + "security_settings": { + "name": "projects/sample1/locations/sample2/securitySettings/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + security_settings=gcdc_security_settings.SecuritySettings( + 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 = gcdc_security_settings.SecuritySettings.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_security_settings(**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/v3beta1/{security_settings.name=projects/*/locations/*/securitySettings/*}" + % client.transport._host, + args[1], + ) + + +def test_update_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + gcdc_security_settings.UpdateSecuritySettingsRequest(), + security_settings=gcdc_security_settings.SecuritySettings( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + security_settings.ListSecuritySettingsRequest, + dict, + ], +) +def test_list_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/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 = security_settings.ListSecuritySettingsResponse( + 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 = security_settings.ListSecuritySettingsResponse.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_security_settings(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSecuritySettingsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_security_settings_rest_required_fields( + request_type=security_settings.ListSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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_security_settings._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_security_settings._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", + ) + ) + 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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = security_settings.ListSecuritySettingsResponse() + # 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 = security_settings.ListSecuritySettingsResponse.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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, "post_list_security_settings" + ) as post, mock.patch.object( + transports.SecuritySettingsServiceRestInterceptor, "pre_list_security_settings" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = security_settings.ListSecuritySettingsRequest.pb( + security_settings.ListSecuritySettingsRequest() + ) + 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 = ( + security_settings.ListSecuritySettingsResponse.to_json( + security_settings.ListSecuritySettingsResponse() + ) + ) + + request = security_settings.ListSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = security_settings.ListSecuritySettingsResponse() + + client.list_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_security_settings_rest_bad_request( + transport: str = "rest", request_type=security_settings.ListSecuritySettingsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/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_security_settings(request) + + +def test_list_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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 = security_settings.ListSecuritySettingsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/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 = security_settings.ListSecuritySettingsResponse.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_security_settings(**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/v3beta1/{parent=projects/*/locations/*}/securitySettings" + % client.transport._host, + args[1], + ) + + +def test_list_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + security_settings.ListSecuritySettingsRequest(), + parent="parent_value", + ) + + +def test_list_security_settings_rest_pager(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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 = ( + security_settings.ListSecuritySettingsResponse( + security_settings=[ + security_settings.SecuritySettings(), + security_settings.SecuritySettings(), + security_settings.SecuritySettings(), + ], + next_page_token="abc", + ), + security_settings.ListSecuritySettingsResponse( + security_settings=[], + next_page_token="def", + ), + security_settings.ListSecuritySettingsResponse( + security_settings=[ + security_settings.SecuritySettings(), + ], + next_page_token="ghi", + ), + security_settings.ListSecuritySettingsResponse( + security_settings=[ + security_settings.SecuritySettings(), + security_settings.SecuritySettings(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + security_settings.ListSecuritySettingsResponse.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": "projects/sample1/locations/sample2"} + + pager = client.list_security_settings(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, security_settings.SecuritySettings) for i in results) + + pages = list(client.list_security_settings(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", + [ + security_settings.DeleteSecuritySettingsRequest, + dict, + ], +) +def test_delete_security_settings_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/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_security_settings(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_security_settings_rest_required_fields( + request_type=security_settings.DeleteSecuritySettingsRequest, +): + transport_class = transports.SecuritySettingsServiceRestTransport + + 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_security_settings._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_security_settings._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 = SecuritySettingsServiceClient( + 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_security_settings(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_security_settings_rest_unset_required_fields(): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_security_settings._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_security_settings_rest_interceptors(null_interceptor): + transport = transports.SecuritySettingsServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SecuritySettingsServiceRestInterceptor(), + ) + client = SecuritySettingsServiceClient(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.SecuritySettingsServiceRestInterceptor, + "pre_delete_security_settings", + ) as pre: + pre.assert_not_called() + pb_message = security_settings.DeleteSecuritySettingsRequest.pb( + security_settings.DeleteSecuritySettingsRequest() + ) + 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 = security_settings.DeleteSecuritySettingsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_security_settings( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_security_settings_rest_bad_request( + transport: str = "rest", + request_type=security_settings.DeleteSecuritySettingsRequest, +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/securitySettings/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_security_settings(request) + + +def test_delete_security_settings_rest_flattened(): + client = SecuritySettingsServiceClient( + 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": "projects/sample1/locations/sample2/securitySettings/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_security_settings(**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/v3beta1/{name=projects/*/locations/*/securitySettings/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_security_settings_rest_flattened_error(transport: str = "rest"): + client = SecuritySettingsServiceClient( + 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_security_settings( + security_settings.DeleteSecuritySettingsRequest(), + name="name_value", + ) + + +def test_delete_security_settings_rest_error(): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + 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 = SecuritySettingsServiceClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SecuritySettingsServiceClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SecuritySettingsServiceClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SecuritySettingsServiceGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SecuritySettingsServiceGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SecuritySettingsServiceGrpcTransport, + transports.SecuritySettingsServiceGrpcAsyncIOTransport, + transports.SecuritySettingsServiceRestTransport, + ], +) +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 = SecuritySettingsServiceClient.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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SecuritySettingsServiceGrpcTransport, + ) + + +def test_security_settings_service_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SecuritySettingsServiceTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_security_settings_service_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.security_settings_service.transports.SecuritySettingsServiceTransport.__init__" ) as Transport: Transport.return_value = None transport = transports.SecuritySettingsServiceTransport( @@ -2552,6 +4202,7 @@ def test_security_settings_service_transport_auth_adc(transport_class): [ transports.SecuritySettingsServiceGrpcTransport, transports.SecuritySettingsServiceGrpcAsyncIOTransport, + transports.SecuritySettingsServiceRestTransport, ], ) def test_security_settings_service_transport_auth_gdch_credentials(transport_class): @@ -2656,11 +4307,23 @@ def test_security_settings_service_grpc_transport_client_cert_source_for_mtls( ) +def test_security_settings_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.SecuritySettingsServiceRestTransport( + 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_security_settings_service_host_no_port(transport_name): @@ -2671,7 +4334,11 @@ def test_security_settings_service_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2679,6 +4346,7 @@ def test_security_settings_service_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_security_settings_service_host_with_port(transport_name): @@ -2689,7 +4357,45 @@ def test_security_settings_service_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_security_settings_service_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SecuritySettingsServiceClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SecuritySettingsServiceClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_security_settings._session + session2 = client2.transport.create_security_settings._session + assert session1 != session2 + session1 = client1.transport.get_security_settings._session + session2 = client2.transport.get_security_settings._session + assert session1 != session2 + session1 = client1.transport.update_security_settings._session + session2 = client2.transport.update_security_settings._session + assert session1 != session2 + session1 = client1.transport.list_security_settings._session + session2 = client2.transport.list_security_settings._session + assert session1 != session2 + session1 = client1.transport.delete_security_settings._session + session2 = client2.transport.delete_security_settings._session + assert session1 != session2 def test_security_settings_service_grpc_transport_channel(): @@ -3042,6 +4748,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SecuritySettingsServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SecuritySettingsServiceClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3763,6 +5755,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3780,6 +5773,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py index a8cc1b7d..d491ee03 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.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 @@ -107,6 +114,7 @@ def test__get_default_mtls_endpoint(): [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_info( @@ -122,7 +130,11 @@ def test_session_entity_types_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -130,6 +142,7 @@ def test_session_entity_types_client_from_service_account_info( [ (transports.SessionEntityTypesGrpcTransport, "grpc"), (transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_service_account_always_use_jwt( @@ -155,6 +168,7 @@ def test_session_entity_types_client_service_account_always_use_jwt( [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_file( @@ -177,13 +191,18 @@ def test_session_entity_types_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_session_entity_types_client_get_transport_class(): transport = SessionEntityTypesClient.get_transport_class() available_transports = [ transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesRestTransport, ] assert transport in available_transports @@ -200,6 +219,7 @@ def test_session_entity_types_client_get_transport_class(): transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -355,6 +375,18 @@ def test_session_entity_types_client_client_options( "grpc_asyncio", "false", ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "true", + ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -554,6 +586,7 @@ def test_session_entity_types_client_get_mtls_endpoint_and_cert_source(client_cl transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_client_options_scopes( @@ -594,6 +627,12 @@ def test_session_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + None, + ), ], ) def test_session_entity_types_client_client_options_credentials_file( @@ -2198,222 +2237,1741 @@ async def test_delete_session_entity_type_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.ListSessionEntityTypesRequest, + dict, + ], +) +def test_list_session_entity_types_rest(request_type): + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - 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 = session_entity_type.ListSessionEntityTypesResponse( + next_page_token="next_page_token_value", ) - # 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 = SessionEntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_session_entity_types(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSessionEntityTypesPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_required_fields( + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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, + ) ) - client = SessionEntityTypesClient(transport=transport) - assert client.transport is transport + # verify fields with default values are dropped -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_session_entity_types._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_session_entity_types._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", + ) ) - channel = transport.grpc_channel - assert channel + jsonified_request.update(unset_fields) - transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse() + # 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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.SessionEntityTypesGrpcTransport, - transports.SessionEntityTypesGrpcAsyncIOTransport, - ], -) -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() + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.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 -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = SessionEntityTypesClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name + response = client.list_session_entity_types(request) + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.SessionEntityTypesGrpcTransport, + + unset_fields = transport.list_session_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_session_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_session_entity_types_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_list_session_entity_types" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_list_session_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.ListSessionEntityTypesRequest.pb( + session_entity_type.ListSessionEntityTypesRequest() + ) + 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 = ( + session_entity_type.ListSessionEntityTypesResponse.to_json( + session_entity_type.ListSessionEntityTypesResponse() + ) ) + request = session_entity_type.ListSessionEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.ListSessionEntityTypesResponse() -def test_session_entity_types_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_session_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_session_entity_types", - "get_session_entity_type", - "create_session_entity_type", - "update_session_entity_type", - "delete_session_entity_type", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + pre.assert_called_once() + post.assert_called_once() + + +def test_list_session_entity_types_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + client = SessionEntityTypesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request = request_type(**request_init) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # 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_session_entity_types(request) -def test_session_entity_types_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.dialogflowcx_v3beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport( - credentials_file="credentials.json", - quota_project_id="octopus", +def test_list_session_entity_types_rest_flattened(): + client = SessionEntityTypesClient( + 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 = session_entity_type.ListSessionEntityTypesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.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_session_entity_types(**mock_args) -def test_session_entity_types_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.dialogflowcx_v3beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport() - adc.assert_called_once() + # 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/v3beta1/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) -def test_session_entity_types_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) - SessionEntityTypesClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, +def test_list_session_entity_types_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_types( + session_entity_type.ListSessionEntityTypesRequest(), + parent="parent_value", ) -@pytest.mark.parametrize( - "transport_class", +def test_list_session_entity_types_rest_pager(transport: str = "rest"): + client = SessionEntityTypesClient( + 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 = ( + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + next_page_token="abc", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[], + next_page_token="def", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + ], + next_page_token="ghi", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + session_entity_type.ListSessionEntityTypesResponse.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": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + + pager = client.list_session_entity_types(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, session_entity_type.SessionEntityType) for i in results + ) + + pages = list(client.list_session_entity_types(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", + [ + session_entity_type.GetSessionEntityTypeRequest, + dict, + ], +) +def test_get_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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 = session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.SessionEntityType.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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_get_session_entity_type_rest_required_fields( + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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_session_entity_type._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_session_entity_type._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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType() + # 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 = session_entity_type.SessionEntityType.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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_get_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_get_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.GetSessionEntityTypeRequest.pb( + session_entity_type.GetSessionEntityTypeRequest() + ) + 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 = session_entity_type.SessionEntityType.to_json( + session_entity_type.SessionEntityType() + ) + + request = session_entity_type.GetSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.SessionEntityType() + + client.get_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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_session_entity_type(request) + + +def test_get_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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 = session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + + # 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 = session_entity_type.SessionEntityType.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_session_entity_type(**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/v3beta1/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_get_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + session_entity_type.GetSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_get_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_session_entity_type.CreateSessionEntityTypeRequest, + dict, + ], +) +def test_create_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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 = gcdc_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_create_session_entity_type_rest_required_fields( + request_type=gcdc_session_entity_type.CreateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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() + ).create_session_entity_type._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() + ).create_session_entity_type._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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_session_entity_type.SessionEntityType() + # 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "sessionEntityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_create_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_create_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_session_entity_type.CreateSessionEntityTypeRequest.pb( + gcdc_session_entity_type.CreateSessionEntityTypeRequest() + ) + 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 = gcdc_session_entity_type.SessionEntityType.to_json( + gcdc_session_entity_type.SessionEntityType() + ) + + request = gcdc_session_entity_type.CreateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_session_entity_type.SessionEntityType() + + client.create_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcdc_session_entity_type.CreateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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_session_entity_type(request) + + +def test_create_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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 = gcdc_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + session_entity_type=gcdc_session_entity_type.SessionEntityType( + 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(**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/v3beta1/{parent=projects/*/locations/*/agents/*/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) + + +def test_create_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + gcdc_session_entity_type.CreateSessionEntityTypeRequest(), + parent="parent_value", + session_entity_type=gcdc_session_entity_type.SessionEntityType( + name="name_value" + ), + ) + + +def test_create_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_session_entity_type.UpdateSessionEntityTypeRequest, + dict, + ], +) +def test_update_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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 = gcdc_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcdc_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_update_session_entity_type_rest_required_fields( + request_type=gcdc_session_entity_type.UpdateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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_session_entity_type._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_session_entity_type._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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_session_entity_type.SessionEntityType() + # 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("sessionEntityType",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "post_update_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_update_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_session_entity_type.UpdateSessionEntityTypeRequest.pb( + gcdc_session_entity_type.UpdateSessionEntityTypeRequest() + ) + 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 = gcdc_session_entity_type.SessionEntityType.to_json( + gcdc_session_entity_type.SessionEntityType() + ) + + request = gcdc_session_entity_type.UpdateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_session_entity_type.SessionEntityType() + + client.update_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcdc_session_entity_type.UpdateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + 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_session_entity_type(request) + + +def test_update_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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 = gcdc_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "session_entity_type": { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + session_entity_type=gcdc_session_entity_type.SessionEntityType( + 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 = gcdc_session_entity_type.SessionEntityType.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_session_entity_type(**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/v3beta1/{session_entity_type.name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + gcdc_session_entity_type.UpdateSessionEntityTypeRequest(), + session_entity_type=gcdc_session_entity_type.SessionEntityType( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.DeleteSessionEntityTypeRequest, + dict, + ], +) +def test_delete_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_session_entity_type_rest_required_fields( + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + 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_session_entity_type._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_session_entity_type._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 = SessionEntityTypesClient( + 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_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(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.SessionEntityTypesRestInterceptor, "pre_delete_session_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = session_entity_type.DeleteSessionEntityTypeRequest.pb( + session_entity_type.DeleteSessionEntityTypeRequest() + ) + 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 = session_entity_type.DeleteSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + 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_session_entity_type(request) + + +def test_delete_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + 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": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4/entityTypes/sample5" + } + + # 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_session_entity_type(**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/v3beta1/{name=projects/*/locations/*/agents/*/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + 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_session_entity_type( + session_entity_type.DeleteSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + 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 = SessionEntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SessionEntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, + ], +) +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 = SessionEntityTypesClient.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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SessionEntityTypesGrpcTransport, + ) + + +def test_session_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_session_entity_types_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_session_entity_types", + "get_session_entity_type", + "create_session_entity_type", + "update_session_entity_type", + "delete_session_entity_type", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_session_entity_types_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.dialogflowcx_v3beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_session_entity_types_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.dialogflowcx_v3beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport() + adc.assert_called_once() + + +def test_session_entity_types_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) + SessionEntityTypesClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", [ transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, @@ -2440,6 +3998,7 @@ def test_session_entity_types_transport_auth_adc(transport_class): [ transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, ], ) def test_session_entity_types_transport_auth_gdch_credentials(transport_class): @@ -2542,11 +4101,23 @@ def test_session_entity_types_grpc_transport_client_cert_source_for_mtls( ) +def test_session_entity_types_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.SessionEntityTypesRestTransport( + 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_session_entity_types_host_no_port(transport_name): @@ -2557,7 +4128,11 @@ def test_session_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2565,6 +4140,7 @@ def test_session_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_session_entity_types_host_with_port(transport_name): @@ -2575,7 +4151,45 @@ def test_session_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_session_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionEntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionEntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_session_entity_types._session + session2 = client2.transport.list_session_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_session_entity_type._session + session2 = client2.transport.get_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_session_entity_type._session + session2 = client2.transport.create_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_session_entity_type._session + session2 = client2.transport.update_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_session_entity_type._session + session2 = client2.transport.delete_session_entity_type._session + assert session1 != session2 def test_session_entity_types_grpc_transport_channel(): @@ -2878,6 +4492,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3597,6 +5497,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3614,6 +5515,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py index a3a392aa..bf2f8855 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.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 @@ -98,6 +105,7 @@ def test__get_default_mtls_endpoint(): [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_info(client_class, transport_name): @@ -111,7 +119,11 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -119,6 +131,7 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) [ (transports.SessionsGrpcTransport, "grpc"), (transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_service_account_always_use_jwt( @@ -144,6 +157,7 @@ def test_sessions_client_service_account_always_use_jwt( [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_file(client_class, transport_name): @@ -164,13 +178,18 @@ def test_sessions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_sessions_client_get_transport_class(): transport = SessionsClient.get_transport_class() available_transports = [ transports.SessionsGrpcTransport, + transports.SessionsRestTransport, ] assert transport in available_transports @@ -183,6 +202,7 @@ def test_sessions_client_get_transport_class(): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -324,6 +344,8 @@ def test_sessions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (SessionsClient, transports.SessionsRestTransport, "rest", "true"), + (SessionsClient, transports.SessionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -513,6 +535,7 @@ def test_sessions_client_get_mtls_endpoint_and_cert_source(client_class): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_client_options_scopes( @@ -548,6 +571,7 @@ def test_sessions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (SessionsClient, transports.SessionsRestTransport, "rest", None), ], ) def test_sessions_client_client_options_credentials_file( @@ -1194,6 +1218,605 @@ async def test_fulfill_intent_field_headers_async(): ) in kw["metadata"] +@pytest.mark.parametrize( + "request_type", + [ + session.DetectIntentRequest, + dict, + ], +) +def test_detect_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/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 = session.DetectIntentResponse( + response_id="response_id_value", + output_audio=b"output_audio_blob", + response_type=session.DetectIntentResponse.ResponseType.PARTIAL, + allow_cancellation=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session.DetectIntentResponse.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.detect_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session.DetectIntentResponse) + assert response.response_id == "response_id_value" + assert response.output_audio == b"output_audio_blob" + assert response.response_type == session.DetectIntentResponse.ResponseType.PARTIAL + assert response.allow_cancellation is True + + +def test_detect_intent_rest_required_fields(request_type=session.DetectIntentRequest): + transport_class = transports.SessionsRestTransport + + request_init = {} + request_init["session"] = "" + 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() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["session"] = "session_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "session" in jsonified_request + assert jsonified_request["session"] == "session_value" + + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session.DetectIntentResponse() + # 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 = session.DetectIntentResponse.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.detect_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_detect_intent_rest_unset_required_fields(): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.detect_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "session", + "queryInput", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_detect_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(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.SessionsRestInterceptor, "post_detect_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_detect_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session.DetectIntentRequest.pb(session.DetectIntentRequest()) + 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 = session.DetectIntentResponse.to_json( + session.DetectIntentResponse() + ) + + request = session.DetectIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session.DetectIntentResponse() + + client.detect_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_detect_intent_rest_bad_request( + transport: str = "rest", request_type=session.DetectIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + 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.detect_intent(request) + + +def test_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_detect_intent_rest_no_http_options(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = session.StreamingDetectIntentRequest() + requests = [request] + with pytest.raises(RuntimeError): + client.streaming_detect_intent(requests) + + +@pytest.mark.parametrize( + "request_type", + [ + session.MatchIntentRequest, + dict, + ], +) +def test_match_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/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 = session.MatchIntentResponse( + text="text_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session.MatchIntentResponse.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.match_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session.MatchIntentResponse) + + +def test_match_intent_rest_required_fields(request_type=session.MatchIntentRequest): + transport_class = transports.SessionsRestTransport + + request_init = {} + request_init["session"] = "" + 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() + ).match_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["session"] = "session_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).match_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "session" in jsonified_request + assert jsonified_request["session"] == "session_value" + + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session.MatchIntentResponse() + # 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 = session.MatchIntentResponse.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.match_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_match_intent_rest_unset_required_fields(): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.match_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "session", + "queryInput", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_match_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(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.SessionsRestInterceptor, "post_match_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_match_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session.MatchIntentRequest.pb(session.MatchIntentRequest()) + 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 = session.MatchIntentResponse.to_json( + session.MatchIntentResponse() + ) + + request = session.MatchIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session.MatchIntentResponse() + + client.match_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_match_intent_rest_bad_request( + transport: str = "rest", request_type=session.MatchIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + 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.match_intent(request) + + +def test_match_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + session.FulfillIntentRequest, + dict, + ], +) +def test_fulfill_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "match_intent_request": { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/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 = session.FulfillIntentResponse( + response_id="response_id_value", + output_audio=b"output_audio_blob", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session.FulfillIntentResponse.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.fulfill_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session.FulfillIntentResponse) + assert response.response_id == "response_id_value" + assert response.output_audio == b"output_audio_blob" + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_fulfill_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(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.SessionsRestInterceptor, "post_fulfill_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_fulfill_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session.FulfillIntentRequest.pb(session.FulfillIntentRequest()) + 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 = session.FulfillIntentResponse.to_json( + session.FulfillIntentResponse() + ) + + request = session.FulfillIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session.FulfillIntentResponse() + + client.fulfill_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_fulfill_intent_rest_bad_request( + transport: str = "rest", request_type=session.FulfillIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "match_intent_request": { + "session": "projects/sample1/locations/sample2/agents/sample3/sessions/sample4" + } + } + 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.fulfill_intent(request) + + +def test_fulfill_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # Since a `google.api.http` annotation is required for using a rest transport + # method, this should error. + with pytest.raises(NotImplementedError) as not_implemented_error: + client.streaming_detect_intent({}) + assert "Method StreamingDetectIntent is not available over REST transport" in str( + not_implemented_error.value + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.SessionsGrpcTransport( @@ -1275,6 +1898,7 @@ def test_transport_get_channel(): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1289,6 +1913,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1435,6 +2060,7 @@ def test_sessions_transport_auth_adc(transport_class): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_sessions_transport_auth_gdch_credentials(transport_class): @@ -1532,11 +2158,23 @@ def test_sessions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_sessions_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.SessionsRestTransport( + 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_sessions_host_no_port(transport_name): @@ -1547,7 +2185,11 @@ def test_sessions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1555,6 +2197,7 @@ def test_sessions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_sessions_host_with_port(transport_name): @@ -1565,7 +2208,42 @@ def test_sessions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_sessions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.detect_intent._session + session2 = client2.transport.detect_intent._session + assert session1 != session2 + session1 = client1.transport.streaming_detect_intent._session + session2 = client2.transport.streaming_detect_intent._session + assert session1 != session2 + session1 = client1.transport.match_intent._session + session2 = client2.transport.match_intent._session + assert session1 != session2 + session1 = client1.transport.fulfill_intent._session + session2 = client2.transport.fulfill_intent._session + assert session1 != session2 def test_sessions_grpc_transport_channel(): @@ -2105,6 +2783,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2822,6 +3786,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2839,6 +3804,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.py index 7c198b6a..016088fe 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.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 @@ -108,6 +115,7 @@ def test__get_default_mtls_endpoint(): [ (TestCasesClient, "grpc"), (TestCasesAsyncClient, "grpc_asyncio"), + (TestCasesClient, "rest"), ], ) def test_test_cases_client_from_service_account_info(client_class, transport_name): @@ -121,7 +129,11 @@ def test_test_cases_client_from_service_account_info(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -129,6 +141,7 @@ def test_test_cases_client_from_service_account_info(client_class, transport_nam [ (transports.TestCasesGrpcTransport, "grpc"), (transports.TestCasesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.TestCasesRestTransport, "rest"), ], ) def test_test_cases_client_service_account_always_use_jwt( @@ -154,6 +167,7 @@ def test_test_cases_client_service_account_always_use_jwt( [ (TestCasesClient, "grpc"), (TestCasesAsyncClient, "grpc_asyncio"), + (TestCasesClient, "rest"), ], ) def test_test_cases_client_from_service_account_file(client_class, transport_name): @@ -174,13 +188,18 @@ def test_test_cases_client_from_service_account_file(client_class, transport_nam assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_test_cases_client_get_transport_class(): transport = TestCasesClient.get_transport_class() available_transports = [ transports.TestCasesGrpcTransport, + transports.TestCasesRestTransport, ] assert transport in available_transports @@ -197,6 +216,7 @@ def test_test_cases_client_get_transport_class(): transports.TestCasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (TestCasesClient, transports.TestCasesRestTransport, "rest"), ], ) @mock.patch.object( @@ -340,6 +360,8 @@ def test_test_cases_client_client_options( "grpc_asyncio", "false", ), + (TestCasesClient, transports.TestCasesRestTransport, "rest", "true"), + (TestCasesClient, transports.TestCasesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -533,6 +555,7 @@ def test_test_cases_client_get_mtls_endpoint_and_cert_source(client_class): transports.TestCasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (TestCasesClient, transports.TestCasesRestTransport, "rest"), ], ) def test_test_cases_client_client_options_scopes( @@ -568,6 +591,7 @@ def test_test_cases_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (TestCasesClient, transports.TestCasesRestTransport, "rest", None), ], ) def test_test_cases_client_client_options_credentials_file( @@ -3543,149 +3567,4113 @@ async def test_get_test_case_result_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.TestCasesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + test_case.ListTestCasesRequest, + dict, + ], +) +def test_list_test_cases_rest(request_type): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = TestCasesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = test_case.ListTestCasesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.TestCasesGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.ListTestCasesResponse.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_test_cases(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCasesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_cases_rest_required_fields( + request_type=test_case.ListTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_cases._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_test_cases._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", + "view", + ) + ) + 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 = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.ListTestCasesResponse() + # 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 = test_case.ListTestCasesResponse.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_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = TestCasesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + "view", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.TestCasesGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = TestCasesClient( - client_options=options, - transport=transport, + client = TestCasesClient(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.TestCasesRestInterceptor, "post_list_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_list_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ListTestCasesRequest.pb(test_case.ListTestCasesRequest()) + 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 = test_case.ListTestCasesResponse.to_json( + test_case.ListTestCasesResponse() ) - # 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 = TestCasesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = test_case.ListTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.ListTestCasesResponse() + + client.list_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.TestCasesGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.ListTestCasesRequest +): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = TestCasesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.TestCasesGrpcTransport( + # 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_test_cases(request) + + +def test_list_test_cases_rest_flattened(): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = TestCasesClient(transport=transport) - assert client.transport is 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 = test_case.ListTestCasesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.TestCasesGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = test_case.ListTestCasesResponse.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_test_cases(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases" + % client.transport._host, + args[1], + ) + + +def test_list_test_cases_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.TestCasesGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_test_cases( + test_case.ListTestCasesRequest(), + parent="parent_value", + ) + + +def test_list_test_cases_rest_pager(transport: str = "rest"): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse( + test_cases=[], + next_page_token="def", + ), + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + ], + next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(test_case.ListTestCasesResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.TestCasesGrpcTransport, - transports.TestCasesGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_test_cases(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCase) for i in results) + + pages = list(client.list_test_cases(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + test_case.BatchDeleteTestCasesRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = TestCasesClient.get_transport_class(transport_name)( +def test_batch_delete_test_cases_rest(request_type): + client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.batch_delete_test_cases(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_batch_delete_test_cases_rest_required_fields( + request_type=test_case.BatchDeleteTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + request_init = {} + request_init["parent"] = "" + 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 + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_test_cases._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["names"] = "names_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_test_cases._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 "names" in jsonified_request + assert jsonified_request["names"] == "names_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = TestCasesClient( 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": "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 = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.TestCasesGrpcTransport, + + unset_fields = transport.batch_delete_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "names", + ) + ) ) -def test_test_cases_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.TestCasesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "pre_batch_delete_test_cases" + ) as pre: + pre.assert_not_called() + pb_message = test_case.BatchDeleteTestCasesRequest.pb( + test_case.BatchDeleteTestCasesRequest() + ) + 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 = test_case.BatchDeleteTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.batch_delete_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) + pre.assert_called_once() -def test_test_cases_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.test_cases.transports.TestCasesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.TestCasesTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_test_cases", - "batch_delete_test_cases", - "get_test_case", - "create_test_case", - "update_test_case", - "run_test_case", +def test_batch_delete_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.BatchDeleteTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.batch_delete_test_cases(request) + + +def test_batch_delete_test_cases_rest_flattened(): + client = TestCasesClient( + 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 = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_test_cases(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_test_cases_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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.batch_delete_test_cases( + test_case.BatchDeleteTestCasesRequest(), + parent="parent_value", + ) + + +def test_batch_delete_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.GetTestCaseRequest, + dict, + ], +) +def test_get_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/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 = test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.TestCase.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_test_case(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.TestCase) + assert response.name == "name_value" + assert response.tags == ["tags_value"] + assert response.display_name == "display_name_value" + assert response.notes == "notes_value" + + +def test_get_test_case_rest_required_fields(request_type=test_case.GetTestCaseRequest): + transport_class = transports.TestCasesRestTransport + + 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_test_case._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_test_case._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.TestCase() + # 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 = test_case.TestCase.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_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_test_case._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_get_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_get_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.GetTestCaseRequest.pb(test_case.GetTestCaseRequest()) + 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 = test_case.TestCase.to_json(test_case.TestCase()) + + request = test_case.GetTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.TestCase() + + client.get_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_test_case_rest_bad_request( + transport: str = "rest", request_type=test_case.GetTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + 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_test_case(request) + + +def test_get_test_case_rest_flattened(): + client = TestCasesClient( + 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 = test_case.TestCase() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + + # 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 = test_case.TestCase.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_test_case(**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/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*}" + % client.transport._host, + args[1], + ) + + +def test_get_test_case_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case( + test_case.GetTestCaseRequest(), + name="name_value", + ) + + +def test_get_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_test_case.CreateTestCaseRequest, + dict, + ], +) +def test_create_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["test_case"] = { + "name": "name_value", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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 = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_test_case.TestCase.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_test_case(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + assert response.name == "name_value" + assert response.tags == ["tags_value"] + assert response.display_name == "display_name_value" + assert response.notes == "notes_value" + + +def test_create_test_case_rest_required_fields( + request_type=gcdc_test_case.CreateTestCaseRequest, +): + transport_class = transports.TestCasesRestTransport + + 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() + ).create_test_case._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() + ).create_test_case._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_test_case.TestCase() + # 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 = gcdc_test_case.TestCase.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_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_test_case._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "testCase", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_create_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_create_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_test_case.CreateTestCaseRequest.pb( + gcdc_test_case.CreateTestCaseRequest() + ) + 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 = gcdc_test_case.TestCase.to_json( + gcdc_test_case.TestCase() + ) + + request = gcdc_test_case.CreateTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_test_case.TestCase() + + client.create_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_test_case_rest_bad_request( + transport: str = "rest", request_type=gcdc_test_case.CreateTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["test_case"] = { + "name": "name_value", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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_test_case(request) + + +def test_create_test_case_rest_flattened(): + client = TestCasesClient( + 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 = gcdc_test_case.TestCase() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + test_case=gcdc_test_case.TestCase(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 = gcdc_test_case.TestCase.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_test_case(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/testCases" + % client.transport._host, + args[1], + ) + + +def test_create_test_case_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case( + gcdc_test_case.CreateTestCaseRequest(), + parent="parent_value", + test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + +def test_create_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_test_case.UpdateTestCaseRequest, + dict, + ], +) +def test_update_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "test_case": { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + } + request_init["test_case"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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 = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_test_case.TestCase.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_test_case(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + assert response.name == "name_value" + assert response.tags == ["tags_value"] + assert response.display_name == "display_name_value" + assert response.notes == "notes_value" + + +def test_update_test_case_rest_required_fields( + request_type=gcdc_test_case.UpdateTestCaseRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_case._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_test_case._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_test_case.TestCase() + # 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 = gcdc_test_case.TestCase.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_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_test_case._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "testCase", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_update_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_update_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_test_case.UpdateTestCaseRequest.pb( + gcdc_test_case.UpdateTestCaseRequest() + ) + 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 = gcdc_test_case.TestCase.to_json( + gcdc_test_case.TestCase() + ) + + request = gcdc_test_case.UpdateTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_test_case.TestCase() + + client.update_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_test_case_rest_bad_request( + transport: str = "rest", request_type=gcdc_test_case.UpdateTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "test_case": { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + } + request_init["test_case"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4", + "tags": ["tags_value1", "tags_value2"], + "display_name": "display_name_value", + "notes": "notes_value", + "test_config": { + "tracking_parameters": [ + "tracking_parameters_value1", + "tracking_parameters_value2", + ], + "flow": "flow_value", + "page": "page_value", + }, + "test_case_conversation_turns": [ + { + "user_input": { + "input": { + "text": {"text": "text_value"}, + "intent": {"intent": "intent_value"}, + "audio": { + "config": { + "audio_encoding": 1, + "sample_rate_hertz": 1817, + "enable_word_info": True, + "phrase_hints": [ + "phrase_hints_value1", + "phrase_hints_value2", + ], + "model": "model_value", + "model_variant": 1, + "single_utterance": True, + }, + "audio": b"audio_blob", + }, + "event": {"event": "event_value"}, + "dtmf": { + "digits": "digits_value", + "finish_digit": "finish_digit_value", + }, + "language_code": "language_code_value", + }, + "injected_parameters": {"fields": {}}, + "is_webhook_enabled": True, + "enable_sentiment_analysis": True, + }, + "virtual_agent_output": { + "session_parameters": {}, + "differences": [{"type_": 1, "description": "description_value"}], + "diagnostic_info": {}, + "triggered_intent": { + "name": "name_value", + "display_name": "display_name_value", + "training_phrases": [ + { + "id": "id_value", + "parts": [ + { + "text": "text_value", + "parameter_id": "parameter_id_value", + } + ], + "repeat_count": 1289, + } + ], + "parameters": [ + { + "id": "id_value", + "entity_type": "entity_type_value", + "is_list": True, + "redact": True, + } + ], + "priority": 898, + "is_fallback": True, + "labels": {}, + "description": "description_value", + }, + "current_page": { + "name": "name_value", + "display_name": "display_name_value", + "entry_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "form": { + "parameters": [ + { + "display_name": "display_name_value", + "required": True, + "entity_type": "entity_type_value", + "is_list": True, + "fill_behavior": { + "initial_prompt_fulfillment": {}, + "reprompt_event_handlers": [ + { + "name": "name_value", + "event": "event_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + }, + "default_value": {}, + "redact": True, + } + ] + }, + "transition_route_groups": [ + "transition_route_groups_value1", + "transition_route_groups_value2", + ], + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": {}, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + "event_handlers": {}, + }, + "text_responses": {}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + } + ], + "creation_time": {"seconds": 751, "nanos": 543}, + "last_test_result": { + "name": "name_value", + "environment": "environment_value", + "conversation_turns": {}, + "test_result": 1, + "test_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_test_case(request) + + +def test_update_test_case_rest_flattened(): + client = TestCasesClient( + 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 = gcdc_test_case.TestCase() + + # get arguments that satisfy an http rule for this method + sample_request = { + "test_case": { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + test_case=gcdc_test_case.TestCase(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 = gcdc_test_case.TestCase.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_test_case(**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/v3beta1/{test_case.name=projects/*/locations/*/agents/*/testCases/*}" + % client.transport._host, + args[1], + ) + + +def test_update_test_case_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case( + gcdc_test_case.UpdateTestCaseRequest(), + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.RunTestCaseRequest, + dict, + ], +) +def test_run_test_case_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/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(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.run_test_case(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_run_test_case_rest_required_fields(request_type=test_case.RunTestCaseRequest): + transport_class = transports.TestCasesRestTransport + + 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() + ).run_test_case._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() + ).run_test_case._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 = TestCasesClient( + 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.run_test_case(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_run_test_case_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.run_test_case._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_run_test_case_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_run_test_case" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_run_test_case" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.RunTestCaseRequest.pb(test_case.RunTestCaseRequest()) + 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 = test_case.RunTestCaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.run_test_case( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_run_test_case_rest_bad_request( + transport: str = "rest", request_type=test_case.RunTestCaseRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + 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.run_test_case(request) + + +def test_run_test_case_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.BatchRunTestCasesRequest, + dict, + ], +) +def test_batch_run_test_cases_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.batch_run_test_cases(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_run_test_cases_rest_required_fields( + request_type=test_case.BatchRunTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["test_cases"] = "" + 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_run_test_cases._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["testCases"] = "test_cases_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_run_test_cases._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 "testCases" in jsonified_request + assert jsonified_request["testCases"] == "test_cases_value" + + client = TestCasesClient( + 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.batch_run_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_run_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_run_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "testCases", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_run_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_batch_run_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_batch_run_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.BatchRunTestCasesRequest.pb( + test_case.BatchRunTestCasesRequest() + ) + 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 = test_case.BatchRunTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_run_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_run_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.BatchRunTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.batch_run_test_cases(request) + + +def test_batch_run_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.CalculateCoverageRequest, + dict, + ], +) +def test_calculate_coverage_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"agent": "projects/sample1/locations/sample2/agents/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 = test_case.CalculateCoverageResponse( + agent="agent_value", + intent_coverage=test_case.IntentCoverage( + intents=[test_case.IntentCoverage.Intent(intent="intent_value")] + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.CalculateCoverageResponse.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.calculate_coverage(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.CalculateCoverageResponse) + assert response.agent == "agent_value" + + +def test_calculate_coverage_rest_required_fields( + request_type=test_case.CalculateCoverageRequest, +): + transport_class = transports.TestCasesRestTransport + + request_init = {} + request_init["agent"] = "" + 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() + ).calculate_coverage._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["agent"] = "agent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).calculate_coverage._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("type_",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "agent" in jsonified_request + assert jsonified_request["agent"] == "agent_value" + + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.CalculateCoverageResponse() + # 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 = test_case.CalculateCoverageResponse.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.calculate_coverage(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_calculate_coverage_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.calculate_coverage._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("type",)) + & set( + ( + "agent", + "type", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_calculate_coverage_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_calculate_coverage" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_calculate_coverage" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.CalculateCoverageRequest.pb( + test_case.CalculateCoverageRequest() + ) + 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 = test_case.CalculateCoverageResponse.to_json( + test_case.CalculateCoverageResponse() + ) + + request = test_case.CalculateCoverageRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.CalculateCoverageResponse() + + client.calculate_coverage( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_calculate_coverage_rest_bad_request( + transport: str = "rest", request_type=test_case.CalculateCoverageRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"agent": "projects/sample1/locations/sample2/agents/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.calculate_coverage(request) + + +def test_calculate_coverage_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.ImportTestCasesRequest, + dict, + ], +) +def test_import_test_cases_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.import_test_cases(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_test_cases_rest_required_fields( + request_type=test_case.ImportTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + 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() + ).import_test_cases._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() + ).import_test_cases._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 = TestCasesClient( + 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.import_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_import_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_import_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ImportTestCasesRequest.pb( + test_case.ImportTestCasesRequest() + ) + 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 = test_case.ImportTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.ImportTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.import_test_cases(request) + + +def test_import_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.ExportTestCasesRequest, + dict, + ], +) +def test_export_test_cases_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = 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.export_test_cases(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_test_cases_rest_required_fields( + request_type=test_case.ExportTestCasesRequest, +): + transport_class = transports.TestCasesRestTransport + + 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() + ).export_test_cases._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_test_cases._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 = TestCasesClient( + 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.export_test_cases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_test_cases_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_test_cases._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_test_cases_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_export_test_cases" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_export_test_cases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ExportTestCasesRequest.pb( + test_case.ExportTestCasesRequest() + ) + 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 = test_case.ExportTestCasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_test_cases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_test_cases_rest_bad_request( + transport: str = "rest", request_type=test_case.ExportTestCasesRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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.export_test_cases(request) + + +def test_export_test_cases_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + test_case.ListTestCaseResultsRequest, + dict, + ], +) +def test_list_test_case_results_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/testCases/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 = test_case.ListTestCaseResultsResponse( + 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 = test_case.ListTestCaseResultsResponse.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_test_case_results(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCaseResultsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_case_results_rest_required_fields( + request_type=test_case.ListTestCaseResultsRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_case_results._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_test_case_results._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.ListTestCaseResultsResponse() + # 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 = test_case.ListTestCaseResultsResponse.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_test_case_results(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_test_case_results_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_test_case_results._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_test_case_results_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_list_test_case_results" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_list_test_case_results" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.ListTestCaseResultsRequest.pb( + test_case.ListTestCaseResultsRequest() + ) + 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 = test_case.ListTestCaseResultsResponse.to_json( + test_case.ListTestCaseResultsResponse() + ) + + request = test_case.ListTestCaseResultsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.ListTestCaseResultsResponse() + + client.list_test_case_results( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_test_case_results_rest_bad_request( + transport: str = "rest", request_type=test_case.ListTestCaseResultsRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + 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_test_case_results(request) + + +def test_list_test_case_results_rest_flattened(): + client = TestCasesClient( + 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 = test_case.ListTestCaseResultsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + + # 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 = test_case.ListTestCaseResultsResponse.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_test_case_results(**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/v3beta1/{parent=projects/*/locations/*/agents/*/testCases/*}/results" + % client.transport._host, + args[1], + ) + + +def test_list_test_case_results_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case_results( + test_case.ListTestCaseResultsRequest(), + parent="parent_value", + ) + + +def test_list_test_case_results_rest_pager(transport: str = "rest"): + client = TestCasesClient( + 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 = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], + next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + ], + next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + test_case.ListTestCaseResultsResponse.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": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4" + } + + pager = client.list_test_case_results(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCaseResult) for i in results) + + pages = list(client.list_test_case_results(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", + [ + test_case.GetTestCaseResultRequest, + dict, + ], +) +def test_get_test_case_result_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4/results/sample5" + } + 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 = test_case.TestCaseResult( + name="name_value", + environment="environment_value", + test_result=test_case.TestResult.PASSED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = test_case.TestCaseResult.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_test_case_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.TestCaseResult) + assert response.name == "name_value" + assert response.environment == "environment_value" + assert response.test_result == test_case.TestResult.PASSED + + +def test_get_test_case_result_rest_required_fields( + request_type=test_case.GetTestCaseResultRequest, +): + transport_class = transports.TestCasesRestTransport + + 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_test_case_result._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_test_case_result._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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = test_case.TestCaseResult() + # 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 = test_case.TestCaseResult.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_test_case_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_test_case_result_rest_unset_required_fields(): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_test_case_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_test_case_result_rest_interceptors(null_interceptor): + transport = transports.TestCasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.TestCasesRestInterceptor(), + ) + client = TestCasesClient(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.TestCasesRestInterceptor, "post_get_test_case_result" + ) as post, mock.patch.object( + transports.TestCasesRestInterceptor, "pre_get_test_case_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = test_case.GetTestCaseResultRequest.pb( + test_case.GetTestCaseResultRequest() + ) + 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 = test_case.TestCaseResult.to_json( + test_case.TestCaseResult() + ) + + request = test_case.GetTestCaseResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = test_case.TestCaseResult() + + client.get_test_case_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_test_case_result_rest_bad_request( + transport: str = "rest", request_type=test_case.GetTestCaseResultRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4/results/sample5" + } + 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_test_case_result(request) + + +def test_get_test_case_result_rest_flattened(): + client = TestCasesClient( + 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 = test_case.TestCaseResult() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/testCases/sample4/results/sample5" + } + + # 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 = test_case.TestCaseResult.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_test_case_result(**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/v3beta1/{name=projects/*/locations/*/agents/*/testCases/*/results/*}" + % client.transport._host, + args[1], + ) + + +def test_get_test_case_result_rest_flattened_error(transport: str = "rest"): + client = TestCasesClient( + 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_test_case_result( + test_case.GetTestCaseResultRequest(), + name="name_value", + ) + + +def test_get_test_case_result_rest_error(): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = TestCasesClient( + 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 = TestCasesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = TestCasesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TestCasesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TestCasesGrpcTransport, + transports.TestCasesGrpcAsyncIOTransport, + transports.TestCasesRestTransport, + ], +) +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 = TestCasesClient.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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.TestCasesGrpcTransport, + ) + + +def test_test_cases_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.TestCasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_test_cases_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.test_cases.transports.TestCasesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TestCasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_test_cases", + "batch_delete_test_cases", + "get_test_case", + "create_test_case", + "update_test_case", + "run_test_case", "batch_run_test_cases", "calculate_coverage", "import_test_cases", @@ -3797,6 +7785,7 @@ def test_test_cases_transport_auth_adc(transport_class): [ transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport, + transports.TestCasesRestTransport, ], ) def test_test_cases_transport_auth_gdch_credentials(transport_class): @@ -3894,11 +7883,40 @@ def test_test_cases_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_test_cases_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.TestCasesRestTransport( + 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_test_cases_rest_lro_client(): + client = TestCasesClient( + 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_test_cases_host_no_port(transport_name): @@ -3909,7 +7927,11 @@ def test_test_cases_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3917,6 +7939,7 @@ def test_test_cases_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_test_cases_host_with_port(transport_name): @@ -3927,7 +7950,66 @@ def test_test_cases_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_test_cases_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = TestCasesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = TestCasesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_test_cases._session + session2 = client2.transport.list_test_cases._session + assert session1 != session2 + session1 = client1.transport.batch_delete_test_cases._session + session2 = client2.transport.batch_delete_test_cases._session + assert session1 != session2 + session1 = client1.transport.get_test_case._session + session2 = client2.transport.get_test_case._session + assert session1 != session2 + session1 = client1.transport.create_test_case._session + session2 = client2.transport.create_test_case._session + assert session1 != session2 + session1 = client1.transport.update_test_case._session + session2 = client2.transport.update_test_case._session + assert session1 != session2 + session1 = client1.transport.run_test_case._session + session2 = client2.transport.run_test_case._session + assert session1 != session2 + session1 = client1.transport.batch_run_test_cases._session + session2 = client2.transport.batch_run_test_cases._session + assert session1 != session2 + session1 = client1.transport.calculate_coverage._session + session2 = client2.transport.calculate_coverage._session + assert session1 != session2 + session1 = client1.transport.import_test_cases._session + session2 = client2.transport.import_test_cases._session + assert session1 != session2 + session1 = client1.transport.export_test_cases._session + session2 = client2.transport.export_test_cases._session + assert session1 != session2 + session1 = client1.transport.list_test_case_results._session + session2 = client2.transport.list_test_case_results._session + assert session1 != session2 + session1 = client1.transport.get_test_case_result._session + session2 = client2.transport.get_test_case_result._session + assert session1 != session2 def test_test_cases_grpc_transport_channel(): @@ -4524,6 +8606,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = TestCasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = TestCasesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -5241,6 +9609,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -5258,6 +9627,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py index 6e6b3dbf..0abc8f46 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.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 @@ -112,6 +119,7 @@ def test__get_default_mtls_endpoint(): [ (TransitionRouteGroupsClient, "grpc"), (TransitionRouteGroupsAsyncClient, "grpc_asyncio"), + (TransitionRouteGroupsClient, "rest"), ], ) def test_transition_route_groups_client_from_service_account_info( @@ -127,7 +135,11 @@ def test_transition_route_groups_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -135,6 +147,7 @@ def test_transition_route_groups_client_from_service_account_info( [ (transports.TransitionRouteGroupsGrpcTransport, "grpc"), (transports.TransitionRouteGroupsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.TransitionRouteGroupsRestTransport, "rest"), ], ) def test_transition_route_groups_client_service_account_always_use_jwt( @@ -160,6 +173,7 @@ def test_transition_route_groups_client_service_account_always_use_jwt( [ (TransitionRouteGroupsClient, "grpc"), (TransitionRouteGroupsAsyncClient, "grpc_asyncio"), + (TransitionRouteGroupsClient, "rest"), ], ) def test_transition_route_groups_client_from_service_account_file( @@ -182,13 +196,18 @@ def test_transition_route_groups_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_transition_route_groups_client_get_transport_class(): transport = TransitionRouteGroupsClient.get_transport_class() available_transports = [ transports.TransitionRouteGroupsGrpcTransport, + transports.TransitionRouteGroupsRestTransport, ] assert transport in available_transports @@ -209,6 +228,11 @@ def test_transition_route_groups_client_get_transport_class(): transports.TransitionRouteGroupsGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -364,6 +388,18 @@ def test_transition_route_groups_client_client_options( "grpc_asyncio", "false", ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + "true", + ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -567,6 +603,11 @@ def test_transition_route_groups_client_get_mtls_endpoint_and_cert_source(client transports.TransitionRouteGroupsGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + ), ], ) def test_transition_route_groups_client_client_options_scopes( @@ -607,6 +648,12 @@ def test_transition_route_groups_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + TransitionRouteGroupsClient, + transports.TransitionRouteGroupsRestTransport, + "rest", + None, + ), ], ) def test_transition_route_groups_client_client_options_credentials_file( @@ -2206,208 +2253,2050 @@ async def test_delete_transition_route_group_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + transition_route_group.ListTransitionRouteGroupsRequest, + dict, + ], +) +def test_list_transition_route_groups_rest(request_type): + client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - 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 = transition_route_group.ListTransitionRouteGroupsResponse( + next_page_token="next_page_token_value", ) - # 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 = TransitionRouteGroupsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = transition_route_group.ListTransitionRouteGroupsResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_transition_route_groups(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTransitionRouteGroupsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_transition_route_groups_rest_required_fields( + request_type=transition_route_group.ListTransitionRouteGroupsRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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, + ) ) - with pytest.raises(ValueError): - client = TransitionRouteGroupsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_transition_route_groups._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_transition_route_groups._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "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" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( + client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = TransitionRouteGroupsClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = transition_route_group.ListTransitionRouteGroupsResponse() + # 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 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.TransitionRouteGroupsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = ( + transition_route_group.ListTransitionRouteGroupsResponse.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_transition_route_groups(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_transition_route_groups_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.TransitionRouteGroupsGrpcAsyncIOTransport( + unset_fields = transport.list_transition_route_groups._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_transition_route_groups_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_list_transition_route_groups", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_list_transition_route_groups", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = transition_route_group.ListTransitionRouteGroupsRequest.pb( + transition_route_group.ListTransitionRouteGroupsRequest() + ) + 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 = ( + transition_route_group.ListTransitionRouteGroupsResponse.to_json( + transition_route_group.ListTransitionRouteGroupsResponse() + ) + ) + request = transition_route_group.ListTransitionRouteGroupsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = transition_route_group.ListTransitionRouteGroupsResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.TransitionRouteGroupsGrpcTransport, - transports.TransitionRouteGroupsGrpcAsyncIOTransport, - ], -) -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() + client.list_transition_route_groups( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = TransitionRouteGroupsClient.get_transport_class(transport_name)( + +def test_list_transition_route_groups_rest_bad_request( + transport: str = "rest", + request_type=transition_route_group.ListTransitionRouteGroupsRequest, +): + client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + 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_transition_route_groups(request) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + +def test_list_transition_route_groups_rest_flattened(): client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.TransitionRouteGroupsGrpcTransport, + 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 = transition_route_group.ListTransitionRouteGroupsResponse() -def test_transition_route_groups_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.TransitionRouteGroupsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) -def test_transition_route_groups_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.transition_route_groups.transports.TransitionRouteGroupsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.TransitionRouteGroupsTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = transition_route_group.ListTransitionRouteGroupsResponse.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 - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_transition_route_groups", - "get_transition_route_group", - "create_transition_route_group", - "update_transition_route_group", - "delete_transition_route_group", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + client.list_transition_route_groups(**mock_args) - with pytest.raises(NotImplementedError): - transport.close() + # 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/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups" + % client.transport._host, + args[1], + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_transition_route_groups_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_transition_route_groups_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.dialogflowcx_v3beta1.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.TransitionRouteGroupsTransport( - 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", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_transition_route_groups( + transition_route_group.ListTransitionRouteGroupsRequest(), + parent="parent_value", ) -def test_transition_route_groups_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.dialogflowcx_v3beta1.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.TransitionRouteGroupsTransport() - adc.assert_called_once() - +def test_list_transition_route_groups_rest_pager(transport: str = "rest"): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_transition_route_groups_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: + # 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 = ( + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[ + transition_route_group.TransitionRouteGroup(), + transition_route_group.TransitionRouteGroup(), + transition_route_group.TransitionRouteGroup(), + ], + next_page_token="abc", + ), + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[], + next_page_token="def", + ), + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[ + transition_route_group.TransitionRouteGroup(), + ], + next_page_token="ghi", + ), + transition_route_group.ListTransitionRouteGroupsResponse( + transition_route_groups=[ + transition_route_group.TransitionRouteGroup(), + transition_route_group.TransitionRouteGroup(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + transition_route_group.ListTransitionRouteGroupsResponse.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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + pager = client.list_transition_route_groups(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, transition_route_group.TransitionRouteGroup) for i in results + ) + + pages = list(client.list_transition_route_groups(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", + [ + transition_route_group.GetTransitionRouteGroupRequest, + dict, + ], +) +def test_get_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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 = transition_route_group.TransitionRouteGroup( + name="name_value", + display_name="display_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, transition_route_group.TransitionRouteGroup) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + + +def test_get_transition_route_group_rest_required_fields( + request_type=transition_route_group.GetTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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_transition_route_group._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_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = transition_route_group.TransitionRouteGroup() + # 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 = transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_transition_route_group._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_get_transition_route_group", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_get_transition_route_group", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = transition_route_group.GetTransitionRouteGroupRequest.pb( + transition_route_group.GetTransitionRouteGroupRequest() + ) + 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 = transition_route_group.TransitionRouteGroup.to_json( + transition_route_group.TransitionRouteGroup() + ) + + request = transition_route_group.GetTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = transition_route_group.TransitionRouteGroup() + + client.get_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=transition_route_group.GetTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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_transition_route_group(request) + + +def test_get_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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 = transition_route_group.TransitionRouteGroup() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + + # 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 = transition_route_group.TransitionRouteGroup.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_transition_route_group(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}" + % client.transport._host, + args[1], + ) + + +def test_get_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + transition_route_group.GetTransitionRouteGroupRequest(), + name="name_value", + ) + + +def test_get_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_transition_route_group.CreateTransitionRouteGroupRequest, + dict, + ], +) +def test_create_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["transition_route_group"] = { + "name": "name_value", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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 = gcdc_transition_route_group.TransitionRouteGroup( + name="name_value", + display_name="display_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_transition_route_group.TransitionRouteGroup) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + + +def test_create_transition_route_group_rest_required_fields( + request_type=gcdc_transition_route_group.CreateTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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() + ).create_transition_route_group._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() + ).create_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + 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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_transition_route_group.TransitionRouteGroup() + # 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_transition_route_group._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "transitionRouteGroup", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_create_transition_route_group", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_create_transition_route_group", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_transition_route_group.CreateTransitionRouteGroupRequest.pb( + gcdc_transition_route_group.CreateTransitionRouteGroupRequest() + ) + 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 = ( + gcdc_transition_route_group.TransitionRouteGroup.to_json( + gcdc_transition_route_group.TransitionRouteGroup() + ) + ) + + request = gcdc_transition_route_group.CreateTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_transition_route_group.TransitionRouteGroup() + + client.create_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=gcdc_transition_route_group.CreateTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["transition_route_group"] = { + "name": "name_value", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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_transition_route_group(request) + + +def test_create_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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 = gcdc_transition_route_group.TransitionRouteGroup() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(**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/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/transitionRouteGroups" + % client.transport._host, + args[1], + ) + + +def test_create_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + gcdc_transition_route_group.CreateTransitionRouteGroupRequest(), + parent="parent_value", + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + name="name_value" + ), + ) + + +def test_create_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, + dict, + ], +) +def test_update_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "transition_route_group": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + } + request_init["transition_route_group"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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 = gcdc_transition_route_group.TransitionRouteGroup( + name="name_value", + display_name="display_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_transition_route_group.TransitionRouteGroup) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + + +def test_update_transition_route_group_rest_required_fields( + request_type=gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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_transition_route_group._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_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_transition_route_group.TransitionRouteGroup() + # 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_transition_route_group._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("transitionRouteGroup",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "post_update_transition_route_group", + ) as post, mock.patch.object( + transports.TransitionRouteGroupsRestInterceptor, + "pre_update_transition_route_group", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_transition_route_group.UpdateTransitionRouteGroupRequest.pb( + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest() + ) + 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 = ( + gcdc_transition_route_group.TransitionRouteGroup.to_json( + gcdc_transition_route_group.TransitionRouteGroup() + ) + ) + + request = gcdc_transition_route_group.UpdateTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_transition_route_group.TransitionRouteGroup() + + client.update_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=gcdc_transition_route_group.UpdateTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "transition_route_group": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + } + request_init["transition_route_group"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5", + "display_name": "display_name_value", + "transition_routes": [ + { + "name": "name_value", + "intent": "intent_value", + "condition": "condition_value", + "trigger_fulfillment": { + "messages": [ + { + "text": { + "text": ["text_value1", "text_value2"], + "allow_playback_interruption": True, + }, + "payload": {"fields": {}}, + "conversation_success": {"metadata": {}}, + "output_audio_text": { + "text": "text_value", + "ssml": "ssml_value", + "allow_playback_interruption": True, + }, + "live_agent_handoff": {"metadata": {}}, + "end_interaction": {}, + "play_audio": { + "audio_uri": "audio_uri_value", + "allow_playback_interruption": True, + }, + "mixed_audio": { + "segments": [ + { + "audio": b"audio_blob", + "uri": "uri_value", + "allow_playback_interruption": True, + } + ] + }, + "telephony_transfer_call": { + "phone_number": "phone_number_value" + }, + "channel": "channel_value", + } + ], + "webhook": "webhook_value", + "return_partial_responses": True, + "tag": "tag_value", + "set_parameter_actions": [ + { + "parameter": "parameter_value", + "value": { + "null_value": 0, + "number_value": 0.1285, + "string_value": "string_value_value", + "bool_value": True, + "struct_value": {}, + "list_value": {"values": {}}, + }, + } + ], + "conditional_cases": [ + { + "cases": [ + { + "condition": "condition_value", + "case_content": [ + {"message": {}, "additional_cases": {}} + ], + } + ] + } + ], + }, + "target_page": "target_page_value", + "target_flow": "target_flow_value", + } + ], + } + 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_transition_route_group(request) + + +def test_update_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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 = gcdc_transition_route_group.TransitionRouteGroup() + + # get arguments that satisfy an http rule for this method + sample_request = { + "transition_route_group": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + 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 = gcdc_transition_route_group.TransitionRouteGroup.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_transition_route_group(**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/v3beta1/{transition_route_group.name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}" + % client.transport._host, + args[1], + ) + + +def test_update_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + gcdc_transition_route_group.UpdateTransitionRouteGroupRequest(), + transition_route_group=gcdc_transition_route_group.TransitionRouteGroup( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + transition_route_group.DeleteTransitionRouteGroupRequest, + dict, + ], +) +def test_delete_transition_route_group_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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_transition_route_group(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_transition_route_group_rest_required_fields( + request_type=transition_route_group.DeleteTransitionRouteGroupRequest, +): + transport_class = transports.TransitionRouteGroupsRestTransport + + 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_transition_route_group._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_transition_route_group._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = TransitionRouteGroupsClient( + 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_transition_route_group(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_transition_route_group_rest_unset_required_fields(): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_transition_route_group._get_unset_required_fields( + {} + ) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_transition_route_group_rest_interceptors(null_interceptor): + transport = transports.TransitionRouteGroupsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.TransitionRouteGroupsRestInterceptor(), + ) + client = TransitionRouteGroupsClient(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.TransitionRouteGroupsRestInterceptor, + "pre_delete_transition_route_group", + ) as pre: + pre.assert_not_called() + pb_message = transition_route_group.DeleteTransitionRouteGroupRequest.pb( + transition_route_group.DeleteTransitionRouteGroupRequest() + ) + 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 = transition_route_group.DeleteTransitionRouteGroupRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_transition_route_group( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_transition_route_group_rest_bad_request( + transport: str = "rest", + request_type=transition_route_group.DeleteTransitionRouteGroupRequest, +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + 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_transition_route_group(request) + + +def test_delete_transition_route_group_rest_flattened(): + client = TransitionRouteGroupsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/transitionRouteGroups/sample5" + } + + # 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_transition_route_group(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/transitionRouteGroups/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_transition_route_group_rest_flattened_error(transport: str = "rest"): + client = TransitionRouteGroupsClient( + 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_transition_route_group( + transition_route_group.DeleteTransitionRouteGroupRequest(), + name="name_value", + ) + + +def test_delete_transition_route_group_rest_error(): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + 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 = TransitionRouteGroupsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TransitionRouteGroupsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = TransitionRouteGroupsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TransitionRouteGroupsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TransitionRouteGroupsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TransitionRouteGroupsGrpcTransport, + transports.TransitionRouteGroupsGrpcAsyncIOTransport, + transports.TransitionRouteGroupsRestTransport, + ], +) +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 = TransitionRouteGroupsClient.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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.TransitionRouteGroupsGrpcTransport, + ) + + +def test_transition_route_groups_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.TransitionRouteGroupsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_transition_route_groups_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.transition_route_groups.transports.TransitionRouteGroupsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TransitionRouteGroupsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_transition_route_groups", + "get_transition_route_group", + "create_transition_route_group", + "update_transition_route_group", + "delete_transition_route_group", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_transition_route_groups_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.dialogflowcx_v3beta1.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TransitionRouteGroupsTransport( + 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", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_transition_route_groups_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.dialogflowcx_v3beta1.services.transition_route_groups.transports.TransitionRouteGroupsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TransitionRouteGroupsTransport() + adc.assert_called_once() + + +def test_transition_route_groups_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) TransitionRouteGroupsClient() adc.assert_called_once_with( @@ -2448,6 +4337,7 @@ def test_transition_route_groups_transport_auth_adc(transport_class): [ transports.TransitionRouteGroupsGrpcTransport, transports.TransitionRouteGroupsGrpcAsyncIOTransport, + transports.TransitionRouteGroupsRestTransport, ], ) def test_transition_route_groups_transport_auth_gdch_credentials(transport_class): @@ -2552,11 +4442,23 @@ def test_transition_route_groups_grpc_transport_client_cert_source_for_mtls( ) +def test_transition_route_groups_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.TransitionRouteGroupsRestTransport( + 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_transition_route_groups_host_no_port(transport_name): @@ -2567,7 +4469,11 @@ def test_transition_route_groups_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2575,6 +4481,7 @@ def test_transition_route_groups_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_transition_route_groups_host_with_port(transport_name): @@ -2585,7 +4492,45 @@ def test_transition_route_groups_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_transition_route_groups_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = TransitionRouteGroupsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = TransitionRouteGroupsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_transition_route_groups._session + session2 = client2.transport.list_transition_route_groups._session + assert session1 != session2 + session1 = client1.transport.get_transition_route_group._session + session2 = client2.transport.get_transition_route_group._session + assert session1 != session2 + session1 = client1.transport.create_transition_route_group._session + session2 = client2.transport.create_transition_route_group._session + assert session1 != session2 + session1 = client1.transport.update_transition_route_group._session + session2 = client2.transport.update_transition_route_group._session + assert session1 != session2 + session1 = client1.transport.delete_transition_route_group._session + session2 = client2.transport.delete_transition_route_group._session + assert session1 != session2 def test_transition_route_groups_grpc_transport_channel(): @@ -3009,6 +4954,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = TransitionRouteGroupsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = TransitionRouteGroupsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3730,6 +5961,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3747,6 +5979,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py index f381fdc7..cd23e8ee 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.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 @@ -102,6 +109,7 @@ def test__get_default_mtls_endpoint(): [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_info(client_class, transport_name): @@ -115,7 +123,11 @@ def test_versions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -123,6 +135,7 @@ def test_versions_client_from_service_account_info(client_class, transport_name) [ (transports.VersionsGrpcTransport, "grpc"), (transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_service_account_always_use_jwt( @@ -148,6 +161,7 @@ def test_versions_client_service_account_always_use_jwt( [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_file(client_class, transport_name): @@ -168,13 +182,18 @@ def test_versions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_versions_client_get_transport_class(): transport = VersionsClient.get_transport_class() available_transports = [ transports.VersionsGrpcTransport, + transports.VersionsRestTransport, ] assert transport in available_transports @@ -187,6 +206,7 @@ def test_versions_client_get_transport_class(): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -328,6 +348,8 @@ def test_versions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (VersionsClient, transports.VersionsRestTransport, "rest", "true"), + (VersionsClient, transports.VersionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -517,6 +539,7 @@ def test_versions_client_get_mtls_endpoint_and_cert_source(client_class): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_client_options_scopes( @@ -552,6 +575,7 @@ def test_versions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (VersionsClient, transports.VersionsRestTransport, "rest", None), ], ) def test_versions_client_client_options_credentials_file( @@ -2492,141 +2516,2173 @@ async def test_compare_versions_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.VersionsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + version.ListVersionsRequest, + dict, + ], +) +def test_list_versions_rest(request_type): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/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 = version.ListVersionsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.VersionsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.ListVersionsResponse.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_versions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListVersionsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_versions_rest_required_fields(request_type=version.ListVersionsRequest): + transport_class = transports.VersionsRestTransport + + 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_versions._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_versions._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", + ) + ) + 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 = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse() + # 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 = version.ListVersionsResponse.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_versions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_versions_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_versions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.VersionsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_versions_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = VersionsClient( - client_options=options, - transport=transport, + client = VersionsClient(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.VersionsRestInterceptor, "post_list_versions" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_list_versions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.ListVersionsRequest.pb(version.ListVersionsRequest()) + 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 = version.ListVersionsResponse.to_json( + version.ListVersionsResponse() ) - # 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 = VersionsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = version.ListVersionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.ListVersionsResponse() + + client.list_versions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.VersionsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_versions_rest_bad_request( + transport: str = "rest", request_type=version.ListVersionsRequest +): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # 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_versions(request) + + +def test_list_versions_rest_flattened(): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = VersionsClient(transport=transport) - assert client.transport is 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 = version.ListVersionsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # 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 = version.ListVersionsResponse.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_versions(**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/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/versions" + % client.transport._host, + args[1], + ) + + +def test_list_versions_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.VersionsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_versions( + version.ListVersionsRequest(), + parent="parent_value", + ) + + +def test_list_versions_rest_pager(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + version.Version(), + ], + next_page_token="abc", + ), + version.ListVersionsResponse( + versions=[], + next_page_token="def", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + ], + next_page_token="ghi", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(version.ListVersionsResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.VersionsGrpcTransport, - transports.VersionsGrpcAsyncIOTransport, - ], -) -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() + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + pager = client.list_versions(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, version.Version) for i in results) + + pages = list(client.list_versions(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + version.GetVersionRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = VersionsClient.get_transport_class(transport_name)( +def test_get_version_rest(request_type): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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 = version.Version( + name="name_value", + display_name="display_name_value", + description="description_value", + state=version.Version.State.RUNNING, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.Version.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_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, version.Version) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == version.Version.State.RUNNING + + +def test_get_version_rest_required_fields(request_type=version.GetVersionRequest): + transport_class = transports.VersionsRestTransport + + 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_version._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_version._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" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.VersionsGrpcTransport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.Version() + # 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 = version.Version.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_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_versions_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_get_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_get_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.GetVersionRequest.pb(version.GetVersionRequest()) + 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 = version.Version.to_json(version.Version()) + + request = version.GetVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.Version() -def test_versions_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.versions.transports.VersionsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.get_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly + pre.assert_called_once() + post.assert_called_once() + + +def test_get_version_rest_bad_request( + transport: str = "rest", request_type=version.GetVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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_version(request) + + +def test_get_version_rest_flattened(): + client = VersionsClient( + 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 = version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # 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 = version.Version.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_version(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_get_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + version.GetVersionRequest(), + name="name_value", + ) + + +def test_get_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_version.CreateVersionRequest, + dict, + ], +) +def test_create_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["version"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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.create_version(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_version_rest_required_fields( + request_type=gcdc_version.CreateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + 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() + ).create_version._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() + ).create_version._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 = VersionsClient( + 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.create_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "version", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_create_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_create_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_version.CreateVersionRequest.pb( + gcdc_version.CreateVersionRequest() + ) + 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 = gcdc_version.CreateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_version_rest_bad_request( + transport: str = "rest", request_type=gcdc_version.CreateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + request_init["version"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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_version(request) + + +def test_create_version_rest_flattened(): + client = VersionsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/agents/sample3/flows/sample4" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + version=gcdc_version.Version(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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_version(**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/v3beta1/{parent=projects/*/locations/*/agents/*/flows/*}/versions" + % client.transport._host, + args[1], + ) + + +def test_create_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + gcdc_version.CreateVersionRequest(), + parent="parent_value", + version=gcdc_version.Version(name="name_value"), + ) + + +def test_create_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_version.UpdateVersionRequest, + dict, + ], +) +def test_update_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "version": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + } + request_init["version"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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 = gcdc_version.Version( + name="name_value", + display_name="display_name_value", + description="description_value", + state=gcdc_version.Version.State.RUNNING, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_version.Version.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_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_version.Version) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.state == gcdc_version.Version.State.RUNNING + + +def test_update_version_rest_required_fields( + request_type=gcdc_version.UpdateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + 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_version._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_version._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 = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_version.Version() + # 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 = gcdc_version.Version.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_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "version", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_update_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_update_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_version.UpdateVersionRequest.pb( + gcdc_version.UpdateVersionRequest() + ) + 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 = gcdc_version.Version.to_json(gcdc_version.Version()) + + request = gcdc_version.UpdateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_version.Version() + + client.update_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_version_rest_bad_request( + transport: str = "rest", request_type=gcdc_version.UpdateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "version": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + } + request_init["version"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5", + "display_name": "display_name_value", + "description": "description_value", + "nlu_settings": { + "model_type": 1, + "classification_threshold": 0.25520000000000004, + "model_training_mode": 1, + }, + "create_time": {"seconds": 751, "nanos": 543}, + "state": 1, + } + 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_version(request) + + +def test_update_version_rest_flattened(): + client = VersionsClient( + 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 = gcdc_version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = { + "version": { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + } + + # get truthy value for each flattened field + mock_args = dict( + version=gcdc_version.Version(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 = gcdc_version.Version.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_version(**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/v3beta1/{version.name=projects/*/locations/*/agents/*/flows/*/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_update_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + gcdc_version.UpdateVersionRequest(), + version=gcdc_version.Version(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.DeleteVersionRequest, + dict, + ], +) +def test_delete_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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_version(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_version_rest_required_fields(request_type=version.DeleteVersionRequest): + transport_class = transports.VersionsRestTransport + + 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_version._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_version._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 = VersionsClient( + 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_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "pre_delete_version" + ) as pre: + pre.assert_not_called() + pb_message = version.DeleteVersionRequest.pb(version.DeleteVersionRequest()) + 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 = version.DeleteVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_version_rest_bad_request( + transport: str = "rest", request_type=version.DeleteVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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_version(request) + + +def test_delete_version_rest_flattened(): + client = VersionsClient( + 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": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # 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_version(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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_version( + version.DeleteVersionRequest(), + name="name_value", + ) + + +def test_delete_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.LoadVersionRequest, + dict, + ], +) +def test_load_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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.load_version(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_load_version_rest_required_fields(request_type=version.LoadVersionRequest): + transport_class = transports.VersionsRestTransport + + 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() + ).load_version._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() + ).load_version._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 = VersionsClient( + 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.load_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_load_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.load_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_load_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_load_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_load_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.LoadVersionRequest.pb(version.LoadVersionRequest()) + 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 = version.LoadVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.load_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_load_version_rest_bad_request( + transport: str = "rest", request_type=version.LoadVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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.load_version(request) + + +def test_load_version_rest_flattened(): + client = VersionsClient( + 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 = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # 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 = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.load_version(**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/v3beta1/{name=projects/*/locations/*/agents/*/flows/*/versions/*}:load" + % client.transport._host, + args[1], + ) + + +def test_load_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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.load_version( + version.LoadVersionRequest(), + name="name_value", + ) + + +def test_load_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.CompareVersionsRequest, + dict, + ], +) +def test_compare_versions_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "base_version": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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 = version.CompareVersionsResponse( + base_version_content_json="base_version_content_json_value", + target_version_content_json="target_version_content_json_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.CompareVersionsResponse.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.compare_versions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, version.CompareVersionsResponse) + assert response.base_version_content_json == "base_version_content_json_value" + assert response.target_version_content_json == "target_version_content_json_value" + + +def test_compare_versions_rest_required_fields( + request_type=version.CompareVersionsRequest, +): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["base_version"] = "" + request_init["target_version"] = "" + 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() + ).compare_versions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["baseVersion"] = "base_version_value" + jsonified_request["targetVersion"] = "target_version_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).compare_versions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "baseVersion" in jsonified_request + assert jsonified_request["baseVersion"] == "base_version_value" + assert "targetVersion" in jsonified_request + assert jsonified_request["targetVersion"] == "target_version_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.CompareVersionsResponse() + # 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 = version.CompareVersionsResponse.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.compare_versions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_compare_versions_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.compare_versions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "baseVersion", + "targetVersion", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_compare_versions_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(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.VersionsRestInterceptor, "post_compare_versions" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_compare_versions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.CompareVersionsRequest.pb(version.CompareVersionsRequest()) + 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 = version.CompareVersionsResponse.to_json( + version.CompareVersionsResponse() + ) + + request = version.CompareVersionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.CompareVersionsResponse() + + client.compare_versions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_compare_versions_rest_bad_request( + transport: str = "rest", request_type=version.CompareVersionsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "base_version": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + 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.compare_versions(request) + + +def test_compare_versions_rest_flattened(): + client = VersionsClient( + 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 = version.CompareVersionsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "base_version": "projects/sample1/locations/sample2/agents/sample3/flows/sample4/versions/sample5" + } + + # get truthy value for each flattened field + mock_args = dict( + base_version="base_version_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 = version.CompareVersionsResponse.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.compare_versions(**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/v3beta1/{base_version=projects/*/locations/*/agents/*/flows/*/versions/*}:compareVersions" + % client.transport._host, + args[1], + ) + + +def test_compare_versions_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + 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.compare_versions( + version.CompareVersionsRequest(), + base_version="base_version_value", + ) + + +def test_compare_versions_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = VersionsClient( + 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 = VersionsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = VersionsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.VersionsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.VersionsGrpcTransport, + transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, + ], +) +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 = VersionsClient.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 = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.VersionsGrpcTransport, + ) + + +def test_versions_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_versions_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.versions.transports.VersionsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly # raise NotImplementedError. methods = ( "list_versions", @@ -2741,6 +4797,7 @@ def test_versions_transport_auth_adc(transport_class): [ transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, ], ) def test_versions_transport_auth_gdch_credentials(transport_class): @@ -2838,11 +4895,40 @@ def test_versions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_versions_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.VersionsRestTransport( + 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_versions_rest_lro_client(): + client = VersionsClient( + 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_versions_host_no_port(transport_name): @@ -2853,7 +4939,11 @@ def test_versions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2861,6 +4951,7 @@ def test_versions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_versions_host_with_port(transport_name): @@ -2871,7 +4962,51 @@ def test_versions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_versions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = VersionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = VersionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_versions._session + session2 = client2.transport.list_versions._session + assert session1 != session2 + session1 = client1.transport.get_version._session + session2 = client2.transport.get_version._session + assert session1 != session2 + session1 = client1.transport.create_version._session + session2 = client2.transport.create_version._session + assert session1 != session2 + session1 = client1.transport.update_version._session + session2 = client2.transport.update_version._session + assert session1 != session2 + session1 = client1.transport.delete_version._session + session2 = client2.transport.delete_version._session + assert session1 != session2 + session1 = client1.transport.load_version._session + session2 = client2.transport.load_version._session + assert session1 != session2 + session1 = client1.transport.compare_versions._session + session2 = client2.transport.compare_versions._session + assert session1 != session2 def test_versions_grpc_transport_channel(): @@ -3198,6 +5333,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3915,6 +6336,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3932,6 +6354,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py index b9c99b64..70b1fbd2 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.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 @@ -95,6 +102,7 @@ def test__get_default_mtls_endpoint(): [ (WebhooksClient, "grpc"), (WebhooksAsyncClient, "grpc_asyncio"), + (WebhooksClient, "rest"), ], ) def test_webhooks_client_from_service_account_info(client_class, transport_name): @@ -108,7 +116,11 @@ def test_webhooks_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +128,7 @@ def test_webhooks_client_from_service_account_info(client_class, transport_name) [ (transports.WebhooksGrpcTransport, "grpc"), (transports.WebhooksGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.WebhooksRestTransport, "rest"), ], ) def test_webhooks_client_service_account_always_use_jwt( @@ -141,6 +154,7 @@ def test_webhooks_client_service_account_always_use_jwt( [ (WebhooksClient, "grpc"), (WebhooksAsyncClient, "grpc_asyncio"), + (WebhooksClient, "rest"), ], ) def test_webhooks_client_from_service_account_file(client_class, transport_name): @@ -161,13 +175,18 @@ def test_webhooks_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_webhooks_client_get_transport_class(): transport = WebhooksClient.get_transport_class() available_transports = [ transports.WebhooksGrpcTransport, + transports.WebhooksRestTransport, ] assert transport in available_transports @@ -180,6 +199,7 @@ def test_webhooks_client_get_transport_class(): [ (WebhooksClient, transports.WebhooksGrpcTransport, "grpc"), (WebhooksAsyncClient, transports.WebhooksGrpcAsyncIOTransport, "grpc_asyncio"), + (WebhooksClient, transports.WebhooksRestTransport, "rest"), ], ) @mock.patch.object( @@ -321,6 +341,8 @@ def test_webhooks_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (WebhooksClient, transports.WebhooksRestTransport, "rest", "true"), + (WebhooksClient, transports.WebhooksRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -510,6 +532,7 @@ def test_webhooks_client_get_mtls_endpoint_and_cert_source(client_class): [ (WebhooksClient, transports.WebhooksGrpcTransport, "grpc"), (WebhooksAsyncClient, transports.WebhooksGrpcAsyncIOTransport, "grpc_asyncio"), + (WebhooksClient, transports.WebhooksRestTransport, "rest"), ], ) def test_webhooks_client_client_options_scopes( @@ -545,6 +568,7 @@ def test_webhooks_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (WebhooksClient, transports.WebhooksRestTransport, "rest", None), ], ) def test_webhooks_client_client_options_credentials_file( @@ -2032,171 +2056,1648 @@ async def test_delete_webhook_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.WebhooksGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + webhook.ListWebhooksRequest, + dict, + ], +) +def test_list_webhooks_rest(request_type): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = WebhooksClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/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 = webhook.ListWebhooksResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.WebhooksGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = webhook.ListWebhooksResponse.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_webhooks(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListWebhooksPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_webhooks_rest_required_fields(request_type=webhook.ListWebhooksRequest): + transport_class = transports.WebhooksRestTransport + + 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_webhooks._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_webhooks._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", + ) + ) + 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 = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = WebhooksClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = webhook.ListWebhooksResponse() + # 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 = webhook.ListWebhooksResponse.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_webhooks(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_webhooks_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_webhooks._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.WebhooksGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_webhooks_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = WebhooksClient( - client_options=options, - transport=transport, + client = WebhooksClient(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.WebhooksRestInterceptor, "post_list_webhooks" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_list_webhooks" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = webhook.ListWebhooksRequest.pb(webhook.ListWebhooksRequest()) + 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 = webhook.ListWebhooksResponse.to_json( + webhook.ListWebhooksResponse() ) - # 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 = WebhooksClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = webhook.ListWebhooksRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = webhook.ListWebhooksResponse() + + client.list_webhooks( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.WebhooksGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_webhooks_rest_bad_request( + transport: str = "rest", request_type=webhook.ListWebhooksRequest +): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = WebhooksClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.WebhooksGrpcTransport( + # 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_webhooks(request) + + +def test_list_webhooks_rest_flattened(): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = WebhooksClient(transport=transport) - assert client.transport is 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 = webhook.ListWebhooksResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.WebhooksGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # 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 = webhook.ListWebhooksResponse.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_webhooks(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/webhooks" + % client.transport._host, + args[1], + ) + + +def test_list_webhooks_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.WebhooksGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_webhooks( + webhook.ListWebhooksRequest(), + parent="parent_value", + ) + + +def test_list_webhooks_rest_pager(transport: str = "rest"): + client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # 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 = ( + webhook.ListWebhooksResponse( + webhooks=[ + webhook.Webhook(), + webhook.Webhook(), + webhook.Webhook(), + ], + next_page_token="abc", + ), + webhook.ListWebhooksResponse( + webhooks=[], + next_page_token="def", + ), + webhook.ListWebhooksResponse( + webhooks=[ + webhook.Webhook(), + ], + next_page_token="ghi", + ), + webhook.ListWebhooksResponse( + webhooks=[ + webhook.Webhook(), + webhook.Webhook(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(webhook.ListWebhooksResponse.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 -@pytest.mark.parametrize( - "transport_class", - [ - transports.WebhooksGrpcTransport, - transports.WebhooksGrpcAsyncIOTransport, - ], -) -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() + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + pager = client.list_webhooks(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, webhook.Webhook) for i in results) + + pages = list(client.list_webhooks(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + webhook.GetWebhookRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = WebhooksClient.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_webhook_rest(request_type): client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.WebhooksGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + request = request_type(**request_init) -def test_webhooks_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.WebhooksTransport( - 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 = webhook.Webhook( + name="name_value", + display_name="display_name_value", + disabled=True, + generic_web_service=webhook.Webhook.GenericWebService(uri="uri_value"), ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = webhook.Webhook.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_webhooks_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflowcx_v3beta1.services.webhooks.transports.WebhooksTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.WebhooksTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_webhook(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_webhooks", - "get_webhook", - "create_webhook", - "update_webhook", - "delete_webhook", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, webhook.Webhook) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.disabled is True + + +def test_get_webhook_rest_required_fields(request_type=webhook.GetWebhookRequest): + transport_class = transports.WebhooksRestTransport + + 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, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_webhook._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_webhooks_base_transport_with_credentials_file(): + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_webhook._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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = webhook.Webhook() + # 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 = webhook.Webhook.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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_webhook._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "post_get_webhook" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_get_webhook" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = webhook.GetWebhookRequest.pb(webhook.GetWebhookRequest()) + 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 = webhook.Webhook.to_json(webhook.Webhook()) + + request = webhook.GetWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = webhook.Webhook() + + client.get_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_webhook_rest_bad_request( + transport: str = "rest", request_type=webhook.GetWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + 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_webhook(request) + + +def test_get_webhook_rest_flattened(): + client = WebhooksClient( + 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 = webhook.Webhook() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + + # 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 = webhook.Webhook.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_webhook(**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/v3beta1/{name=projects/*/locations/*/agents/*/webhooks/*}" + % client.transport._host, + args[1], + ) + + +def test_get_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + webhook.GetWebhookRequest(), + name="name_value", + ) + + +def test_get_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_webhook.CreateWebhookRequest, + dict, + ], +) +def test_create_webhook_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["webhook"] = { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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 = gcdc_webhook.Webhook( + name="name_value", + display_name="display_name_value", + disabled=True, + generic_web_service=gcdc_webhook.Webhook.GenericWebService(uri="uri_value"), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_webhook.Webhook.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_webhook(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_webhook.Webhook) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.disabled is True + + +def test_create_webhook_rest_required_fields( + request_type=gcdc_webhook.CreateWebhookRequest, +): + transport_class = transports.WebhooksRestTransport + + 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() + ).create_webhook._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() + ).create_webhook._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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_webhook.Webhook() + # 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 = gcdc_webhook.Webhook.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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_webhook._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "webhook", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "post_create_webhook" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_create_webhook" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_webhook.CreateWebhookRequest.pb( + gcdc_webhook.CreateWebhookRequest() + ) + 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 = gcdc_webhook.Webhook.to_json(gcdc_webhook.Webhook()) + + request = gcdc_webhook.CreateWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_webhook.Webhook() + + client.create_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_webhook_rest_bad_request( + transport: str = "rest", request_type=gcdc_webhook.CreateWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + request_init["webhook"] = { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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_webhook(request) + + +def test_create_webhook_rest_flattened(): + client = WebhooksClient( + 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 = gcdc_webhook.Webhook() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2/agents/sample3"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + webhook=gcdc_webhook.Webhook(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 = gcdc_webhook.Webhook.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_webhook(**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/v3beta1/{parent=projects/*/locations/*/agents/*}/webhooks" + % client.transport._host, + args[1], + ) + + +def test_create_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + gcdc_webhook.CreateWebhookRequest(), + parent="parent_value", + webhook=gcdc_webhook.Webhook(name="name_value"), + ) + + +def test_create_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcdc_webhook.UpdateWebhookRequest, + dict, + ], +) +def test_update_webhook_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "webhook": { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + } + request_init["webhook"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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 = gcdc_webhook.Webhook( + name="name_value", + display_name="display_name_value", + disabled=True, + generic_web_service=gcdc_webhook.Webhook.GenericWebService(uri="uri_value"), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcdc_webhook.Webhook.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_webhook(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_webhook.Webhook) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.disabled is True + + +def test_update_webhook_rest_required_fields( + request_type=gcdc_webhook.UpdateWebhookRequest, +): + transport_class = transports.WebhooksRestTransport + + 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_webhook._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_webhook._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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcdc_webhook.Webhook() + # 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 = gcdc_webhook.Webhook.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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_webhook._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("webhook",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "post_update_webhook" + ) as post, mock.patch.object( + transports.WebhooksRestInterceptor, "pre_update_webhook" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcdc_webhook.UpdateWebhookRequest.pb( + gcdc_webhook.UpdateWebhookRequest() + ) + 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 = gcdc_webhook.Webhook.to_json(gcdc_webhook.Webhook()) + + request = gcdc_webhook.UpdateWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcdc_webhook.Webhook() + + client.update_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_webhook_rest_bad_request( + transport: str = "rest", request_type=gcdc_webhook.UpdateWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "webhook": { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + } + request_init["webhook"] = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "allowed_ca_certs": [b"allowed_ca_certs_blob1", b"allowed_ca_certs_blob2"], + }, + "service_directory": {"service": "service_value", "generic_web_service": {}}, + "timeout": {"seconds": 751, "nanos": 543}, + "disabled": True, + } + 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_webhook(request) + + +def test_update_webhook_rest_flattened(): + client = WebhooksClient( + 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 = gcdc_webhook.Webhook() + + # get arguments that satisfy an http rule for this method + sample_request = { + "webhook": { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + } + + # get truthy value for each flattened field + mock_args = dict( + webhook=gcdc_webhook.Webhook(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 = gcdc_webhook.Webhook.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_webhook(**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/v3beta1/{webhook.name=projects/*/locations/*/agents/*/webhooks/*}" + % client.transport._host, + args[1], + ) + + +def test_update_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + gcdc_webhook.UpdateWebhookRequest(), + webhook=gcdc_webhook.Webhook(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + webhook.DeleteWebhookRequest, + dict, + ], +) +def test_delete_webhook_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/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 = 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_webhook(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_webhook_rest_required_fields(request_type=webhook.DeleteWebhookRequest): + transport_class = transports.WebhooksRestTransport + + 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_webhook._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_webhook._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + 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 = WebhooksClient( + 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_webhook(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_webhook_rest_unset_required_fields(): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_webhook._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_webhook_rest_interceptors(null_interceptor): + transport = transports.WebhooksRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.WebhooksRestInterceptor(), + ) + client = WebhooksClient(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.WebhooksRestInterceptor, "pre_delete_webhook" + ) as pre: + pre.assert_not_called() + pb_message = webhook.DeleteWebhookRequest.pb(webhook.DeleteWebhookRequest()) + 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 = webhook.DeleteWebhookRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_webhook( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_webhook_rest_bad_request( + transport: str = "rest", request_type=webhook.DeleteWebhookRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + 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_webhook(request) + + +def test_delete_webhook_rest_flattened(): + client = WebhooksClient( + 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": "projects/sample1/locations/sample2/agents/sample3/webhooks/sample4" + } + + # 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_webhook(**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/v3beta1/{name=projects/*/locations/*/agents/*/webhooks/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_webhook_rest_flattened_error(transport: str = "rest"): + client = WebhooksClient( + 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_webhook( + webhook.DeleteWebhookRequest(), + name="name_value", + ) + + +def test_delete_webhook_rest_error(): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebhooksClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = WebhooksClient( + 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 = WebhooksClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = WebhooksClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = WebhooksClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.WebhooksGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.WebhooksGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebhooksGrpcTransport, + transports.WebhooksGrpcAsyncIOTransport, + transports.WebhooksRestTransport, + ], +) +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 = WebhooksClient.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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.WebhooksGrpcTransport, + ) + + +def test_webhooks_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.WebhooksTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_webhooks_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.webhooks.transports.WebhooksTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.WebhooksTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_webhooks", + "get_webhook", + "create_webhook", + "update_webhook", + "delete_webhook", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + 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_webhooks_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 @@ -2274,6 +3775,7 @@ def test_webhooks_transport_auth_adc(transport_class): [ transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport, + transports.WebhooksRestTransport, ], ) def test_webhooks_transport_auth_gdch_credentials(transport_class): @@ -2371,11 +3873,23 @@ def test_webhooks_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_webhooks_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.WebhooksRestTransport( + 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_webhooks_host_no_port(transport_name): @@ -2386,7 +3900,11 @@ def test_webhooks_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2394,6 +3912,7 @@ def test_webhooks_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_webhooks_host_with_port(transport_name): @@ -2404,7 +3923,45 @@ def test_webhooks_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_webhooks_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = WebhooksClient( + credentials=creds1, + transport=transport_name, + ) + client2 = WebhooksClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_webhooks._session + session2 = client2.transport.list_webhooks._session + assert session1 != session2 + session1 = client1.transport.get_webhook._session + session2 = client2.transport.get_webhook._session + assert session1 != session2 + session1 = client1.transport.create_webhook._session + session2 = client2.transport.create_webhook._session + assert session1 != session2 + session1 = client1.transport.update_webhook._session + session2 = client2.transport.update_webhook._session + assert session1 != session2 + session1 = client1.transport.delete_webhook._session + session2 = client2.transport.delete_webhook._session + assert session1 != session2 def test_webhooks_grpc_transport_channel(): @@ -2723,6 +4280,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, 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_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/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 = locations_pb2.Location() + + # 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_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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 = locations_pb2.ListLocationsResponse() + + # 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.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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 = 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.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, 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 = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/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() + + # 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_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, 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.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = WebhooksClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + 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.ListOperationsResponse() + + # 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.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = WebhooksClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3440,6 +5283,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3457,6 +5301,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: